9

我正在用 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小姐)。奇怪的是,这些延迟会出现在典型 ping 时间 <1 毫秒的 LAN 连接上,但如果服务器在 localhost 上运行,它们就不会发生,即使 ping 时间实际上是相同的(至少差异不应该是大约 100 毫秒)。如果我在每个数据包上重新打开连接,这对我来说是有意义的,导致很多握手,但我不是。就好像服务器进入等待状态会使其与客户端不同步,然后在重新建立本质上是丢失的连接时会有点跌跌撞撞。

那么,我做错了吗?有没有办法让 TcpServer 和 TcpClient 之间的连接保持同步,以便服务器始终准备好接收数据?(反之亦然:有时处理来自客户端的请求需要几毫秒,然后客户端似乎还没有准备好接收来自服务器的响应,直到它在 Read() 阻塞后有片刻时间醒来.)

4

1 回答 1

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,与我的第一个版本),没有提到这样做会导致非常严重的性能损失。

于 2011-05-26T10:30:57.707 回答