gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 23:02:53 24 4
gpt4 key购买 nike

我正在尝试在系统调用 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。在 IDE QtCreator 中,我尝试调试。选择刚刚被打断然后返回收听。甚至没有达到条件“if (errno == EINTR)”。控制台中没有调试消息,系统日志中也没有。同时 SIGQUIT 工作正常:调用 sig_handler 并且也达到了条件“if (errno == EINTR)”。

如您所见,我尝试通过以下方式检查 SIGINT:使用来自信号处理程序的标志,以及来自选择

的结果

我试图在主题 Not able to catch SIGINT signal while using select() 中找到答案.但是找不到解决方案。这个问题我在其他WEB-resources遇到过,但是也没有解决办法。

SIGINT 信号从命令行接收:"kill -s 2 (PID)"

UPD 问题已解决。问题出在调试器中。在调试器下 SIGINT 无法正常工作。在没有调试器的情况下运行程序按预期工作正常。

最佳答案

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

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

  • 与其将 NULL 作为最后一个参数传递给 select,不如传递一个指向作为全局变量的 timeval 的指针。在您的信号处理程序中,将时间间隔设置为 0 秒。因此,如果在您调用 select 之前信号到达,select 将请求 0 超时并立即返回。

关于c++ - 使用 select() 时无法捕获 SIGINT 信号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27204444/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com