2012-02-17 17 views
0

私は、非同期ソケットを使用する単純なTCPサーバーを持っています。私が直面してるの挑戦はこれです:マルチスレッドソケットサーバー - データを受信

私は、次のTCPサーバのクラスを持っている:

public class tcp_server { 
     const int max_clients = 300; 
     const int max_buffer_size = 10; 

     public AsyncCallback pfnWorkerCallBack; 
     private Socket m_mainSocket; 
     private Socket[] m_workerSocket = new Socket[max_clients]; 
     private int m_clientCount = 0; 

      ... 

     public void OnClientConnect(IAsyncResult asyn) { } 
     public void WaitForData(System.Net.Sockets.Socket soc, int socket_id) { } 
     public void OnDataReceived(IAsyncResult asyn) 

     public class SocketPacket 
     { 
      public System.Net.Sockets.Socket m_currentSocket; 
      public byte[] dataBuffer = new byte[max_buffer_size]; 
      public int socket_id = -1; 
     } 
} 

ここOnDataRecieved関数の完全なコードは次のとおりです。

public void OnDataReceived(IAsyncResult asyn) 
    { 
     try 
     { 
      SocketPacket socketData = (SocketPacket)asyn.AsyncState; // cast 

      int iRx = 0; 
      iRx = socketData.m_currentSocket.EndReceive(asyn); 

      char[] chars = new char[iRx + 1]; 
      System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder(); 
      int charLen = d.GetChars(socketData.dataBuffer, 0, iRx, chars, 0); 

      WaitForData(socketData.m_currentSocket, socketData.socket_id); 
     } 
     catch (ObjectDisposedException) 
     { 
      log("OnDataReceived: Socket has been closed\n"); 
     } 
     catch (SocketException se) 
     { 
      log(se.Message); 
     } 
    } 

max_buffer_sizeは10に設定されていますサーバーに100バイトを送信すると、onDataRecieveは10回実行されます。

私は3つの問題を抱えて:

私はすべて100バイト「を集める」と、受信したデータ内のコマンドをチェックします別の関数に渡す必要があります。データサイズが常に事前にわかっているわけではないので、クライアントはパケットの最後に4バイトの 'パケットエンド識別子'を追加する。どのように/どこでこの一時バッファを定義することができますか?そのため、onDataRecieveはそれを埋めるでしょう。もし見つかったら、データをコマンド識別関数に渡しますか?

クライアントは、(同じ接続上の)別のスレッドから多くのデータを送信することがあります。受信したパケットごとに複数の一時バッファを用意する方法が必要です。バッファをいっぱいになるまで待ってから、コマンド識別機能を満たしてからバッファをクリア/削除します。例えば

  1. クライアント(スレッド/パケット#1) - >サーバ(不完全なデータ、スレッドが何らかの理由でハング)
  2. クライアント(スレッド/パケット#2) - >サーバ(完全データ、バッファをID FUNCTをコマンドに渡されます)
  3. クライアント(スレッド/パケット#1) - >サーバー(第一パケットのデータの残りの部分は、ID funcをコマンドに渡されるバッファに到着)

外部(public)からこのバッファにアクセスできるようにする必要があります。そのバッファがいっぱいになってから別のクラスのバッファを使い始めることができます。

私はそれが理にかなっていると思います。どうすればこれを達成できますか?

+0

誰でも少なくとも正しい方向で私を指し示すことができます。私はこれを行う例を見つけることができません。 – user1002194

答えて

0
  1. 私は、OnDataReceivedに入れるか、代理人または別のクラスやインターフェイスへの参照を介して別のクラスにコールする必要があると思います。別のクラスを呼び出す場合、コールバック関数はちょうど受信したバイトを受け取り、それらを処理する必要があります。ここで重要なのは、スレッド間の同期が必要なため、OnDataReceived内から実行する必要があると考えられる理由です。また、OnDataReceivedを呼び出すたびに文字をデコードしています。 1バイト文字(ASCII)のみを送信することを確実にしている場合を除き、パケットを一度取得した方がよいでしょう。そうでなければ、複数の送信に分割された文字をデコードしようとする可能性があります。

  2. クライアントの各スレッドは、独自の接続を必要とするか、適切なロック内でパケット全体を一度に送信する必要があります。各スレッドに独自の接続がある場合、サーバー上の接続ごとにバッファが必要です。クライアントに接続が1つしかない場合は、サーバー上に複数のバッファーが必要なくなります。

  3. これはブロッキングキューに適しています。これはCLRバージョン:http://msdn.microsoft.com/en-us/library/dd267312.aspxです。 Concurrent Queue、http://msdn.microsoft.com/en-us/library/dd267265.aspxでそれを使用したいと思うでしょう。 tcp_serverクラスは、パケットが完全に受信されたときにそのパケットをキューに入れ、次にキューから読み取ったときに別のスレッドがブロックされ、キューに配置されたパケットを処理します。

関連する問題