NetworkStream.DataAvailable更新缓慢

时间:2013-12-11 18:29:46

标签: c# tcp tcp-ip networkstream

我正在编写一个基本的TCP / IP服务器来接收来自现有客户端的消息。目前,我能够接收单缓冲区和多缓冲区消息。当客户端发送一组多个消息时,问题就出现了。它不是将每个消息作为单个通信发送,而是希望在流再次关闭之前打开流并且集合中的所有消息一个接一个地发送。我在下面编辑的代码段中为此编码:

private void AcceptMessage(IAsyncResult ar)
{
    String receivedMessage = "";

    //  Only run if the server is listening. Otherwise, an exception will be thrown.
    if (isListening)
    {
       ASCIIEncoding encoder = new ASCIIEncoding();
       try
       {
           TcpListener listener = (TcpListener)ar.AsyncState;
           using (TcpClient client = listener.EndAcceptTcpClient(ar))
           using (NetworkStream stream = client.GetStream())
           {
               int bytesRead;
               int totalBytes = 0;
               stream.ReadTimeout = ReadTimeout;
               do
               {
                   byte[] receivedBytes = new byte[BufferSize];
                   StringBuilder message = new StringBuilder();
                   bytesRead = 0;
                   do
                   {
                       try
                       {
                           if (stream.CanRead)
                           bytesRead = stream.Read(receivedBytes, 0, BufferSize);
                       }
                       catch (...Exception Handling...)

                       if (bytesRead == 0)
                           break;

                       message.Append(encoder.GetString(receivedBytes, 0, bytesRead));
                       totalBytes += bytesRead;
                   } while (bytesRead == BufferSize);     //  Allow for multiple buffers in a single message
                   byte[] ack = encoder.GetBytes(GetAck(message.ToString(), ackNak, status, statusMessage));
                   stream.Write(ack, 0, ack.Length);
                   ...Message Processing...
               } while (stream.DataAvailable);         //  Allow for multiple messages                        
           }
       }
       catch (...Error Handling...)
       finally { ...Cleanup...}
   }
}

问题出现在第二个while (stream.DataAvailable);当检查发生时,DataAvailable在发送一组消息时显示为false,但如果我在下一行放置一个中断,它将显示为true。换句话说,它正在检查数据是否可用之前是否可用。我可以通过在检查是否有更多消息之前添加一秒延迟来解决此问题,但在100个案例中的99个中,这将是不必要的延迟。由于客户端一次只能发送一条消息(或一组消息),因此在繁忙时间可能会增加大量时间来接收消息。

是否有更好的方法来确定是否有更多待处理的消息(没有客户端修改)?谢谢!

修改

我更改了代码以包含建议。我添加了超时,并将第一次检查从stream.DataAvailable更改为bytesRead == BufferSize。我无法访问客户端软件,因此无法添加EOM传输。我也无法保证在单个流或多个单独的流中是否会发送多条消息。我还没弄明白如何判断是否有更多的消息未决。我不能打开流,因为它会阻止下一次传输。

我将Elgonzo标记为答案,因为他帮助解决了我问题的大多数方面。它仍然没有回答如何判断是否有待处理的消息,这可能是不可能的,但我的经理决定,一旦连接打开,我们应该将其作为专用连接保持打开状态。这是有效的,因为我们的侦听器仅通过具有一致流量的内部安全网络与单个设备进行通信。如果在一段时间内不活动,我们会增加断开连接。

2 个答案:

答案 0 :(得分:2)

数据是否可用以及服务器端数据的速度(和周期性)不仅取决于客户端的时间/行为,还取决于网络/互联网的速度和延迟因素中间的联系(这本身取决于许多和未知因素)。

因此,您不能在外部while循环中使用stream.DataAvailable来检查是否会有更多数据进入。您可能必须在NetworkStream上设置ReadTimeout以了解客户端何时完成/断开连接。

此外,当客户端即将结束其连接时,最好实现由客户端发送的特定信号/消息,而不仅仅依赖于超时。这将帮助您解决问题,即不清楚原因是服务器或客户端中的错误,还是问题是由网络连接问题引起的。

这个问题的答案中的实现细节(尽管不同的应用场景方法是相同的):Reading from closed NetworkStream doesn't cause any exception

此外,即使你的内部while循环也可能在糟糕/慢速的网络连接上失败,并且可能会留下来自客户端的部分接收消息,因为stream.DataAvailable在下一个数据包之前可能是假的(将继续接收当前消息...

答案 1 :(得分:0)

我建议启动自己的线程,该线程在后台运行,如果有可用的数据,只需从流中读取数据。如果收到数据,则只收集数据,直到收到完整的消息(应由定义的字节或字节序列表示),然后触发事件。在我看来,这应该有助于避免这个问题。