qudp socket信号不触发_信号 - Linux Signal - 网络编程的相关信号

SIGHUP

当挂起进程的控制终端时,SIGHUP信号将被触发。对于没有控制终端的网络后台程序而言,它们通常利用SIGHUP信号来强制服务器重读配置文件。

SIGPIPE

默认情况下,往一个读端关闭的管道或socket连接中写数据将引发SIGPIPE信号。我们需要在代码中捕获并处理该信号,或者至少忽略它,因为程序接收到SIGPIPE信号的默认行为是结束进程,而我们不希望因为错误的写操作而导致程序退出。引起SIGPIPE信号的写操作将设置errno为EPIPE。我们可以使用send函数的MSG_NOSIGNAL标志来禁止写操作触发SIGPIPE信号。在这种情况下,我们应该使用send函数反馈的errno值来判断管道或者socket连接的读端是否已经关闭。此外,我们也可以利用I/O复用系统调用来检查管道和SOCKET连接的读段是否已经关闭。以poll为例,当管道的读端关闭时,写端文件描述符上的POLLHUP事件将被触发;当sock连接对方关闭时,socket上的POLLRDHUP事件将被触发。

SIGURG

在Linxu环境下,内核通知应用程序带外数据到达主要有两种方法:一种是利用I/O复用技术,select等系统调用在接收到带外数据时将返回,并向应用程序报告socket上的异常事件;另外一种方法就是使用SIGURG信号,示例代码如下:

#include #include #include #include #include #include #include #include #include #include #include #define BUF_SIZE 1024static int connfd;/*SIGURG信号的处理函数*/void sig_urg(int sig){    int save_errno = errno;    char buf[BUF_SIZE];    char oobdata;    int atmark, s;    for (;;) {        atmark = sockatmark(connfd);        if (atmark == -1) {            perror("sockatmark");            break;        }        if (atmark)            break;        s = read(connfd, buf, BUF_SIZE);        if (s == -1)            perror("read");        if (s <= 0)            break;    }    if (atmark == 1) {        if (recv(connfd, &oobdata, 1, MSG_OOB) == -1) {            perror("recv");        }        printf("OOB DATA IS %c", oobdata);    }    errno = save_errno;}void addsig(int sig, void(*sig_handler)(int)){    struct sigaction sa;    memset(&sa, '0', sizeof(sa));    sa.sa_handler = sig_handler;    sa.sa_flags |= SA_RESTART;    sigfillset(&sa.sa_mask);    assert(sigaction(sig, &sa, NULL) != -1);}int main(int argc, char const *argv[]){    if(argc <= 2){        printf("usage: %s ip_address port_number", basename(argv[0]));        return 1;    }    const char* ip = argv[1];    int port = atoi(argv[2]);    struct sockaddr_in address;    bzero(&address, sizeof(address));    address.sin_family = AF_INET;    inet_pton(AF_INET, ip, &address.sin_addr);    address.sin_port = htons(port);    int sock = socket(PF_INET, SOCK_STREAM, 0);    assert(sock > 0);    int ret = bind(sock, (struct sockaddr*)&address, sizeof(address));    assert(ret != -1);    ret = listen(sock, 5);    assert(ret != -1);    struct sockaddr_in client;    socklen_t client_addrlength = sizeof(client);    connfd = accept(sock, (struct sockaddr*)&client, &client_addrlength);    if(connfd < 0){        printf("errno is %d - %s", errno, strerror(errno));    }    else{        addsig(SIGURG, sig_urg);        /*使用SIGURG之前,我们必须设置socket的宿主进程或进程组*/        fcntl(connfd, F_SETOWN, getpid());        char buffer[BUF_SIZE];        while (1){            memset(buffer, '0', BUF_SIZE);            ret = recv(connfd, buffer, BUF_SIZE-1, 0);            if(ret <= 0){                break;            }            printf("got %d bytes of normal data '%s'", ret, buffer);        }        close(connfd);    }    close(sock);    return 0;}

这里需要注意的是即使应用程序得到了有带外数据需要接收的通知,还需要知道带外数据在数据流中的位置,才能准确接收到带外数据。可以利用sockatmark来判断sockfd是否处于带外标记,即下一个被读取到的数据是否是带外数据。如果是返回1, 此时我们就可以利用带MSG_OOB标志的recv调用来接收带外数据。如果不是,则返回0。

a9c128db7525ef385209c6b54ddda420.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值