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

时间:2012-10-11 07:37:22

标签: windows winapi sockets operating-system

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

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

现在,我完全相信(人们倾向于经常提及)“UDP不保证交付” - 但这并不重要,因为 通过机器 - 我在Wireshark看到它们 此外,我熟悉操作系统缓冲区和填充的可能性,但这里有一些奇怪的部分......

我做了一些研究,试图找出哪些数据包被准确删除。我发现的是,所有丢弃的数据包共享两个共同点(虽然一些,但绝对不是大多数不是 / em>也分享了这些内容):

  1. 他们很小。协议中的许多数据包都很大,接近MTU - 但丢弃的所有数据包都不到100字节(粗略)。
  2. 它们总是两个中的一个:SYN等价物(即对等体发送给我们的第一个数据包以发起通信)或FIN等效物(即当对象不再对谈话感兴趣时发送的数据包给我们)。
  3. 这两种品质中的任何一种都可以影响操作系统缓冲区,并导致数据包随机丢失(或者更有趣 - 有选择地)丢弃吗? 任何关于这个奇怪问题的灯都会非常感激。

    非常感谢。


    编辑(24/10/12):

    我想我可能错过了一个重要的细节。似乎在到达之前丢弃的数据包共享其他共同点:它们(我开始相信,它们)被“新”对等体发送到服务器,即它< strong>之前没有尝试联系。

    例如,如果一个syn等效数据包来自我们以前从未见过的对等*,WSARecvFrom将不会看到它。但是,如果我们已经向同伴发送了一个syn-equivalent数据包我们自己(即使它当时没有回复),现在它发送我们相当于,我们会看到它。

    (*)我不确定这是否是我们还没有看到的 peer (即ip:port)或者只是 port 我们还没有看到之前。

    这有帮助吗?
    这是我从未听说过的某种WinSock选项吗? (正如我上面所说,代码不是我的,所以它可能是使用我不知道的套接字选项)

    再次感谢!

4 个答案:

答案 0 :(得分:3)

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

如果这是问题,您至少可以通过请求更大的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));

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

  • 登录到RAM缓冲区,仅偶尔打印(无论您调整哪种尺寸,效率最高)
  • 从低优先级线程记录,要么接受对此的内存要求不可预测,要么添加代码以在日志缓冲区满了时丢弃数据

答案 1 :(得分:2)

我遇到了一个非常相似的问题,在确认接收缓冲区没有引起丢弃之后,我得知这是因为我将接收超时设置为1ms太低了。将套接字设置为非阻塞并且未设置接收超时对我来说解决了这个问题。

答案 2 :(得分:1)

关闭Windows防火墙。

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

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

  

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

答案 3 :(得分:0)

在redhat-linux上也面临同样的问题。 结果这是一个路由问题。

RCA如下:

  1. 确实,UDP能够到达目标计算机(在Wireshark上看到)。
  2. 现在找不到路由到源,因此Wireshark上没有回复。
  3. 在某些操作系统上,您可以在Wireshark上看到请求数据包,但操作系统实际上没有传递数据包套接字(您可以在netstat-nap中看到此套接字)。
  4. 在这些情况下,请务必检查ping(ping <dest ip> -I<source ip>