Windows Wireshark看到的UDP数据包被WSARecvFrom丢弃(甚至没有到达)

Windows Wireshark看到的UDP数据包被WSARecvFrom丢弃(甚至没有到达),windows,winapi,sockets,operating-system,Windows,Winapi,Sockets,Operating System,我有一个相当令人困惑的问题。 我正在使用一个大的C++库来处理一些在Windows XP/7上的UDP专有协议。它在整个程序运行期间监听一个端口,并等待来自远程对等方的连接 大多数情况下,这很有效。然而,由于我遇到了一些问题,我决定在调用WSARecvFrom(库中使用的win32函数从我感兴趣的套接字中接收数据报,并告诉它们来自哪个IP和端口)之后直接添加一个简单的调试打印 奇怪的是,在某些情况下,我发现数据包是在操作系统级丢弃的(即,我在Wireshark中看到它们,它们有正确的dst端口,

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

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

现在,我完全明白“UDP不能保证交付”这一事实(人们往往有点过于频繁地提及),但这并不重要,因为机器接收到的数据包,我在Wireshark中看到了它们。
另外,我对操作系统缓冲区和填充的可能性很熟悉,但奇怪的是

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

  • 它们很小。协议中的许多数据包都很大,接近MTU,但所有丢弃的数据包都在100字节(总字节)以下
  • 它们总是两种类型中的一种:SYN等价物(即对等方发送给我们以启动通信的第一个数据包)或FIN等价物(即对等方不再有兴趣与我们交谈时发送的数据包)
  • 这两种质量中的任何一种都会影响操作系统缓冲区,并导致数据包被随机(或更有趣的-有选择地)丢弃吗?
    任何关于这个奇怪问题的说明都将不胜感激

    非常感谢


    编辑(2012年10月24日):

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

    例如,如果一个syn等效数据包从一个我们以前从未见过的对等方*到达,
    WSARecvFrom
    将看不到它。但是,如果我们已经将一个syn等效数据包发送给该对等方我们自己(即使它当时没有回复),现在它将一个syn等效数据包发送给我们,我们将看到它

    (*)我不确定这是一个我们从未见过的对等端口(即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));
    
    如果您仍然看到操作系统正在接收数据,但没有发送到套接字客户端,那么您可以考虑使用不同的日志记录方法。e、 g

    • 记录到RAM缓冲区,并仅偶尔打印(以您认为最有效的大小)
    • 从低优先级线程记录日志,要么接受此线程的内存需求不可预测,要么添加代码以在日志缓冲区满时丢弃数据

    关闭Windows防火墙

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

    这是我根据你在更新中所说的最符合逻辑的猜测:

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


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

    区域协调安排如下:

  • 确实,UDP能够到达目标计算机(见Wireshark)
  • 现在未找到到源的路由,因此无法在Wireshark上看到回复
  • 在某些操作系统上,您可以在Wireshark上看到请求数据包,但操作系统实际上并不提供数据包套接字(您可以在netstat nap中看到此套接字)
  • 在这种情况下,请始终检查ping(
    ping-I

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

    感谢您的回答,但是它仍然没有阐明被丢弃的数据包的具体特征(短、类syn或类fin、仅数据包)。另外,我可能还不够清楚,但日志记录并没有导致问题,我添加它来调查问题。我不需要它,否则:)我不认为当套接字的recv缓冲区填充时,数据丢失有任何定义的行为。您是否尝试过增加缓冲区大小以查看是否会减少丢弃的数据包数?我将尝试查询和调整缓冲区大小,但我同意-
    “我认为没有任何已定义的行为