recv() 跳过 UDP 数据包
recv() skipping UDP packets
我编写了简单的程序来处理传入的 UDP 数据包。我发送了 60000 个 UDP 数据包,这个程序正在丢失数据包。带宽约为 60-70 Mbit/s。
如果我并行运行 tcpdump,那么我会看到内核接收到所有包。我还尝试了 recvmsg 和 recvmmsg,结果相同。
程序源代码:
#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);
}
问题已解决。我对 tcpdump 的看法是错误的,并非所有数据包都传送到内核。另外我没有详细描述问题。程序在单核ARM处理器上运行,UDP数据包的有效载荷为256字节,所以CPU跟上数据流,结果内核UDP队列owerflows,我看到丢包。 iperf3 有 1448 字节的有效载荷,并且工作正常。如果我将 iperf3 有效载荷包减少到 256 字节,它也会开始丢弃数据包。
为了解决这个问题,我将有效负载增加到 512 字节,增加了 net.core.rmem_max、net.core.rmem_default 和 NIC 环形缓冲区,一切正常。
我编写了简单的程序来处理传入的 UDP 数据包。我发送了 60000 个 UDP 数据包,这个程序正在丢失数据包。带宽约为 60-70 Mbit/s。 如果我并行运行 tcpdump,那么我会看到内核接收到所有包。我还尝试了 recvmsg 和 recvmmsg,结果相同。
程序源代码:
#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);
}
问题已解决。我对 tcpdump 的看法是错误的,并非所有数据包都传送到内核。另外我没有详细描述问题。程序在单核ARM处理器上运行,UDP数据包的有效载荷为256字节,所以CPU跟上数据流,结果内核UDP队列owerflows,我看到丢包。 iperf3 有 1448 字节的有效载荷,并且工作正常。如果我将 iperf3 有效载荷包减少到 256 字节,它也会开始丢弃数据包。 为了解决这个问题,我将有效负载增加到 512 字节,增加了 net.core.rmem_max、net.core.rmem_default 和 NIC 环形缓冲区,一切正常。