处理C#中丢弃的TCP数据包

我在客户端和编写C#的服务器之间一次性发送大量数据.当我在本地计算机上运行客户端和服务器时它工作正常,但是当我将服务器放在互联网上的远程计算机上时,它似乎丢弃了数据.

我使用socket.Send()方法发送20000个字符串,并使用一个执行socket.Receive()的循环接收它们.每个字符串由唯一字符分隔,我用它来计算收到的数字(如果你愿意,这是协议).该协议经过验证,即使使用碎片消息,每个字符串也会被正确计算.在我的本地机器上,我得到全部20000,通过互联网我得到17000-20000之间的任何东西.远程计算机的连接速度似乎更慢.为了增加混乱,打开Wireshark似乎减少了丢弃的消息数量.

首先,是什么原因造成的?这是TCP / IP问题还是我的代码有问题?

其次,我怎么能绕过这个?接收所有20000个字符串至关重要.

套接代码

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,bytesRead);
    CountStringsIn(input);
}

套接字发送代码

private static readonly Encoding encoding = new ASCIIEncoding();
//...
socket.Send(encoding.GetBytes(string));

解决方法

如果您丢弃数据包,您将看到传输延迟,因为它必须重新传输丢弃的数据包.这可能是非常重要的,尽管有一个称为选择性确认的TCP选项,如果双方支持,它将仅触发丢弃的数据包的重发,而不是每个数据包的重新发送.在代码中无法控制它.认情况下,您始终可以假设每个数据包都是为TCP发送的,如果有某些原因导致它无法按顺序传送每个数据包,则连接将丢失,无论是超时还是发送连接的一端RST包.

您所看到的很可能是Nagle算法的结果.它所做的不是在发布时发送每一位数据,而是发送一个字节,然后等待来自另一方的ack.在等待时,它会聚合您要发送的所有其他数据,并将其合并为一个大数据包然后发送.由于TCP的最大大小为65k,它可以将相当多的数据合并到一个数据包中,尽管这种情况发生的可能性极小,特别是因为winsock的认缓冲区大小约为10k左右(我忘记了确切的数量).此外,如果接收器的最大窗口大小小于65k,它将仅发送与接收器的最后一个广告窗口大小一样多的数量.窗口大小也影响Nagle的算法,因为它在发送之前可以聚合多少数据,因为它不能发送超过窗口大小的数据.

您之所以看到这一点,是因为在互联网上,与您的网络不同,第一个ack需要更多时间才能返回,因此Naggle算法会将更多数据聚合到一个数据包中.在本地,返回实际上是瞬时的,所以它能够尽快发送数据到将其发布到套接字.您可以使用SetSockOpt(winsock)或Socket.SetSocketoption(.Net)在客户端禁用Naggle算法,但我强烈建议您不要在套接字上禁用Naggling,除非您100%确定您知道自己在做什么.这是有充分理由的.

相关文章

原文地址:http://msdn.microsoft.com/en-us/magazine/cc163...
前言 随着近些年微服务的流行,有越来越多的开发者和团队所采...
最近因为比较忙,好久没有写博客了,这篇主要给大家分享一下...
在多核CPU在今天和不久的将来,计算机将拥有更多的内核,Mic...
c语言输入成绩怎么判断等级
字符型数据在内存中的存储形式是什么