gpt4 book ai didi

c# - NetworkStream 不刷新数据

转载 作者:行者123 更新时间:2023-12-02 20:30:18 26 4
gpt4 key购买 nike

我正在使用套接字编写一个简单的聊天程序。当我发送长消息时,随后刷新流和短消息,长消息的末尾会附加到短消息中。它看起来像这样:

发送“aaasdsd”

接收“aaasdsd”

发送“bb”

接收“bbasdsd

通过调试,我发现 Flush 方法应该清除流中的所有数据,但并没有这样做。根据 mdsn,这是预期的行为,因为 NetworkStream 没有缓冲。在这种情况下我该如何清除流?我可以在每条消息后面加上一个相同长度的空(由\0 字符组成),但我认为这样做是不正确的,而且它会搞砸我需要的一些功能。

最佳答案

TCP 不是这样工作的。就这么简单。

TCP 是一种基于流的协议(protocol)。这意味着您永远不应该将其视为基于消息的协议(protocol)(与 UDP 不同)。如果您需要通过 TCP 发送消息,则必须在 TCP 之上添加您自己的消息传递协议(protocol)。

您在这里尝试做的是发送两条单独的消息,并在另一端接收两条单独的消息。这在 UDP(基于消息的)上工作得很好,但在 TCP 上就不行了,因为 TCP 是一个没有组织的流。

是的,Flush 工作得很好。只是无论您在一侧调用多少次Flush,以及调用多少次单独的Send,一侧的每个Receive另一端将获取其缓冲区中能够容纳的尽可能多的数据,而不考虑另一端的 Send

您设计的解决方案(几乎 - 只需用单个 \0 分隔字符串)实际上是处理此问题的正确方法之一。通过这样做,您可以再次处理流顶部的消息。这称为消息框架 - 它允许您区分各个消息。就您而言,您已在消息之间添加了分隔符。考虑在文件中写入相同的数据 - 同样,您需要自己的某种方式来分隔各个消息(例如,使用结束行)。

处理消息帧的另一种方法是使用长度前缀 - 在发送字符串本身之前,发送它的长度。然后,当您在另一侧阅读时,您知道字符串之间应该始终有一个长度前缀,以便读者知道消息何时结束。

另一种方法对于您的情况可能不太有用 - 您可以使用固定长度的数据。例如,一条消息总是恰好是 100 个字节。当与预定义的消息类型结合使用时,这非常强大 - 因此消息类型 1 将恰好包含两个整数,例如表示一些坐标。

无论哪种情况,您都需要在接收端进行自己的缓冲。这是因为(正如您已经看到的)单个接收可以一次读取多条消息,同时,不能保证在一次读取中读取整个消息。编写自己的网络实际上非常棘手 - 除非您这样做是为了实际学习网络编程,我建议使用一些现成的技术 - 例如,Lindgren(一个很好的网络库,针对游戏进行了优化但也适用于一般网络)或 WCF。对于聊天系统,简单的 HTTP(尤其是使用双向 WebSocket)可能就可以了。

编辑:

正如 Damien 正确指出的那样,您的代码似乎还存在另一个问题 - 您似乎忽略了 Read 的返回值。返回值告诉您实际读取的字节数。由于您在接收端有一个固定大小的持久缓冲区(显然),这意味着您刚刚读取的数据量之后的每个字节仍将包含数据。要解决此问题,只需确保您仅使用 Read 返回的字节数即可。另外,由于这似乎表明您完全忽略了 Read 返回值,因此请确保在 Read 返回 0 时正确处理这种情况 -这意味着另一方已正常关闭其连接 - 接收方也应该这样做。

关于c# - NetworkStream 不刷新数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30499153/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com