2012-02-17 115 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类将数据包放入队列中,当它被完全接收时,然后另一个线程可能在从队列中读取时被阻塞,并处理放置在队列中的所有数据包。