我在用 C# 编写的客户端和服务器之间一次性发送大量数据。当我在本地计算机上运行客户端和服务器时,它工作正常,但是当我将服务器放在互联网上的远程计算机上时,它似乎丢失了数据。
我使用 socket.Send() 方法发送 20000 个字符串,并使用执行 socket.Receive() 的循环接收它们。每个字符串都由我用来计算收到的数字的唯一字符分隔(如果你愿意,这就是协议(protocol))。该协议(protocol)是经过验证的,因为即使是碎片化的消息,每个字符串也会被正确计算。在我的本地机器上我得到所有 20000,通过互联网我得到 17000-20000 之间的任何东西。远程计算机的连接速度越慢似乎越糟糕。更令人困惑的是,打开 Wireshark 似乎减少了丢失消息的数量。
首先,这是什么原因造成的?是 TCP/IP 问题还是我的代码有问题?
其次,我该如何解决这个问题?接收所有 20000 个字符串至关重要。
Socket接收代码:
private static readonly Encoding encoding = new ASCIIEncoding();
///...
while (socket.Connected)
{
byte[] recvBuffer = new byte[1024];
int bytesRead = 0;
try
{
bytesRead = socket.Receive(recvBuffer);
}
catch (SocketException e)
{
if (! socket.Connected)
{
return;
}
}
string input = encoding.GetString(recvBuffer, 0, bytesRead);
CountStringsIn(input);
}
套接字发送代码:
private static readonly Encoding encoding = new ASCIIEncoding();
//...
socket.Send(encoding.GetBytes(string));
最佳答案
如果您正在丢弃数据包,您会看到传输延迟,因为它必须重新传输丢弃的数据包。这可能非常重要,尽管有一个称为选择性确认的 TCP 选项,如果双方都支持,它将触发仅重新发送那些被丢弃的数据包,而不是自丢弃数据包以来的每个数据包。无法在您的代码中控制它。默认情况下,您始终可以假设每个数据包都按顺序传送给 TCP,如果由于某种原因不能按顺序传送每个数据包,则连接将断开,要么是超时,要么是连接的一端发送RST数据包。
您所看到的很可能是 Nagle 算法的结果。它所做的不是在您发布数据时发送每一位数据,而是发送一个字节,然后等待另一方的确认。在等待期间,它会聚合您要发送的所有其他数据并将其组合成一个大数据包,然后发送。由于 TCP 的最大大小为 65k,它可以将相当多的数据组合到一个数据包中,尽管这种情况极不可能发生,特别是因为 winsock 的默认缓冲区大小约为 10k 左右(我忘记了确切的数量)。此外,如果接收方的最大窗口大小小于 65k,它只会发送与接收方最后公布的窗口大小一样多的数据。窗口大小也会影响 Nagle 的算法,以及它在发送之前可以聚合的数据量,因为它不能发送超过窗口大小的数据。
你看到这个的原因是因为在互联网上,不像你的网络,第一个 ack 需要更多的时间来返回所以 Naggle 的算法将更多的数据聚合到一个数据包中。在本地,返回实际上是瞬时的,因此它能够在您将数据发布到套接字时尽可能快地发送数据。您可以使用 SetSockOpt (winsock) 或 Socket.SetSocketOption (.Net) 在客户端禁用 Naggle 算法,但我强烈建议您不要在套接字上禁用 Naggling,除非您 100% 确定您知道自己在做什么。这是有充分理由的。
关于c# - 在 C# 中处理丢弃的 TCP 数据包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1338006/