As Remus says above, you have to use async to keep performance high. That is the Begin.../End... methods in .NET.
Under the hood for sockets, these methods make use of IO Completion Ports which seems to be the most performant way of processing many sockets on Windows operating systems.
As Jim says, the TcpClient class can help here and is pretty easy to use. Here is an example of using the TcpListener to listen for incoming connections and the TcpClient to handle them, with the initial BeginAccept and BeginRead calls being async.
This example does assume a message based protocol is used over the sockets and that is ommitted except that the first 4 bytes of each transmission is the length, but that then allows you to use a synchronous Read on the stream to get the rest of the data that is already buffered.
Here is the code:
class ClientContext
{
public TcpClient Client;
public Stream Stream;
public byte[] Buffer = new byte[4];
public MemoryStream Message = new MemoryStream();
}
class Program
{
static void OnMessageReceived(ClientContext context)
{
// process the message here
}
static void OnClientRead(IAsyncResult ar)
{
ClientContext context = ar.AsyncState as ClientContext;
if (context == null)
return;
try
{
int read = context.Stream.EndRead(ar);
context.Message.Write(context.Buffer, 0, read);
int length = BitConverter.ToInt32(context.Buffer, 0);
byte[] buffer = new byte[1024];
while (length > 0)
{
read = context.Stream.Read(buffer, 0, Math.Min(buffer.Length, length));
context.Message.Write(buffer, 0, read);
length -= read;
}
OnMessageReceived(context);
}
catch (System.Exception)
{
context.Client.Close();
context.Stream.Dispose();
context.Message.Dispose();
context = null;
}
finally
{
if (context != null)
context.Stream.BeginRead(context.Buffer, 0, context.Buffer.Length, OnClientRead, context);
}
}
static void OnClientAccepted(IAsyncResult ar)
{
TcpListener listener = ar.AsyncState as TcpListener;
if (listener == null)
return;
try
{
ClientContext context = new ClientContext();
context.Client = listener.EndAcceptTcpClient(ar);
context.Stream = context.Client.GetStream();
context.Stream.BeginRead(context.Buffer, 0, context.Buffer.Length, OnClientRead, context);
}
finally
{
listener.BeginAcceptTcpClient(OnClientAccepted, listener);
}
}
static void Main(string[] args)
{
TcpListener listener = new TcpListener(new IPEndPoint(IPAddress.Any, 20000));
listener.Start();
listener.BeginAcceptTcpClient(OnClientAccepted, listener);
Console.Write("Press enter to exit...");
Console.ReadLine();
listener.Stop();
}
}
It demonstrates how to handle the async calls, but it will need error handling adding to make sure the TcpListener is always accepting new connections and more error handling for when clients disconnect unexpectedly. Also, there do seem to be a few cases where not all of the data arrives in one go that would need handling too.