web-dev-qa-db-ja.com

非同期サーバーソケット複数のクライアント

私はmsdnで公開されている次のコードを使用しています。

http://msdn.Microsoft.com/en-us/library/fx6588te.aspx

アプリケーションが新しいクライアントを待機している間、サーバーアプリケーションがブロックされないことを理解しています。

しかし、このアプリケーション(またはソケット)は、複数の同時リクエストを処理できますか?

  • クライアントAとBが同時に接続するとどうなりますか?

  • クライアントAが接続し、その要求の処理に5秒かかる場合、クライアントBが1秒後に接続した場合、クライアントAが終了するのを待ってから処理を開始する必要がありますか?

  • または、クライアントAとクライアントBの要求は同時に処理されますか?

ソケットリスナーコードの受信/送信データの間にThread.Sleep(n)コマンドを配置することにより、これを使用していくつかのテストを行いました。その後、ソケットに複数のリクエストを送信できますが、それらは処理されているように見えます。ただし、ソケットは常にsameスレッドIDでそれらを処理します。これにより、実際には同時に発生していないと思われます。

特に、このアプリは新しい接続を待っている間はブロックしないというMicrosoftの説明を考えると、それは同時接続を処理できることを意味しますか?

13
Remotec

[2014年更新] :このスレッド に記載されているように、この回答が投稿されてから例が変更されたようです。 MSDNの例では、複数の着信接続を適切に処理するようになりました。とにかく、ここで説明されている一般的なアプローチは正しく、おそらくそれは追加の説明を提供することができます。


ソケット通信を行う場合、基本的に、すべての着信接続に対して単一のリスナーソケットがあり、接続されたクライアントごとに複数のハンドラーソケットがあります。

着信接続をリッスンする

ポートのリッスンを開始すると、着信接続用のコールバックメソッドを使用してソケットを作成します(これは あなたが言及したものを参照しています)。これは、そのポート番号の唯一のリスナーソケットです。

listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);

この行は、新しいクライアントが接続されるたびにAcceptCallbackメソッドを呼び出すようにリスナーに指示します(新しい接続コールバック)。この方法は、他の着信接続をブロックするため、迅速に作業を行う必要があります。

専用ハンドラソケットの作成

そのため、AcceptCallbackは、独自のバックグラウンドデータコールバックメソッドを使用して専用「ハンドラー」ソケットをすぐに作成する必要があります。 (ReadCallback):

// inside AcceptCallback, we switch to the handler socket for communication
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
    new AsyncCallback(ReadCallback), state); // fired on a background thread

その瞬間から、新しく接続されたクライアントがデータを受信するたびにReadCallbackメソッドが呼び出されます。

また、戻る前に、AcceptCallbacklistener.BeginAcceptを再度呼び出して、新しい着信接続をリッスンし続ける必要があります。

// this is the same server socket we opened previously, which will now 
// continue waiting for other client connections: it doesn't care about
// the actual data transmission between individual clients
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);

この部分はMSDNの例から省略されています。つまり、単一の接続しか受信できません。

データ受信中

クライアントからデータのパケットを取得するとすぐに、ReadCallbackメソッドが呼び出されます。したがって、このデータコールバックメソッド内で、受信したデータを読み取って処理してから、同じBeginReceiveメソッドagainを呼び出す必要があります(ここでもReadCallbackをデータコールバックメソッドとして)。

[編集]

MSDNの例の問題は、単一のクライアントのみの接続を許可することです(listener.BeginAcceptは1回だけ呼び出されます)。複数の同時接続を許可するには、handler.BeginReceiveを使用して受信ソケットを作成してから、listener.BeginAcceptを呼び出して新しいクライアントのリッスンを開始する必要があります。

31
Groo

すべてのソケットには、リッスンキューが関連付けられています。これには、保留中/部分的に受け入れられた着信接続があります。保留中の接続の最大数は、listen()APIでプログラムで定義できます。これは、この例では「listener.Listen(100)」にすぎません。ここでこれを100とすると、ソケット 'listener'は、リスンキューに150(= 2 * 100/2)の保留中の接続を持つことができます。

0
Mani