将一条完整的消息写入NetworkStream,还是将每条消息的部分写入是个好主意
本文关键字:消息 好主意 NetworkStream 一条 | 更新日期: 2023-09-27 18:22:41
我一直在想,向NetworkStream写入完整的消息是否比在多个Write调用中写入消息的每一部分更好。例如,会像这样完整地写信息吗。。。
NetworkStream ns = tcpClient.GetStream();
byte[] message = Encoding.ASCII.GetBytes("This is a message.");
ns.Write(message, 0, message.Length);
做一个比这样写更好的主意。。。
NetworkStream ns = tcpClient.GetStream();
byte[] message1 = Encoding.ASCII.GetBytes("This ");
byte[] message2 = Encoding.ASCII.GetBytes("is ");
byte[] message3 = Encoding.ASCII.GetBytes("a ");
byte[] message4 = Encoding.ASCII.GetBytes("message.");
ns.Write(message1, 0, message1.Length);
ns.Write(message2, 0, message2.Length);
ns.Write(message3, 0, message3.Length);
ns.Write(message4, 0, message4.Length);
每种方法的程序性能或网络性能是否也有很大差异?
这很棘手,取决于套接字的配置方式。您所写的内容不会直接映射到收到的内容:
- NIC可能必须在传输时将其拆分为数据包
- 套接字/NIC可以被配置为组合数据包进行传输(减少实际的网络数据包,但很难确定你已经发送了你认为拥有的数据-它可能在本地缓冲)
请特别注意,NetworkStream.Flush()
不会执行任何操作,因此您不能使用它来推送任何最后几个字节的
一个好的折衷方案是将NetworkStream
封装在BufferedStream
中,并使用NoDelay = true
配置Socket
(禁用本地输出缓冲)。BufferedStream
允许您继续以任何大小的块(包括单个字节)进行写入,而不会造成巨大的数据包碎片;当CCD_ 7接近设定大小时。但是,更重要的是,您现在可以访问BufferedStream
的Flush()
方法,该方法将将缓冲数据清空到网络;如果有一个复杂的后台对话,并且需要知道你已经发送了信息的末尾,这很有用。
否则的风险是,客户端永远等待响应(没有意识到它在本地仍有3个字节缓冲,因此没有发送完整的请求),而服务器没有响应,因为它仍在等待请求的最后3个字节。僵局
在网络方面也是如此。但是在客户端上,如果使用第二种方法,则不需要将整个消息加载到内存中。这在处理大量数据时可能非常有用。例如,假设您想要发送巨大的文件。你可以分块读取这些文件,这样你就不需要将整个文件内容加载到内存中,然后分块发送到网络。在客户端的内存中,一次只能加载一个块。
但很明显,如果你已经在内存中存储了整个消息,就不用麻烦了,一次性将其写入网络套接字。