2016-09-29 54 views
0

我目前ClientHandler方法接收TcpClient,开辟了一个NetStream说客户端,并开始从它像这样拉取数据:使用TcpClient/TcpListener,接收未知数量的单独消息的最佳方法是什么?

   try 
      { 
       //byte[] bytes = new byte[client.ReceiveBufferSize]; 
       byte[] bytes = new byte[100]; 
       int bytes_read = netstream.Read(bytes, 0, bytes.Length); 
       Console.WriteLine(DateTime.Now.ToString() + ": Bytes Read"); 

       while (bytes_read > 0) 
       { 
        memstream.Write(bytes, 0, bytes_read); 
        bytes_read = netstream.Read(bytes, 0, bytes.Length); 

        if (memstream.Length > 255) 
        { 
         MemStreamRead(memstream); 
         memstream.Flush(); 
         OkResponse(netstream); 
        } 
       } 
      } 

      catch (Exception e) 
      { 
       Console.WriteLine("No longer connected"); 
       connected = false; 
       Console.WriteLine(e); 
       Console.WriteLine(e.StackTrace); 
      } 

我已经可以得到的第一个消息出来的客户端,但我很难想出我将如何为新消息保持开放,并决定何时完成我目前的消息。

netstream.DataAvailable似乎它可以工作,我假设它检测到netstream不再获取更多数据,并返回false。但是,一旦有新数据可用,我该如何再次开始收听?

在此先感谢您的帮助!

+0

使用流读取器的异步任务连续读取tcpclient的基本流对象 –

回答

2

保留TcpClient对象及其netstream某处,您可以反复使用它。然后根据需要经常拨打netstream.Read()(非阻塞)。当有数据要读时,DataAvailable会告诉你。

注意:传入的TCP数据被添加到一个大缓冲区,并且在接收到数据时不能被分离回数据包。
调用Read()具有足够大的尺寸将从缓冲区获得“全部”数据。
您将需要您自己的更高级别的协议来分隔它。易于实现...

另一方面,在UDP上,Read()将返回1个数据包的数据。在Read()之后将返回下一个数据包的数据。数据包的“结构”被保留。

对于TCP更高级别的协议,你可以这样做:

  • 开始每条消息(每定义的消息,可能有1个字节的长度100.000字节),1个或多个0xFF的字节,所以你可以很容易地检测到消息的开始。
  • 从0x02开始(STX,意思是'文本开始'),以0x03结束(ETX,文本结束),所以你可以排除未被包围的'无意义'数据(例如活动消息) STX,ETX。
  • 如果您发送的二进制数据可能包含0x02,0x03,0xFF,那么您可以使用nnnnnn开始每个消息,nnnnnn是一个数字,并以字节为单位定义消息长度。无意义的数据不能在这里分开。

编辑
另行通知:
如果连接是由远程端关闭,Read()仍将成功执行,但不会返回数据。您必须以另一种方式找出连接是否即将关闭。查看我在其他SO网络问题上的答案以获取更多有用的信息。

+1

您可能还想提到,使用TCP时,调用'.Read'也可能只能获得数据包的*部分*。有时你需要做多个'.Read's才能得到完整的消息。 –

+0

@Bradley Uffner:真的,尽管非常罕见。数据包碎片不再经常发生,afaik,尽管MTU通常在1500bytes,但即使发送的数据超过MTU(如10kB),您也很难从NIC的输入缓冲区检索不完整的数据包。 TCP层应该在进一步传递之前重新组装它。 –

1

一旦有新数据可用,我该如何再次开始收听?

再次致电Read。这是大多数循环的工作原理,只需调用非阻塞的Read(或在专用线程上阻塞Read),并在获取数据时对其进行处理。

当我目前的消息是做

这就是你有另外一个问题。当操作系统套接字缓冲区中没有更多数据时,您的消息不一定会完成,而是在您的规则定义完成时完成。您通常会以消息长度打开消息,然后向操作系统请求数据,直到您填充了给定长度的缓冲区(或由于超时而失败)。

相关问题