gpt4 book ai didi

c - sigaction 将 SIGINT 传递给系统调用,但不传递信号

转载 作者:行者123 更新时间:2023-12-02 07:06:59 27 4
gpt4 key购买 nike

我有一个循环处理 accept(2) 调用。我希望能够在将 SIGINT 发送到程序时执行一些清理操作。我的第一个想法是使用 signal 函数。

void signal_handler(int signal) {
printf("Caught signal\n");
}

int main() {
signal(SIGINT, &signal_handler);
// ...
int accept_fd = accept(sock, NULL, NULL);
if (accept_fd == -1) {
close(sock);
perror("accept");
return 1;
}
// ...
}

但是,这只是打印“捕获信号”,然后程序继续。

如果我修改 main 以使用 sigaction,程序将按预期工作。

int main() {
struct sigaction sa;
sa.sa_handler = &signal_handler;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
// ...
int accept_fd = accept(sock, NULL, NULL);
if (accept_fd == -1) {
close(sock);
perror("accept");
return 1;
}
// ...
}

发送 SIGINT 后,我收到捕获信号,然后收到接受:中断的系统调用。来自 accept(2)

的手册页

ERRORS

...

EINTR The system call was interrupted by a signal that was caught before a valid connection arrived; see signal(7).

我知道 sigaction 更现代,我应该使用它而不是 signal,但我很好奇为什么它提供了这种功能差异。

下面我为每种情况提供了一个完整的可用示例程序。

信号示例(2)

#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

#define BUFFER_SIZE 32

void signal_handler(int signal) {
printf("Caught signal\n");
}

int main() {
signal(SIGINT, &signal_handler);
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
struct addrinfo *addr_info;
int info_result = getaddrinfo("localhost", "8080", &hints, &addr_info);
if (info_result != 0) {
printf("Getting address failed\n");
return 1;
}
int sock = socket(addr_info->ai_family, addr_info->ai_socktype, addr_info->ai_protocol);
if (sock == -1) {
printf("Socket Failed\n");
return 1;
}
int bind_result = bind(sock, addr_info->ai_addr, addr_info->ai_addrlen);
if (bind_result == -1) {
close(sock);
printf("Bind Failed\n");
return 1;
}
int listen_result = listen(sock, 8);
if (listen_result == -1) {
close(sock);
printf("Listen Failed\n");
return 1;
}
printf("Waiting...\n");
int accept_fd = accept(sock, NULL, NULL);
if (accept_fd == -1) {
close(sock);
perror("accept");
return 1;
}
printf("Got fd %d\n", accept_fd);
char *buffer = malloc(BUFFER_SIZE * sizeof(char));
int n;
while ((n = read(accept_fd, buffer, BUFFER_SIZE)) > 0) {
printf("%.*s\n", n, buffer);
}
close(sock);
}

sigaction(2) 示例

#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

#define BUFFER_SIZE 32

void signal_handler(int signal) {
printf("Caught signal\n");
}

int main() {
struct sigaction sa;
sa.sa_handler = &signal_handler;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
struct addrinfo *addr_info;
int info_result = getaddrinfo("localhost", "8080", &hints, &addr_info);
if (info_result != 0) {
printf("Getting address failed\n");
return 1;
}
int sock = socket(addr_info->ai_family, addr_info->ai_socktype, addr_info->ai_protocol);
if (sock == -1) {
printf("Socket Failed\n");
return 1;
}
int bind_result = bind(sock, addr_info->ai_addr, addr_info->ai_addrlen);
if (bind_result == -1) {
close(sock);
printf("Bind Failed\n");
return 1;
}
int listen_result = listen(sock, 8);
if (listen_result == -1) {
close(sock);
printf("Listen Failed\n");
return 1;
}
printf("Waiting...\n");
int accept_fd = accept(sock, NULL, NULL);
if (accept_fd == -1) {
close(sock);
perror("accept");
return 1;
}
printf("Got fd %d\n", accept_fd);
char *buffer = malloc(BUFFER_SIZE * sizeof(char));
int n;
while ((n = read(accept_fd, buffer, BUFFER_SIZE)) > 0) {
printf("%.*s\n", n, buffer);
}
close(sock);
}

最佳答案

在 BSD 和 Linux 上,signal() 相当于将 sa_flags 设置为 SA_RESTARTsigaction() 。如果您在 sigaction() 代码中设置该标志,它将与您的 signal() 代码表现相同。如果这不是您想要的,那么您只能使用 sigaction()

来自 Linux man page 的注释(也适用于 BSD 和 OS X):

On BSD, when a signal handler is invoked, the signal disposition is not reset, and further instances of the signal are blocked from being delivered while the handler is executing. Furthermore, certain blocking system calls are automatically restarted if interrupted by a signal handler (see signal(7)). The BSD semantics are equivalent to calling sigaction(2) with the following flags:

       sa.sa_flags = SA_RESTART;

关于c - sigaction 将 SIGINT 传递给系统调用,但不传递信号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52231219/

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