将一条完整的消息写入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);

每种方法的程序性能或网络性能是否也有很大差异?

将一条完整的消息写入NetworkStream,还是将每条消息的部分写入是个好主意

这很棘手,取决于套接字的配置方式。您所写的内容不会直接映射到收到的内容:

  • NIC可能必须在传输时将其拆分为数据包
  • 套接字/NIC可以被配置为组合数据包进行传输(减少实际的网络数据包,但很难确定你已经发送了你认为拥有的数据-它可能在本地缓冲)

请特别注意,NetworkStream.Flush()不会执行任何操作,因此您不能使用它来推送任何最后几个字节的

一个好的折衷方案是将NetworkStream封装在BufferedStream中,并使用NoDelay = true配置Socket(禁用本地输出缓冲)。BufferedStream允许您继续以任何大小的块(包括单个字节)进行写入,而不会造成巨大的数据包碎片;当CCD_ 7接近设定大小时。但是,更重要的是,您现在可以访问BufferedStreamFlush()方法,该方法将将缓冲数据清空到网络;如果有一个复杂的后台对话,并且需要知道你已经发送了信息的末尾,这很有用。

否则的风险是,客户端永远等待响应(没有意识到它在本地仍有3个字节缓冲,因此没有发送完整的请求),而服务器没有响应,因为它仍在等待请求的最后3个字节。僵局

在网络方面也是如此。但是在客户端上,如果使用第二种方法,则不需要将整个消息加载到内存中。这在处理大量数据时可能非常有用。例如,假设您想要发送巨大的文件。你可以分块读取这些文件,这样你就不需要将整个文件内容加载到内存中,然后分块发送到网络。在客户端的内存中,一次只能加载一个块。

但很明显,如果你已经在内存中存储了整个消息,就不用麻烦了,一次性将其写入网络套接字。