我有一个令人困惑的问题。 我在Windows XP / 7上使用大型C ++库来处理UDP上的某些专有协议。它在整个程序运行期间侦听一个端口,并等待来自远程对等端的连接。
大多数情况下,这很有效。但是,由于我遇到的一些问题,我决定在调用WSARecvFrom
之后直接添加一个简单的调试打印(库中使用的win32函数从我感兴趣的套接字中恢复数据报,并告诉我什么是IP和端口他们来自)。
奇怪的是,在某些情况下,我发现数据包在操作系统级别被删除(即我在Wireshark中看到它们,它们有正确的dst端口,所有校验和都是正确的 - 但它们从未出现在我的调试打印中植入代码)。
现在,我完全相信(人们倾向于经常提及)“UDP不保证交付” - 但这不相关,因为数据包是由机器接收的 - 我在Wireshark中看到它们。 此外,我熟悉操作系统缓冲区和填充的可能性,但这里有一些奇怪的部分......
我做了一些研究,试图找出哪些数据包被准确删除。我发现的是,所有丢弃的数据包共享两个共同点(尽管有些,但绝对不是大多数,未丢弃的数据包也共享这些):
这两种品质中的任何一种都可以影响OS缓冲区,并导致数据包随机丢弃(或者更有趣 - 有选择地)掉线? 任何关于这个奇怪问题的灯都会非常感激。
非常感谢。
编辑(24/10/12):
我想我可能错过了一个重要的细节。似乎在到达之前丢弃的数据包共享其他共同点:它们(我开始相信,只有它们)被“新”对等体(即之前未尝试联系的对等体)发送到服务器。
例如,如果一个syn-equivalent数据包从我们以前从未见过的同行*到达,那么WSARecvFrom
就不会看到它。但是,如果我们自己已经向该对等方发送了一个syn-equivalent数据包(即使它当时没有回复),现在它向我们发送了一个syn-equivalent,我们将会看到它。
(*)我不确定这是否是我们没见过的同伴(即ip:port)或者只是我们以前从未见过的端口。
这有帮助吗? 这是我从未听说过的某种WinSock选项吗? (正如我上面所说,代码不是我的,所以它可能是使用我不知道的套接字选项)
再次感谢!
操作系统有一个固定大小的缓冲区,用于到达您的套接字但尚未被您读取的数据。当此缓冲区耗尽时,它将开始丢弃数据。调试日志记录可能会通过延迟从套接字中提取数据的速率来加剧这种情况,从而增加溢出的可能性。
如果这是问题,您至少可以通过请求更大的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));
如果您仍然看到操作系统收到的数据但未传送到套接字客户端,您可以考虑采用不同的日志记录方法。例如
我有一个非常类似的问题,在确认接收缓冲区没有导致丢弃后,我得知这是因为我将接收超时设置得太低,不到1ms。将套接字设置为非阻塞而不设置接收超时为我解决了问题。
关闭Windows防火墙。
这样可以解决吗?如果是这样,您可以重新启用防火墙,只需为您的程序添加规则。
根据您在更新中的说法,这是我最合乎逻辑的猜测:
似乎在到达之前丢弃的数据包共享其他共同点:它们(我开始相信,只有它们)被“新”对等体(即之前未尝试联系的对等体)发送到服务器。
在redhat-linux上也面临同样的问题。结果这是一个路由问题。
RCA如下:
ping <dest ip> -I<source ip>
)