大量写入网络管道时会丢失字节

Bytes are lost when writing a lot to network pipe

我想通过命名管道在两台计算机之间发送一些字节。客户端发送 65537 字节和 PipeStream.Write() returns 就好像字节已发送一样,但服务器从未接收到这些字节。为什么客户要骗我?我想我可以分块发送我的字节,但我的印象是 PipeStream.Write 会为我这样做。其中一台机器是虚拟的,一台是物理的。如果客户端少发送一个字节(65536 字节),服务器将全部接收。在另一种情况下,两台机器都是物理机器,所有 65537 字节也都可以正常接收。下面是重现该行为的代码。 运行 test.exe 100000 - 在一台机器上,test.exe 65537 other.comp.name 在另一台机器上:

class Program
{
    const string PipeName = "TestPipe";

    static void Main(string[] args)
    {
        int bufferSize = int.Parse(args[0]);

        if (args[1] == "-")
        {
            using (var server = new NamedPipeServerStream(PipeName, PipeDirection.InOut, 1,
                PipeTransmissionMode.Byte, PipeOptions.Asynchronous))
            {
                server.WaitForConnection();

                byte[] result = new byte[bufferSize];

                for (int offset = 0; offset < bufferSize; )
                {
                    IAsyncResult asyncResult = server.BeginRead(result, offset, bufferSize - offset, null, null);

                    asyncResult.AsyncWaitHandle.WaitOne();

                    int bytesRead = server.EndRead(asyncResult);

                    if (bytesRead == 0)
                    {
                        Console.WriteLine("Client closed the pipe after {0} bytes.", offset);
                        return;
                    }

                    offset += bytesRead;
                }

                Console.WriteLine("All bytes are read.");
            }
        }
        else
        {
            using (var client = new NamedPipeClientStream(args[1], PipeName, PipeDirection.InOut, PipeOptions.Asynchronous))
            {
                client.Connect(1000);

                byte[] buffer = new byte[bufferSize];

                client.Write(buffer, 0, buffer.Length);

                client.WaitForPipeDrain();

                Console.WriteLine("All bytes are written.");
            }
        }
    }
}

您在 PipeTransmissionMode.Byte 中使用管道。预计在此模式下发送数据并完成处理。在这种情况下,在您的服务器代码中,您不应停止读取 0 个字节。而是检查 server.IsConnected,一旦您的客户端关闭管道,这意味着所有数据都已发送,此值变为 false。您可能会在两者之间获得一些 bytesRead==0 读数。

当涉及 64KB 的 VM 限制时,我刚刚接受了 C# 对我撒谎的事实。解决方法是分块发送字节,不再谈论它。