TCP不是这样工作的。就是这么简单。
TCP是一种基于流的协议。这意味着你不应该像UDP那样将其视为基于消息的协议。如果你需要通过TCP发送消息,你必须在TCP之上添加自己的消息协议。
你尝试做的是发送两个独立的消息,并在另一端接收两个独立的消息。这在UDP(基于消息)上可以正常工作,但在TCP上不行,因为TCP是没有组织的流。
所以,Flush完全可以正常工作。只是无论你在一侧调用多少次Flush,在另一侧调用多少次单独的Send,每个Receive都会获取尽可能多的数据来适应其缓冲区,而不考虑其他侧的Send。
你设计的解决方案(几乎是正确的 - 只需使用单个\0分隔字符串)实际上是处理此问题的一种正确方法。通过这样做,你又在流的顶部处理消息了。这称为消息帧 - 它允许你区分各个消息。在你的情况下,你在消息之间添加了分隔符。想象一下在文件中写入相同的数据 - 再次,你需要自己的某种方式来分隔各个消息(例如使用结束行)。
处理消息帧的另一种方法是使用长度前缀 - 在发送字符串本身之前,发送它的长度。然后,在另一端读取时,你就知道在字符串之间应该始终有一个长度前缀,因此读取器知道消息何时结束。
处理固定长度数据的另一种方法可能对你的情况没有多大用处。所以一个消息将始终正好是100个字节,例如。当与预定义的消息类型结合使用时,这非常强大 - 所以消息类型1将包含恰好两个整数,表示某些坐标,例如。
无论哪种情况,你都需要在接收端进行自己的缓冲。这是因为(如你已经看到的)单个接收可以一次读取多个消息,并且同时不能保证一次读取整个消息。编写你自己的网络编程实际上非常棘手 - 除非你正在做这个来真正学习网络编程,否则我建议使用一些现成的技术 - 例如Lindgren(一个很好的网络库,针对游戏进行了优化,但也适用于一般网络)或WCF。对于聊天系统,简单的HTTP(特别是具有双向WebSockets的)可能也足够了。
正如Damien所指出的那样,你的代码似乎还有另一个问题——你似乎忽略了
Read
的返回值。返回值告诉你实际读取了多少字节。由于接收端有一个固定大小的持久缓冲区(显然),这意味着每个在你刚刚读取后的字节仍将包含旧数据。要解决这个问题,只需确保你只使用
Read
返回的字节数即可。此外,由于这似乎表明你完全忽略了
Read
的返回值,请确保正确处理
Read
返回
0
的情况,这意味着另一端已经优雅地关闭了它的连接,接收方也应该如此做。
Receive
的返回值以查看实际接收到了多少字节。话虽如此,我也同意@Luaans的答案 - 如果你想要消息,那就由你来实现它们(或选择一个已经提供这种抽象的更高级别的网络库)。 - Damien_The_Unbeliever