使用select()时无法捕获SIGINT信号

3

我正在尝试在系统调用select中处理信号。

问题:我有一个带有select调用的工作循环。select等待套接字描述符准备就绪。 需要通过SIGINT或SIGQUIT中断循环,并正确关闭资源并退出程序。 以下是代码:

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <error.h>
#include <errno.h>
#include <signal.h>
#include <syslog.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netinet/in.h>


bool bBreakJob = false;

void sig_handler(int sig)
{
    switch(sig)
    {
    case SIGHUP:
        //rneed to reload config
        break;
    case SIGINT:
        printf("SIGINT \n");
        bBreakJob = true;
        openlog("mydaemon", LOG_PID | LOG_CONS, LOG_DAEMON);
        syslog(LOG_INFO, "Catched SIGINT");
        closelog();
        break;
    case SIGQUIT:
        printf("SIGQUIT \n");
        openlog("mydaemon", LOG_PID | LOG_CONS, LOG_DAEMON);
        syslog(LOG_INFO, "Catched SIGQUIT");
        bBreakJob = true;
        break;
    case SIGPIPE:
        printf("SIGPIPE \n");
        break;
    }
}

int main(int argc, char** argv)
{
    struct sigaction act, oact;
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGINT);
    sigaddset(&set, SIGHUP);
    sigaddset(&set, SIGPIPE);
    sigaddset(&set, SIGQUIT);
    sigprocmask(SIG_UNBLOCK, &set, NULL);
    act.sa_mask = set;
    act.sa_handler = sig_handler;
    act.sa_flags = 0;
    sigaction(SIGINT, &act, NULL);
    sigaction(SIGHUP, &act, NULL);
    sigaction(SIGPIPE, &act, NULL);
    sigaction(SIGQUIT, &act, NULL);

    int fds[0], res, fmax;
    fd_set wset;
    fd_set rset;

    //next line code to open socket 
    int listen_socket = socket(AF_INET, SOCK_STREAM, 0); 
    int iFlags = fcntl(listen_socket, F_GETFL);
    iFlags |= O_NONBLOCK;
    fcntl(listen_socket, F_SETFL, iFlags);
    struct sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = htonl(INADDR_ANY);
    sin.sin_port = htons(4000);
    bind(listen_socket, (struct sockaddr *)&sin, sizeof(sin));
    listen(listen_socket, 20);

    fds[0] = listen_socket;
    FD_ZERO(&wset);
    FD_SET(fds[0], &wset);
    fmax = fds[0] + 1;
    while (FD_ISSET(fds[0], &wset))
    {
        rset = wset;
        res = select(fmax, &rset, NULL, NULL, NULL);
        if (res < 0)
        {
            if (errno == EINTR)
            {   //debug message  
                printf("Loop broken by select's result EINTR");
                break;
            } else
            {
                printf("select(...) fails in listed loop. errno %d (%s)", errno, strerror(errno));
                exit(1);
            }

        }
        else if (res == 0)
        {
          //if timeout is handled
        }
        else if (res > 0)
        {
            if (FD_ISSET(fds[0], &rset))
            {
                //Handle socket input 
            }
        }
        if(bBreakJob)
        {
          printf("Loop broken by signal handler");
          break; 
        }
    } //while( 1 );
    FD_CLR(fds[0], &wset);
    if(bBreakJob)
    { //debug message 
      printf("signal SIGINT is handled ");
    }

}

SIGINT信号无法到达sig_handler。我尝试在QtCreator IDE中进行调试。选择被中断,然后返回到监听。即使是条件“if(errno == EINTR)”也没有到达。控制台和系统日志中也没有调试消息。而同时SIGQUIT工作得很好:sig_handler被调用,并且条件“if(errno == EINTR)”也被满足了。
正如您所看到的,我尝试以两种方式检查SIGINT:从信号处理程序的标志和从select的结果。
我曾试图在Not able to catch SIGINT signal while using select()主题中找到答案。但是无法找到解决方案。我在其他WEB资源中遇到了这个问题,但是也没有解决方案。
SIGINT信号是通过命令行发送的:"kill -s 2 (PID)" 更新:问题已解决。问题在于调试器。在调试器下,SIGINT无法正常工作。在没有调试器的情况下运行程序可以正常工作。

2
这里有太多的编译错误了(http://coliru.stacked-crooked.com/a/6aaf5243e944e985)。这是你真正的代码吗? - n. m.
@n.m. 你说C语言没有bool类型是什么意思?这段代码只是缺少了 #include <stdbool.h> - hyde
1
如果你在写C++代码,请使用C++标签而不是C标签来提问。 - n. m.
重要的是C/C++吗?好的,那我会更准确一些。 - Vitaly Zadunaisky
1
是的,这很重要。请更准确些。 - n. m.
显示剩余5条评论
1个回答

1

选择器和信号的交互比较棘手,因为信号可能会在调用选择器之前立即到达。以下是两种从信号处理程序中唤醒选择循环的方法:

  • "自己的管道技巧":创建一个管道并将读端添加到您的选择读取集中。从信号处理程序中,向此管道的写端写入一个字节,它将使选择器立即返回(因为输入已准备好)。

  • 而不是将NULL作为select的最后一个参数传递,请传递指向全局变量的timeval的指针。在信号处理程序内,将timeval设置为0秒。因此,如果信号在调用选择器之前到达,则选择器将要求0超时并立即返回。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接