2012-02-17 116 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本功能)
  3. 客戶端(螺紋/分組#1) - >服務器(爲第一分組中的數據的剩餘部分到達時,緩衝液傳遞到命令ID FUNC)

我需要能夠從外部訪問此緩衝區(公共),以便在填滿時從另一個類開始使用該緩衝區。

我希望這是有道理的。我怎樣才能做到這一點?

+0

任何人都可以至少指出我在正確的方向。我找不到任何這樣的例子。 – user1002194 2012-02-17 10:53:23

回答

0
  1. 相信需要或者是在OnDataReceived或經由一個委託或參照其他類或接口取消到另一個類。如果您調用另一個類,則回調函數應該接收剛接收到的字節並處理它們。這裏重要的是線程之間的任何必要的同步,這就是爲什麼我認爲它需要在OnDataReceived中執行的原因。另外,我注意到您在每次調用OnDataReceived期間正在解碼字符。一旦你有一個完整的數據包,這可能是最好的辦法,除非你確定只發送單字節字符(ASCII),否則你可能會嘗試解碼已經被髮送的字符。

  2. 客戶端中的每個線程都需要有自己的連接,或者需要確保它在適當的鎖定內一次發送整個數據包。如果每個線程都有自己的連接,那麼您需要服務器上每個連接的緩衝區。如果客戶端只有一個連接,則服務器上不需要多個緩衝區。

  3. 這是一個阻塞隊列的好地方。這是CLR版本:http://msdn.microsoft.com/en-us/library/dd267312.aspx。您可能希望將它用於併發隊列,http://msdn.microsoft.com/en-us/library/dd267265.aspx。 tcp_server類將數據包放入隊列中,當它被完全接收時,然後另一個線程可能在從隊列中讀取時被阻塞,並處理放置在隊列中的所有數據包。