Remus が上で述べているように、パフォーマンスを高く保つには async を使用する必要があります。それが .NET の Begin.../End... メソッドです。
ソケットの内部では、これらのメソッドは IO Completion Ports を利用します。これは、Windows オペレーティング システムで多くのソケットを処理する最もパフォーマンスの高い方法と思われます。
Jim が言うように、ここでは TcpClient クラスが役立ち、非常に使いやすいです。これは、TcpListener を使用して着信接続をリッスンし、TcpClient を使用してそれらを処理する例です。最初の BeginAccept 呼び出しと BeginRead 呼び出しは非同期です。
この例では、ソケット上でメッセージ ベースのプロトコルが使用されていることを前提としており、各転送の最初の 4 バイトが長さであることを除いて省略されていますが、ストリームで同期読み取りを使用して残りのデータを取得できます。それはすでにバッファリングされています。
コードは次のとおりです。
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();
}
}
非同期呼び出しを処理する方法を示しますが、TcpListener が常に新しい接続を受け入れるようにするためにエラー処理を追加する必要があり、クライアントが予期せず切断した場合のエラー処理を追加する必要があります。また、すべてのデータが一度に到着するとは限らず、処理が必要な場合もいくつかあるようです。