【问题标题】:sendto() packet dropped by kernelsendto() 数据包被内核丢弃
【发布时间】:2014-02-22 08:47:57
【问题描述】:
ioctl(socketFd_, SIOCOUTQ, &outstandingBytes);  
getsockopt(socketFd_, SOL_SOCKET, SO_SNDBUF, &sendBuffSize, &buffLen);  

我正在使用这两个api来调试我的程序中的丢包。
观察:

  1. sendto 将始终返回数据包大小,因此对 sendto 的调用始终成功。
  2. oustandingBytes 达到 2040 时,Linux 内核将丢弃数据包,这意味着我无法在 Wireshark 中看到它。我正在本地 eth 接口上捕获数据包。
  3. 我的 sendBuffSize 是 124928,由 getsockopt 返回。
  4. 我发送的数据包大小约为 300 到 350 字节。我有两个套接字,一个用于发送 GRE 数据包的原始套接字和另一个 udp 套接字,我看到两种协议的数据包丢失,两个套接字都处于非阻塞模式。
    sendto 是否无法检测到错误,因为数据包在达到 sendBuffSize 限制之前被丢弃?
    如何在我的系统中增加 2040 的限制。此值应为 getsockopt() api 返回的 124928。
    对于这个问题,我有类似的线程,如下所示,但是我无法得到答案,所以决定开始一个新线程。
    rawsocket sendto() some of the packet are dropped and not seen in the network

【问题讨论】:

    标签: linux sockets networking linux-kernel sendto


    【解决方案1】:

    UDP 和原始套接字不提供任何方法来检测丢弃的数据包。数据包可能由于路由器故障或网络拥塞而在网络中丢失,也可能在内核中被丢弃。如果需要检测丢包,必须在应用层做,或者在UDP之上实现一个会话层。

    如果调用sendto()时内核无法缓冲数据包,它应该返回-1并将errno设置为EWOULDBLOCK

    【讨论】:

    • 我的程序中有重传逻辑,但是我正在寻找的根本原因是,sendto 没有返回任何错误,并且在达到发送缓冲区大小限制之前,linux 内核就已经丢弃了数据包。
    • 然而,“UDP 不提供丢弃数据包检测”和“网络堆栈只会以完全合理的速率丢弃数据包”之间存在很大差异。 2040 字节完全在单个 UDP 图的允许大小范围内,并且少于 2 个以太网帧(或 1 个巨型帧)。虽然您显然不能保证什么会到达电缆的另一端,但您应该非常肯定地能够期望您的数据包至少到达网卡(即使它们是 10 个较小的数据报)。
    • 我对他声称当他仅排队 2040 个字节时数据包被丢弃的说法持怀疑态度。我敢肯定,高性能 DNS 服务器以高速率发送的字节数是该字节数的许多倍。
    • "2040 字节在单个 UDP 图的允许大小范围内" -- 请提供参考。我确实在产品中使用的 UDP 之上编写了一个可靠的数据报协议。我记得关于 UDP 数据包最大大小的不确定性。无论如何,为了安全起见,我将其保持在 640 字节以下,并且从未遇到任何问题。好吧,除了一个网络驱动程序有一个“腐烂的数据包”问题,我必须修补。
    • 参见 RFC 768。UDP 长度字段为 16 位,允许数据报最长为 64K 字节(包括 8 字节标头)。如此大的数据报需要进行 IP 分片和重组,因此不推荐。但 NFS 传统上发送 8K 数据报。
    猜你喜欢
    • 2014-03-16
    • 2019-06-09
    • 2019-07-25
    • 1970-01-01
    • 2012-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多