- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用套接字编写一个简单的聊天程序。当我发送长消息时,随后刷新流和短消息,长消息的末尾会附加到短消息中。它看起来像这样:
发送“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/
我希望有人可以解释这种行为,或者它是否可能是 .NET 中的错误。 由于夏令时而及时向后移动意味着 NetworkStream 不注意其属性 ReadTimeout,并且在此代码的情况下会导致循环旋转
我需要从 NetworkStream 中读取,它会随机发送数据,数据包的大小也会不断变化。我正在实现一个多线程应用程序,其中每个线程都有自己的流来读取。如果流中没有数据,应用程序应该一直等待数据到达。
我编写了以下函数来使用 NetworkStream 的异步读取函数(BeginRead 和 EndRead)实现超时功能。它工作正常,直到我注释掉行 Trace.WriteLine("bytesRea
如果 Internet 上的 B 类网络的子网掩码为 255.255.248.0,那么每个子网的最大主机数是多少?(一) 1022(乙) 1023(三) 2046(D) 2047 任何人都可以告诉我如
我读过一个 Tcp Echo Server 的例子,有些事情我不清楚。 TcpClient client = null; NetworkStream netStream = null; try {
This question already has answers here: NetworkStream.ReadAsync with a cancellation token never canc
我正在使用套接字编写一个简单的聊天程序。当我发送长消息时,随后刷新流和短消息,长消息的末尾会附加到短消息中。它看起来像这样: 发送“aaasdsd” 接收“aaasdsd” 发送“bb” 接收“bba
我目前正在从事一个网络项目,我在其中制定了一个二进制协议(protocol)。我的数据包看起来像这样:[1 字节类型][2 字节索引][2 字节长度][长度字节数据] 这是我接收数据包的代码: Net
我的应用程序打开一个 NetworkStream 和一个 StreamWriter 以将 HL7 消息发送到服务。此服务接收 HL7 消息并始终发回确认。我遇到以下问题:在发送 HL7 消息(有效,我
在同一台计算机上,我有 2 个控制台应用程序。 (客户端向服务器发送文件) 在开始之前,我只想提一下我正在使用这两个 async 函数: 从 NetworkStream 读取: public sta
我正在编写一个简单的客户端-服务器应用程序,在查看 MSDN 文档时,我遇到了一些有趣的流类型... http://msdn.microsoft.com/en-us/library/system.io
早上好 我需要一些建议,我正在使用从 TcpClient 流式传输的 networkStream,一切正常,但后来我需要其他地方的一些功能,这需要关闭流。一旦连接关闭,我似乎找不到重新打开连接的方法。
只是尝试使用 Networkstream,这是我写的一个简单代码: 客户端: TcpClient c = new TcpClient(); c.Connect("10.0
我使用 Moq 和 NUnit 作为单元测试框架。 我写了一个方法,将 NetworkStream 对象作为参数: public static void ReadDataIntoBuffer(Netw
好吧,所以我理解 TCP 是基于流而不是基于消息的整个想法 - 我不关心这个。 我想做的是简单地序列化一些东西,然后通过网络将它发送到另一个使用相同的基于消息的协议(protocol)的应用程序。 问
NetworkStream 从套接字缓冲区读取不应该存在的数据时出现问题。顺便说一句,我正在发送非常大的缓冲区。现在我刚刚在本地主机上进行测试。 这是我读取数据的方式,前 4 个字节包含消息的长度,然
我使用 TcpClient 和 NetworkStream 为我们的游戏创建了一个简单的持久套接字连接。正常连接、发送消息和断开连接(退出应用程序/服务器关闭/等)都没有问题。 但是,我遇到了一些问题
有问题的数据是一个 PNG 文件,前缀为 int 大小。 -Sending: ns.Write(BitConverter.GetBytes((int)data.Length),0,4); ns.Wri
NetworkStream.DataAvailable 是否知道发送方的发送缓冲区是否为空?或者它只是简单地指示接收方的读取缓冲区是否有数据?我的假设是后者... 具体来说,对于一些涉及正在进行的对话
我有一个类,它包装了一个 Stream 实例,所以我可以用它来包装 FileStreams 和 NetworkStreams。现在,我想测试流是否仍在传递任何数据,换句话说,我想测试 NetworkS
我是一名优秀的程序员,十分优秀!