14

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

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

现在,我完全相信“UDP 不能保证交付”这一事实(人们往往会经常提及)——但这不相关,因为数据包由机器接收的——我在 Wireshark 中看到了它们。
此外,我熟悉操作系统缓冲区和填满的可能性,但奇怪的部分来了……

我做了一些研究,试图找出哪些数据包被丢弃了。我发现,所有丢弃的数据包都有两个共同点(虽然一些,但绝对不是大多数没有丢弃的数据包也共享这些):

  1. 他们很小。协议中的许多数据包都很大,接近 MTU - 但所有丢弃的数据包都小于 100 字节(总)。
  2. 它们总是两个之一:一个 SYN 等效(即对等方发送给我们以启动通信的第一个数据包)或 FIN 等效性(即当对等方不再有兴趣与我们交谈时发送的数据包) .

这两种品质中的任何一种都会影响操作系统缓冲区,并导致数据包被随机(或更有趣 - 有选择地)丢弃吗?
任何关于这个奇怪问题的线索将不胜感激。

非常感谢。


编辑(24/10/12):

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

例如,如果一个同步等效数据包从我们以前从未见过的对等点*到达,则它不会被WSARecvFrom. 但是,如果我们自己向该对等方发送了一个 syn-equivalent 数据包(即使它当时没有回复),现在它向我们发送了一个 syn-equivalent,我们将看到它。

(*) 我不确定这是一个我们没见过的对等点(即 ip:port)还是只是一个我们以前没见过的端口。

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

再次感谢!

4

4 回答 4

3

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

如果这是问题所在,您至少可以通过请求更大的 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 缓冲区并仅偶尔打印(以您配置文件最有效的任何大小)
  • 从低优先级线程记录,要么接受对此的内存需求将是不可预测的,要么添加代码以在日志缓冲区已满时丢弃数据
于 2012-10-11T08:11:27.760 回答
2

我有一个非常相似的问题,在确认接收缓冲区没有导致下降后,我了解到这是因为我将接收超时设置得太低,为 1 毫秒。将套接字设置为非阻塞并且不设置接收超时为我解决了这个问题。

于 2018-10-25T20:26:44.850 回答
1

关闭 Windows 防火墙。

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

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

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

于 2013-08-17T05:53:41.080 回答
0

在redhat-linux上也遇到了同样的问题。这原来是一个路由问题。

RCA如下:

  1. 确实,UDP 能够到达目标机器(在 Wireshark 上看到)。
  2. 现在找不到到源的路由,因此在 Wireshark 上看不到回复。
  3. 在某些操作系统上,您可以在 Wireshark 上看到请求数据包,但操作系统实际上并未传递数据包套接字(您可以在 netstat-nap 中看到此套接字)。
  4. 在这种情况下,请始终检查 ping ( ping <dest ip> -I<source ip>)
于 2015-02-02T08:58:03.853 回答