首页 文章

UDP数据包,由Wireshark看到,丢弃(甚至无法到达)WSARecvFrom

提问于
浏览
10

我有一个令人困惑的问题 .
我在Windows XP / 7上使用大型C库来处理UDP上的一些专有协议 . 它在整个程序运行期间侦听一个端口,并等待来自远程对等端的连接 .

大多数情况下,这很有效 . 但是,由于某些问题,我决定在调用 WSARecvFrom 之后直接添加一个简单的调试打印(库中使用的win32函数从我感兴趣的套接字中恢复数据报,并告诉它们来自哪个IP和端口) .
奇怪的是,在某些情况下,我发现数据包被丢弃在 OS level (即我在Wireshark中看到它们,它们有正确的dst端口,所有校验和都是正确的 - 但它们从未出现在我植入的调试打印中进入代码) .

现在,我完全相信(人们往往会经常提一下)"UDP doesn't guarantee delivery" - 但这与机器收到的数据包 are 无关 - 我在Wireshark中看到它们 .
此外,我熟悉操作系统缓冲区和填充的可能性,但这里有一些奇怪的部分......

我发现,所有丢弃的数据包共享两个共同点(虽然有些,但绝大多数没有被丢弃的数据包共享这些):

  • 他们很小 . 协议中的许多数据包很大,接近MTU - 但丢弃的所有数据包都不到100字节(总) .

  • 它们总是两个中的一个:SYN等价物(即对等体发送给我们以发起通信的第一个数据包)或FIN等效物(即当对象不再有兴趣与我们交谈时发送的数据包) ) .

这两种品质中的任何一种都可以影响OS缓冲区,并导致数据包随机丢弃(或者更有趣 - 有选择地)掉线?
任何关于这个奇怪问题的灯都会非常感激 .

非常感谢 .


EDIT (24/10/12):

我想我可能错过了一个重要的细节 . 似乎在到达之前丢弃的数据包共享其他共同点:它们(我开始相信,只有它们)被"new"对等体发送到服务器,即对等体 hasn't tried to contact before .

例如,如果一个syn-equivalent数据包从我们以前从未见过的对等体*到达,则 WSARecvFrom 将不会看到它 . 但是,如果我们已经向该对等方发送了一个syn-equivalent数据包 ourselves (即使它当时没有回复),现在它发送 us 一个syn-equivalent,我们也会看到它 .

(*)我不确定这是否是我们没见过的同伴(即ip:port),或者只是我们以前从未见过的端口 .

这有帮助吗?
这是某种WinSock选项我不知道吗?

再次感谢!

4 回答

  • 1

    操作系统有一个固定大小的缓冲区,用于到达您的套接字但尚未被您读取的数据 . 当此缓冲区耗尽时,它将开始丢弃数据 . 调试日志记录可能会通过延迟从套接字中提取数据的速率来加剧这种情况,从而增加溢出的可能性 .

    如果这是问题,您至少可以通过请求更大的recv缓冲区来减少它的实例 .

    您可以使用查看套接字的recv缓冲区的大小

    int recvBufSize;
    int err = getsockopt(socket, SOL_SOCKET, SO_RCVBUF,
                         (char*)&recvBufSize, sizeof(recvBufSize));
    

    并且您可以使用它将其设置为更大的尺寸

    int recvBufSize = /* usage specific size */;
    int err = setsockopt(socket, SOL_SOCKET, SO_RCVBUF,
                         (const char*)&recvBufSize, sizeof(recvBufSize));
    

    如果您仍然看到操作系统收到的数据但未传送到套接字客户端,您可以考虑采用不同的日志记录方法 . 例如

    • 登录到RAM缓冲区并仅偶尔打印(无论您调整哪种尺寸,效率最高)

    • 从低优先级线程记录,要么接受对此的内存要求不可预测,要么添加代码以在日志缓冲区满了时丢弃数据

  • 3

    我有一个非常类似的问题,在确认接收缓冲区没有导致丢弃后,我得知这是因为我将接收超时设置得太低,不到1ms . 将套接字设置为非阻塞而不设置接收超时为我解决了问题 .

  • 0

    关闭Windows防火墙 .

    这样可以解决吗?如果是这样,您可以重新启用防火墙,只需为您的程序添加规则 .

    根据您在更新中的说法,这是我最合乎逻辑的猜测:

    似乎在到达之前丢弃的数据包共享其他共同点:它们(我开始相信,只有它们)被“新”对等体发送到服务器,即它之前没有尝试联系的对等体 .

  • 2

    在redhat-linux上也面临同样的问题 . 结果是路由问题 .

    RCA如下 . 1.确实UDP能够到达目的地机器(在wireshark上看到) . 2.现在找不到路由到源,所以在wireshark上看不到回复 . 3.在某些操作系统上,您可以在wireshark上看到请求数据包,但操作系统实际上没有传递数据包套接字(您可以在netstat-nap中看到此套接字) . 4.在这种情况下,请检查ping总是(ping -I)

    Rgds,Kishor

相关问题