你如何解释TCP何时没有获得一次读取的所有字节

时间:2012-09-26 06:03:49

标签: c# .net sockets tcp

我刚读了一篇文章说TCPClient.Read()可能无法在一次读取中获取所有发送的字节。你怎么解释这个?

例如,服务器可以将字符串写入tcp流。客户端读取字符串字节的一半,然后在另一个读取调用中读取另一半。

您如何知道何时需要组合两次调用中收到的字节数组?

3 个答案:

答案 0 :(得分:17)

  

您如何知道何时需要组合两次调用中收到的字节数组?

您需要在协议级别做出决定。有四种常见的模型:

  • 近距离结束:每一方每个连接只能发送一条“消息”。发送消息后,它们关闭套接字的发送端。接收方继续阅读,直到它到达流的末尾。
  • 长度前缀:在每条消息之前,包括消息中的字节数。这可以是固定长度格式(例如总是4字节)或一些压缩格式(例如,每字节7比特大小数据,为大小数据的最后字节设置最高比特)。然后是消息本身。接收代码将读取大小,然后读取那么多字节。
  • Chunking:像长度前缀一样,但是在较小的块中。每个块都是长度前缀的,最后一个块表示“消息结束”
  • 消息结束信号:继续阅读,直到看到消息的终结符。如果消息必须能够包含任意数据,这可能会很麻烦,因为您需要包含一个转义机制以表示消息中的终结器数据。

此外,不太常见的是,协议中每条消息始终特定大小 - 在这种情况下,您只需要继续操作,直到您读取了那么多数据。

在所有这些情况下,你基本上需要循环,将数据读入某种缓冲区,直到你有足够的数据,但是你确定了。您应该始终使用Read的返回值来记录您实际读取的字节数,并且始终检查它是否为0,在这种情况下您已达到流的结束。

另请注意,这不仅会影响网络流 - 除了本地MemoryStream之外的任何其他内容(如果它一直在流中,它将始终读取您要求的数据) ,您应该假设数据可能只在多次通话过程中可用。

答案 1 :(得分:-1)

您应该循环调用read()。该循环的条件将检查是否仍有任何数据可供读取。

答案 2 :(得分:-3)

这有点难以回答,因为你永远无法知道数据何时到达,这就是为什么我通常使用线程在我的聊天程序中接收数据。但你应该可以使用类似的东西:

do{
     numberOfBytesRead = myNetworkStream.Read(myReadBuffer,
                                              0, 
                                              myReadBuffer.Length);

     myCompleteMessage.AppendFormat("{0}",
      Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));

  }
  while(myNetworkStream.DataAvailable);

看看这个source