多线程套接字服务器 - 接收数据

时间:2012-02-17 01:54:37

标签: c# asynchronous

我有一个简单的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个问题:

1 我需要'收集'所有100个字节,然后将其传递给另一个将检查接收数据中的命令的函数。客户端在数据包末尾添加4字节“数据包结束标识符”,因为数据大小并不总是事先知道。如何/在哪里可以定义这个临时缓冲区,因此onDataRecieve会填满它,如果找到end,则将数据传递给命令识别函数?

2 客户端可能会从不同的线程(在同一连接上)向我发送大量数据。我需要一种为每个收到的数据包提供多个临时缓冲区的方法,所以我可以等到它们填满并通过缓冲区,无论哪个先填充到命令识别功能,然后清除/删除缓冲区。

例如:

  1. 客户端(线程/数据包#1) - >服务器(数据不完整,线程由于某种原因挂起)
  2. 客户端(线程/数据包#2) - >服务器(完整数据,缓冲区传递给命令ID功能)
  3. 客户端(线程/数据包#1) - >服务器(第一个数据包的其余数据到达,缓冲区传递给命令id func)
  4. 3 我需要能够从外部(公共)访问此缓冲区,因此我可以在填充时从另一个类开始使用该缓冲区。

    我希望这是有道理的。我怎么能做到这一点?

1 个答案:

答案 0 :(得分: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类会在数据包完全接收时将数据包放入队列中,然后另一个线程在从队列中读取时可能会阻塞并处理放入队列的任何数据包。