2013-12-11 59 views
1

我在写一个基本的TCP/IP服务器来接收来自现有客户端的消息。目前,我能够接收单缓冲和多缓冲消息。客户端发送一组多条消息时会出现问题。与其将每个消息作为单个通信发送,它希望打开流,并且在流再次关闭之前,将集合中的所有消息一个接一个地发送。我在下面的编辑片段编码此:NetworkStream.DataAvailable更新缓慢

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发送一组消息的时候显示的是假的,但如果我把一个破下一行它会表现真实。换句话说,在数据可用之前它正在检查数据是否可用。我可以通过在检查是否有更多消息之前增加一秒延迟来解决此问题,但在100个案例中有99个,这将是不必要的延迟。由于客户端一次只能发送一条消息(或一组消息),因此在繁忙时间内可能会增加大量时间来接收消息。

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

编辑

我更改了代码以包含建议。我添加了暂停,并将第一张支票从stream.DataAvailable更改为bytesRead == BufferSize。我无法访问客户端软件,因此我无法添加EOM传输。我也无法保证多个消息是以单个流还是多个单独的流发送。我还没有想出如何判断是否有更多的消息未决。我不能让流打开,因为这阻止了下一次传输。

我标记为Elgonzo作为答案,因为他帮助我的问题的大部分方面。它仍然没有回答如何判断是否有消息挂起,这可能是不可能的,但我的经理认为,一旦连接打开,我们应该将其作为专用连接打开。这是有效的,因为我们的听众只能通过具有一致流量的内部安全网络与单个设备进行通信。如果在一段时间内没有活动,我们将增加暂停时间。

+0

有几个,如果任何正确的使用可用,这不是其中之一。您应该阻止并阅读,直到您有所需,或使用异步或非阻塞I/O同上。 – EJP

回答

2

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

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

此外,当客户端即将结束其连接时,最好实现由客户端发送的特定信号/消息,而不仅仅依赖于超时。这可以帮助您排除问题,如果问题不清楚问题是由服务器还是客户端造成的,或者问题是由网络连接问题引起的。在回答这个问题

实现细节(尽管不同应用场景的方法是一样的):Reading from closed NetworkStream doesn't cause any exception

另外,即使你内心while循环可能会失败的糟糕/慢速网络连接,并可能会离开你与从客户端部分接收到的消息,只是因为stream.DataAvailable可能会在下一个数据包(继续当前消息)之前暂时为假...

+0

谢谢你的建议。不幸的是,我没有访问客户端代码的权限,所以我不能添加EndMessage标记。然而,我确实设置了读取超时,并检查是否填充了缓冲区,以便确定整个消息是否已发送,或者还有更多消息来临。不幸的是,我仍然没有可靠的方法来确定第二条消息是否会在同一个流上传输。谢谢你的建议。 – Tim

+0

不幸的是,如果客户发送的信息不包含这些信息,那么您无法可靠地判断客户是否会发送更多日期。我忘了在我的回答中提到,你也不能完全依靠* Read()*返回'0'(a-ka连接关闭),因为无论服务器套接字和客户端套接字之间的代理或时髦事情是否可能尽管客户端已经很长时间了,但仍然保持服务器端连接长时间处于打开状态。 – elgonzo

0

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