我们在Centos 6上有一个应用程序,它调用recvmmsg()多播地址一次读取1024个UDP数据包.当我们在同一个盒子上运行这个应用程序的多个实例(都收听相同的流量)时,有时这个调用将阻塞多秒,尽管套接字是非阻塞的,并且传入MSG_DONTWAIT.它在所有其他情况下都能正常工作,但在高负载(50MB/s)下会冻结.当应用程序阻塞时,我们落后于UDP流量而无法恢复.使用RR调度程序作为高优先级运行该进程以避免来自其他进程的干扰.我们尝试切换到recvfrom(),并recv()在for循环也具有相同的结果.
我们在内核源代码中可以看到的唯一可以阻止它的是spin_lock_irqsave()队列锁定__skb_try_recv_datagram().但我不知道在什么情况下会出现问题,或者为了防止阻塞该怎么做,或者这是否真的是问题.
我不确定下一步该在哪里,所以任何指针都会受到赞赏.
创建了一个非常简单的程序,可以在我们看到的一个服务器上复制它(没有粘贴接口检索功能,但这里不应该相关,请告诉我你是否需要它).
recv()示例:
int main(){
int fd = socket(AF_INET,SOCK_DGRAM,0);
int flags = fcntl(fd,F_GETFL,0);
fcntl(fd,F_SETFL, flags | O_NONBLOCK);
int reuse = 1;
setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char*)&reuse,sizeof(reuse));
struct sockaddr_in sockaddr;
sockaddr.sin_port = htons(4755);
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(fd,(struct sockaddr*)&sockaddr,sizeof(sockaddr)) < 0){
printf("Failed to bind.\n");
return 1;
}
in_addr_t interface;
if(!getInterface("192.168.15.255",&interface)){
printf("Failed to get interface.\n");
return 1;
}
struct ip_mreq imr;
memset(&imr,0,sizeof(imr));
imr.imr_multiaddr.s_addr = inet_addr("239.255.61.255");
imr.imr_interface.s_addr = interface;
if(!IN_MULTICAST(htonl(imr.imr_multiaddr.s_addr))){ …Run Code Online (Sandbox Code Playgroud)