[英]Receiving UDP Packets Asynchronously From Multiple File Descriptors
我對使用fcntl和sigaction異步接收UDP數據包有疑問。 在我的程序中,我有兩個要監視的UDP流量源。 我已經為通信設置了兩個套接字,並使用本教程設置了當接收到UDP數據包時觸發文件簽名的文件描述符。
這僅適用於一個源,但是當我添加另一個源時,只要其中一個文件描述符接收到數據包,它將僅觸發一個處理程序。
這是演示該行為的簡短程序:
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int done;
int a_fd;
int b_fd;
int recv_dgram(int fd, char* dgram, int size)
{
struct sockaddr_in addr;
int fromlen = sizeof(addr);
return recvfrom(fd, dgram, size, 0, (struct sockaddr*)&addr, (socklen_t*)&fromlen);
}
void a_handler(int signum)
{
char dgram[256];
int size = recv_dgram(a_fd, dgram, 256);
printf("a recieve size: %d\n", size);
}
void b_handler(int signum)
{
char dgram[256];
int size = recv_dgram(b_fd, dgram, 256);
printf("b recieve size: %d\n", size);
}
void sig_handle(int signum)
{
done = 1;
}
int init_fd(int port, const char* group, const char* interface)
{
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if(fd < 0) {
return -1;
}
int reuse = 1;
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) < 0) {
close(fd);
return -1;
}
if(fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
close(fd);
return -1;
}
struct sockaddr_in addr;
memset((char*)&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if(bind(fd, (struct sockaddr*)&addr, sizeof(addr))) {
close(fd);
return -1;
}
struct ip_mreq mcast_group;
mcast_group.imr_multiaddr.s_addr = inet_addr(group);
mcast_group.imr_interface.s_addr = inet_addr(interface);
if(setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mcast_group, sizeof(mcast_group))) {
close(fd);
return -1;
}
return fd;
}
int main(int argc, const char* argv[])
{
done = 0;
signal(SIGINT, sig_handle);
signal(SIGTERM, sig_handle);
// make sockets and sigactions
a_fd = init_fd([a port], [a multicast group], [a interface]);
if(a_fd < 0) {
return -1;
}
pid_t pid = getpid();
int a_flags = fcntl(a_fd, F_GETFL);
fcntl(a_fd, F_SETFL, a_flags | O_ASYNC);
struct sigaction a_sa;
a_sa.sa_flags = 0;
a_sa.sa_handler = a_handler;
sigemptyset(&a_sa.sa_mask);
sigaction(SIGIO, &a_sa, NULL);
fcntl(a_fd, F_SETOWN, pid);
fcntl(a_fd, F_SETSIG, SIGIO);
b_fd = init_fd([b port], [b multicast group], [b interface]);
if(b_fd < 0) {
close(a_fd);
return -1;
}
int b_flags = fcntl(b_fd, F_GETFL);
fcntl(b_fd, F_SETFL, b_flags | O_ASYNC);
struct sigaction b_sa;
b_sa.sa_flags = 0;
b_sa.sa_handler = b_handler;
sigemptyset(&b_sa.sa_mask);
sigaction(SIGIO, &b_sa, NULL);
fcntl(b_fd, F_SETOWN, pid);
fcntl(b_fd, F_SETSIG, SIGIO);
printf("start\n");
while(!done) { pause(); }
printf("done\n");
close(a_fd);
close(b_fd);
return 0;
}
我可以使用以下代碼進行編譯(您也可以使用gcc進行編譯):
g ++ -c test.cpp
g ++ -o測試test.o
我在Ubuntu 12.04 LTS上使用g ++ 4.6.3。
當我使用兩個UDP數據源運行該程序時,如果兩個文件描述符都有可用的數據包,則會觸發b_handler。 因此,每當a_handler應收到一個數據包時,它將打印“ b收到的大小:-1”。 a_handler永遠不會被調用。
我懷疑這是因為getpid()將為它們兩個返回相同的值,所以sigaction處理程序之一將被覆蓋。
有什么辦法可以讓這兩個處理程序彼此獨立地觸發?
謝謝您的幫助。
使用兩個不同的信號,例如SIGIO和SIGUSR1。
fcntl(descriptor, SETSIG, signal_desired);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.