recv() 跳过 UDP 数据包

Posted

技术标签:

【中文标题】recv() 跳过 UDP 数据包【英文标题】:recv() skipping UDP packets 【发布时间】:2021-01-21 08:01:45 【问题描述】:

我编写了简单的程序来处理传入的 UDP 数据包。我发送了 60000 个 UDP 数据包,这个程序正在丢失数据包。带宽约为 60-70 Mbit/s。 如果我并行运行 tcpdump,那么我看到所有包都被内核接收了。我也尝试了 recvmsg 和 recvmsg ,结果相同。

程序源代码:

#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h> 
#include <signal.h>

#include <string.h>
#include <unistd.h>
sig_atomic_t exit_cond = 0;
int sock;
void signal_handler(int signum)

    exit_cond = 1;
    shutdown(sock,SHUT_RDWR);
    close(sock);


char buff[10240];
int main(int argc,char **argv)

    int len;
    unsigned long long overal;
    sock = socket(AF_INET,SOCK_DGRAM,0);
    signal(SIGTERM,signal_handler);
    signal(SIGINT,signal_handler);
    if(sock == -1)
    
        printf("Error in socket()\n");
        return -1;
    
    struct sockaddr_in rcv_addr;
    memset(&rcv_addr, 0, sizeof(rcv_addr)); 

    rcv_addr.sin_family    = AF_INET;
    rcv_addr.sin_addr.s_addr = INADDR_ANY; 
    rcv_addr.sin_port = htons(1024); 
    if(bind(sock, (const struct sockaddr *)&rcv_addr,sizeof(rcv_addr)) < 0)
     
        printf("Error in bind()\n");
        return -1;
    
    
    while(!exit_cond)
    
        
        len = recv(sock, (char *)buff, 10240,
                MSG_WAITALL);
        if(len > 0)
        
            overal++;
        
        
    
    printf("Overal: %lld\n",overal);    

【问题讨论】:

那么UDP 不可靠的。您甚至可以在接口和程序之间的途中丢弃数据包。发生这种情况的一个原因是您的程序根本不够快,无法处理所有传入的数据包。 我通常将 recvfrom 用于 UDP。我不认为我曾经在 UDP 上使用过 recv:仅在 TCP 上。 另一个建议:您检查if(len &gt; 0),这是正确的(至少您执行了一些检查),但您没有发现len&lt;0 (-1) 的情况。在这些情况下,打印errno(请参阅strerror 可以帮助了解是否发生了奇怪的事情 我并不是说这是系统性能问题,而是您的程序中的性能问题。您的程序是否足够快以处理所有收到的包裹?您显示的代码是您运行的实际代码吗?是 minimal reproducible example 为您完全复制了问题吗? 对了,变量overal的初始值是多少?请记住,未初始化的局部变量确实未初始化的,并且会有一个indeterminate(并且看似随机或垃圾)的值。也许如果你初始化它,你会得到更好的结果? 【参考方案1】:

问题解决了。我对 tcpdump 的看法是错误的,并非所有数据包都传递给内核。我也没有详细描述这个问题。程序在单核ARM处理器上运行,UDP数据包的有效载荷为256字节,因此CPU跟上数据流,结果内核UDP队列溢出,我看到数据包丢失。 iperf3 有 1448 字节的有效负载,并且工作正常。如果我将 iperf3 有效负载包减少到 256 字节,它也会开始丢弃数据包。 为了解决这个问题,我将有效负载增加到 512 字节,增加了 net.core.rmem_max、net.core.rmem_default 和 NIC 环形缓冲区,一切正常。

【讨论】:

以上是关于recv() 跳过 UDP 数据包的主要内容,如果未能解决你的问题,请参考以下文章

recv原理高阶版黏包解决方案基于UDP的socket通信

嵌入式开发之UDP 丢包--- UDP 丢包控制方法

UDP主要丢包原因及具体问题分析

如何在 linux C 中解除对 recv() 或 recvfrm() 函数的阻塞

recvfrom()的一次调用只能返回一个UDP包。此种说法正确吗?

粘包问题