原始套接字sendto()发送的一些数据包被丢弃,未在网络中显示。

3
socketFd_ = socket(AF_INET, SOCK_RAW, protoType);    
sentBytes = sendto(socketFd_, buf, len, 0, 
                  (struct sockaddr   *)&sa,sizeof(structsockaddr_in));
protoType = GRE

我正在发送1000个数据包到网络中。如果我的tx数据包速率为40,我可以在Wireshark中看到所有数据包。然而当我试图以100的速率发送时,其中一些数据包(3-4个)将无法到达网络,但sendto没有返回任何错误。我知道sendto只会将tx数据包放入队列中,并不能保证数据包在网络中的传递,那么我该从哪里获取内核中丢弃数据包的统计信息和丢包原因呢?我尝试将接口的txqueuelen增加到65000,但没有帮助。我该如何调试此问题?

我尝试使用以下代码检查发送缓冲区大小:getsockopt(socketFd_, SOL_SOCKET, SO_SNDBUF, &sendBuffSize, &buffLen);它显示了一个大的值,sendBuffSize = 124928,并且我观察到每当我的待处理缓冲区大小在系统调用sendto()之后达到2040时,它会丢弃数据包(sendto()在此处成功返回),我正在使用ioctl(socketFd_, SIOCOUTQ, &outstandingBytes)来检查未完成的sendto()缓冲区大小。我的问题是为什么sendto()没有返回任何错误?这是因为sendBuffSize比outstandingBytes大吗?有人可以帮我调试这个问题吗?谢谢。 - devesh
在 sendto 后再添加一个测试场景,如果我等待 outstandingBytes 达到零再次调用 sendto,那么系统中就不会有任何数据包丢失。 - devesh
1个回答

1

您说得对,sendto只会将txpacket放入队列中,不能保证传递。

根据IEEE文档关于sendto的说明:

成功调用sendto()并不保证消息的传递。返回值-1仅表示本地检测到的错误。

您需要通过ioctl()和getsockopt()执行一些自己的限制,就像您几乎已经做到的那样。我认为您不能期望网络堆栈为您完成所有工作。

类似以下内容:

sendMsgThrottled( msg Msg ) {
    ioctl(socketFd_, SIOCOUTQ, &outstandingBytes);  
    if ( outStandingBytes < limit )
          sendto(socketFd_, ..)
    else
          queueMsg();  /* Or delay */
}

我会通过将发送方和接收方放在同一台机器上进行测试,因为丢包可能不仅仅来自操作系统的网络层。

在每次 sendto 后调用系统调用 ioctl 会影响性能,但我关心的是当 outstandingBytes 达到 2040 时为什么会丢包,如何增加此限制。我的发送缓冲区大小为 124928,我使用 getsockopt() 的 SO_SNDBUF 选项获取此值。 - devesh
你发送的数据包大小是多少?发送速率是40个/秒吗?通常使用ioctl()不会对性能造成太大影响。 - don_q
数据包大小约为326字节,当我以每秒400个数据包的速率发送时,我观察到了这个问题。 从Wireshark中,我发现在150微秒内,我将向网络注入10个数据包。(一种小型突发,我将调用1毫秒定时器,定期按照速率注入数据包) - devesh
你把Naggle算法关掉了吗? - don_q
是的,你说得对,Naggle只适用于TCP,我道歉。UDP不能保证传输成功。你有零丢包的要求吗? - don_q
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接