使用TcpClient / TcpListener,接收未知数量的单独消息的最佳方法是什么?

时间:2016-09-29 17:51:50

标签: c# tcplistener

我当前的ClientHandler方法收到TcpClient,在该客户端上打开NetStream,并开始从中提取数据:

                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。但是,一旦有新数据,我该如何开始再次收听?

提前感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

TcpClient对象及其netstream保留在可以反复使用的位置。然后根据需要经常调用netstream.Read()(非阻塞)。 DataAvailable会告诉您何时有数据需要阅读。

注意:传入的TCP数据被添加到一个大缓冲区中,并且在收到时无法分离回数据包。
以足够大的尺寸拨打Read()将获得所有'来自缓冲区的数据 您将需要自己的更高级别协议来分隔它。易于实施......

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

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

  • 使用1个或多个0xFF字节启动每条消息(每个您的定义的消息,长度可以是1个字节或100.000个字节),这样您就可以轻松检测到消息的开始。
  • 以0x02开头(STX,具有含义'文本开头'),以0x03(ETX,文本结尾)结束,因此您可以排除'废话'未被STX,ETX包围的数据(例如,活动消息)。
  • 如果您要发送可能包含0x02,0x03,0xFF的二进制数据,那么您可以使用nnnnnn开始每条消息,这是一个数字,并以字节为单位定义消息长度。无意义的数据不能在这里分开。

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

答案 1 :(得分:1)

  

一旦有新数据,我该如何重新开始听?

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

  

当我的当前消息完成时

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