4

I'm working on a simple socket server that is supposed to take in multiple connections and hand them off to a "connection" class by means of EndAccept() The problem is that after accepting a connection, the code doesn't accept anything further until the connection ends.

I create the socket in Main() like so, then I pass the socket to ServerEnvironment (static class) via Initialize().

MainSocket.Bind(new IPEndPoint(IPAddress.Parse(Addr), Port));
MainSocket.Listen(10);

ServerEnvironment.Initialize(MainSocket);

while (true)
{
    Console.ReadLine();
    Console.WriteLine(">>");
}

Once MainSocket has been passed, ServerEnvironment takes over from there.

static Socket MainSocket;

public static void Initialize(Socket _MainSocket)
{
    MainSocket = _MainSocket;

    AcceptGameConnection = new AsyncCallback(AddConnection);
    MainSocket.BeginAccept(AcceptGameConnection, null);
}

public static void AddConnection(IAsyncResult Result)
{
    Socket UserSocket = MainSocket.EndAccept(Result);
    ConnectionCount++;

    // Removed the stuff that happens to UserSocket because the same
    // symptoms occur regardless of their presence.

    MainSocket.BeginAccept(AcceptGameConnection, null);
 }

As I search about this question, I come to find that multithreading could be a necessity for my purposes. However, when I use Console.WriteLine(Thread.CurrentThread.ManagedThreadId); in both Initialize(); and AddConnection();, two different thread IDs appear, so I assume that multithreading is already a capability and I don't need to manually create a thread. That wouldn't explain my issue, though.

Is multithreading necessary for me to be able to have concurrent and asynchronous socket connectivity?

EDIT: Binding error..was binding to my LAN address which caused some problems.

2
  • 2
    maybe you should take a look at asp.net/signalr, wich is a really easy to use library Commented Aug 22, 2015 at 20:23
  • Are you using .net >= 4.5? Commented Aug 22, 2015 at 21:03

2 Answers 2

4

This is how you want to do this if you are using .net 4.0 or less

public static void Initialize(Socket _MainSocket)
{
    MainSocket = _MainSocket;

    AcceptGameConnection = new AsyncCallback(AddConnection);
    MainSocket.BeginAccept(result => {
        var userSocket = MainSocket.EndAccept(result);
        var thread = new Thread(AddConnection);
        thread.Start(userSocket);
        Initialize(MainSocket);
    }, null);
 }

 public static void AddConnection(IAsyncResult Result)
 {
     MainSocket.BeginAccept(AcceptGameConnection, null);
 }

 private static void AddConnection(Socket userSocket)
 {
     // Removed the stuff that happens to UserSocket because the same
     // symptoms occur regardless of their presence.
 }

But this is how you can do it in .net 4.5 or above.

public static void Initialize(Socket mainSocket)
{           
    while(true)
    {
        var userSocket = await Task.Factory.FromAsync(
                                mainSocket.BeginAccept,
                                mainSocket.EndAccept);
        ThreadPool.QueueUserWorkItem(_ => AddConnection(userSocket));
    }
 }

 private static void AddConnection(Socket userSocket)
 {
     // Removed the stuff that happens to UserSocket because the same
     // symptoms occur regardless of their presence.
 }
Sign up to request clarification or add additional context in comments.

3 Comments

So I'll definitely try the above and even the latter, but would you mind explaining to me why my method works for other applications? I looked at some other game socket servers and they used my exact pattern.
@Fuselight The problem is that you can't open new connections until you call BeginAccept again. Because that is what BeginAccept does, ACCEPT new connections. What I am doing is starting up a thread to do work and calling BeginAccept straight away. Your other applications might work because the "work" you are doing is reasonably fast to complete.
In effect for a server to open many connections you really need to call Accept as soon as a user connects.
3

The problem is that after accepting a connection, the code doesn't accept anything further until the connection ends.

This happens because the next BeginAccept call is delayed by something, probably by code not shown here. Accepting asynchronously is almost always pointless. Don't copy blindly from the terrible Microsoft tutorials. Your accept loop should be:

while (true) {
 var socket = Accept();
 StartProcessing(socket); //Cannot block!
}

That's all.

You can implement StartProcessing using Task and await. This makes asynchronous socket IO rather simple to do. Alternatively, start a new task/thread per connection that you receive.

simple socket server

Such a thing does not exist. You better leave sockets alone and use a ready made higher level protocol such as WCF or HTTP.

8 Comments

"This happens because the next BeginAccept call is delayed by something, probably by code not shown here." Actually, no! I removed that code in the program itself and it still hung! It's super weird. "Start a new task/thread per connection that you receive." I don't know much about sockets but I do know this is a bad idea at a certain number of connections. There's a reason I avoided that. And I cant use a different protocol, as this is software with a pre-designed protocol.
Regarding Accept not continuing, are you sure that a new connection is even coming in? Anyway, you should switch to the simpler accept loop in any case. There is no reason to use async accept here. All people who don't know what they are doing and copy from others.; Regarding thread, sure just use async IO with await then. Google ".net socket await".; No matter what you do, drop the APM pattern.
I'm absolutely sure that the connection isn't being acknowledged. Also, would accept not block the already-existing connections?
No, those should be run using async IO. They are using independent sockets. Accepted sockets are not tied to their "parent" socket.
If you fail to accept two connections using that failsafe piece of test code then there are not two connections incoming. Bug in the client.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.