C# · 12月 26, 2021

c# – 如何解决TCP在一次读取中没有获得所有字节的问题

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

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

你怎么知道何时需要组合两个调用中收到的字节数组?

解决方法

how do you kNow when you need to combine the byte arrays received in both calls?

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

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

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

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

还要注意,这不仅会影响网络流 – 除了本地MemoryStream之外的任何东西(它总是读取你一次要求的数据,如果它一直在流中),你应该假设数据可能仅在多个电话的过程中可用.