大量写入网络管道时会丢失字节
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# 对我撒谎的事实。解决方法是分块发送字节,不再谈论它。
我想通过命名管道在两台计算机之间发送一些字节。客户端发送 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# 对我撒谎的事实。解决方法是分块发送字节,不再谈论它。