繁体   English   中英

从多个文件描述符异步接收UDP数据包

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM