Asynchronous calls are non-blocking - it is not the case that each socket will be using a particular thread . You can check this with a simple test (see below): on the server you print the thread on which each customer call is made, and it launches multiple clients sending data. In the example below, with 20 clients the server uses only 3 different threads. Depending on the number of clients sending data simultaneously management of socket callbacks can allocate more thread pro threads, but if you do not have 500 clients sending / receiving data to the same you will have much less than 500 threads.
Server :
class Program
{
static ManualResetEvent allDone = new ManualResetEvent(false);
static void Main(string[] args)
{
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPEndPoint localEP = new IPEndPoint(ipHostInfo.AddressList[0], 11000);
Console.WriteLine("Local address and port : {0}", localEP.ToString());
Socket listener = new Socket(localEP.Address.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(localEP);
listener.Listen(10);
while (true)
{
allDone.Reset();
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("Closing the listener...");
}
static void AcceptCallback(IAsyncResult ar)
{
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Signal the main thread to continue.
allDone.Set();
// Create the state object.
StateObject state = new StateObject();
state.WorkSocket = handler;
handler.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.WorkSocket;
// Read data from the client socket.
int read = handler.EndReceive(ar);
// Data was read from the client socket.
if (read > 0)
{
Console.WriteLine("[{0}] read {1} bytes", Thread.CurrentThread.ManagedThreadId, read);
state.sb.Append(Encoding.ASCII.GetString(state.Buffer, 0, read));
handler.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
else
{
if (state.sb.Length > 1)
{
// All the data has been read from the client;
// display it on the console.
string content = state.sb.ToString();
Console.WriteLine("[{0}] Read {1} bytes from socket.\n Data : {2}",
Thread.CurrentThread.ManagedThreadId, content.Length, content);
}
handler.Close();
}
}
public class StateObject
{
public Socket WorkSocket = null;
public const int BufferSize = 1024;
public byte[] Buffer = new byte[BufferSize];
public StringBuilder sb = new StringBuilder();
}
}
Client :
class Program
{
static void Main(string[] args)
{
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPEndPoint remoteEP = new IPEndPoint(ipHostInfo.AddressList[0], 11000);
Socket s = new Socket(remoteEP.Address.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
s.Connect(remoteEP);
Console.WriteLine("Connected, sending a few bytes...");
byte[] bytes = Encoding.ASCII.GetBytes("hello");
s.Send(bytes);
Console.Write("Now press ENTER to send remaining bytes...");
Console.ReadLine();
bytes = Encoding.ASCII.GetBytes(" world");
s.Send(bytes);
s.Close();
s.Dispose();
}
}
Command to run on the command line to start several (20 in this case) clients at a time:
for /l %i in (1,1,20) do start client.exe