Reputation: 554
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.
Upvotes: 4
Views: 1258
Reputation: 15772
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.
}
Upvotes: 4
Reputation: 171236
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.
Upvotes: 3