C# NetworkStream.DataAvailable更新速度慢

C# NetworkStream.DataAvailable更新速度慢,c#,tcp,tcp-ip,networkstream,C#,Tcp,Tcp Ip,Networkstream,我正在编写一个基本的TCP/IP服务器来接收来自现有客户机的消息。目前,我能够接收单缓冲区和多缓冲区消息。当客户端发送一组多条消息时,就会出现问题。它不希望将每条消息作为单个通信发送,而是希望流打开,并且在流再次关闭之前,集中的所有消息都将一个接一个地发送。我在下面编辑的代码片段中对此进行了编码: private void AcceptMessage(IAsyncResult ar) { String receivedMessage = ""; // Only run if

我正在编写一个基本的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标记为答案,因为他在我的问题的大部分方面都提供了帮助。它仍然没有回答如何判断是否存在挂起的消息,这可能是不可能的,但我的经理决定,一旦连接打开,我们应该将其作为专用连接保持打开状态。这是因为我们的侦听器仅通过内部安全网络与具有一致流量的单个设备通信。我们正在添加一个超时,以便在一定时间内不活动时断开连接。

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

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

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

此外,最好在客户端即将结束其连接时实现由客户端发送的特定信号/消息,而不仅仅依赖超时。这将有助于您在不清楚原因是服务器或客户端中的错误,还是网络连接问题导致的问题时排除故障奥斯

此问题答案中的实施细节(尽管不同的应用场景方法相同):


此外,即使您的内部while循环在糟糕/缓慢的网络连接上也可能失败,并且可能会给您留下部分从客户端接收到的消息,这仅仅是因为stream.DataAvailable在下一个数据包(继续当前消息)之前的一段时间可能为false将收到…

感谢您的建议。不幸的是,我无法访问客户端代码,因此无法添加EndMessage标记。但是,我设置了读取超时,并将检查缓冲区是否已满,以了解是否已发送整个消息,或者是否还有更多消息。不幸的是,我仍然处于lef状态没有可靠的方法来确定第二条消息是否会在同一个流上传输。谢谢你的建议。不幸的是,如果客户发送的信息不包含此类信息,你无法可靠地判断客户是否会发送更多的日期。我忘了在我的回答中提到,你也不能t仅依靠Read()返回
0
(a-ka连接关闭),因为无论服务器套接字和客户端套接字之间存在什么蹩脚的代理或古怪的东西,都可能会使服务器端连接保持长时间打开,尽管客户端已经死了很久……可用的代理或连接几乎没有正确的用法,而这不是其中之一。您应该阻塞并读取,直到得到所需的,或者使用异步或无n阻塞I/O同上。