我正在用C#编写客户端/服务器应用程序,而且它很棒。现在,一切正常,而且非常强大。我的问题是,当通过连接发送数据包时,我遇到了一些延迟。
在客户端,我这样做:
NetworkStream ns = tcpClient.GetStream();
// Send packet
byte[] sizePacket = BitConverter.GetBytes(request.Length);
byte[] requestWithHeader = new byte[sizePacket.Length + request.Length];
sizePacket.CopyTo(requestWithHeader, 0);
request.CopyTo(requestWithHeader, sizePacket.Length);
ns.Write(requestWithHeader, 0, requestWithHeader.Length);
// Receive response
ns.Read(sizePacket, 0, sizePacket.Length);
int responseLength = BitConverter.ToInt32(sizePacket, 0);
byte[] response = new byte[responseLength];
int bytesReceived = 0;
while (bytesReceived < responseLength)
{
int bytesRead = ns.Read(response, bytesReceived, responseLength - bytesReceived);
bytesReceived += bytesRead;
}
(遗漏了一些异常捕获等)服务器执行相反的操作,即它在NetworkStream.Read()上阻塞,直到它有一个完整的请求,然后处理它并使用Write()发送响应。
Write()/ Read()的原始速度不是问题(即发送大数据包很快),但是在不关闭连接的情况下一个接一个地发送几个小数据包可能非常慢(延迟50-100毫秒)。奇怪的是,这些延迟出现在LAN连接上,典型的ping时间<1 ms,但如果服务器在localhost上运行则不会发生,即使ping时间实际上是相同的(至少差异不应该大约100毫秒)。如果我在每个数据包上重新打开连接,导致大量握手,那对我来说是有意义的,但我不是。这就好像服务器进入等待状态会使它与客户端不同步,然后在重新建立本质上是丢失的连接时发现它有点绊倒。
那么,我做错了吗?有没有办法保持TcpServer和TcpClient之间的连接同步,以便服务器随时准备接收数据? (反之亦然:有时处理来自客户端的请求需要几毫秒,然后客户端似乎没有准备好接收来自服务器的响应,直到它在Read()上阻塞之后有一些时刻被唤醒。)
答案 0 :(得分:7)
事实证明我的服务器和客户端毕竟不是完全对称。我注意到了,但我认为它根本不重要。显然这是一个巨大的交易。具体来说,服务器执行了此操作:
ns.Write(sizePacket, 0, sizePacket.Length);
ns.Write(response, 0, response.Length);
我改变了这个:
// ... concatenate sizePacket and response into one array, same as client code above
ns.Write(responseWithHeader, 0, responseWithHeader.Length);
现在延迟完全消失了,或者至少它在几毫秒内不再可测量。所以这就像100倍的加速一样。 \ O /
它仍然很奇怪,因为它正在向套接字写入与之前完全相同的数据,所以我想套接字在写操作期间会收到一些秘密元数据,然后以某种方式传递给远程套接字,这可能会将其解释为机会小睡一下。要么是这样,要么第一次写入将套接字置于接收模式,导致它在收到任何内容之后被要求再次发送时绊倒。
我认为这意味着所有这些示例代码都存在,它显示了如何以固定大小的块(通常在单个int之前写入和读取数据包的大小) ,就像我的第一个版本一样),没有提到这样做会造成非常严重的性能损失。