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

问题描述 投票:1回答:1

我有一个处理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后,我得到Caught Signal,然后是accept: Interrupted system call。来自accept(2)的手册页

错误

...

EINTR系统调用被有效连接到达之前捕获的信号中断;见信号(7)。

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

下面我列出了每个案例的完整可用示例程序。

Example with 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);
}

Example with 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);
}
c sockets signals
1个回答
1
投票

在BSD和Linux上,signal()相当于sigaction()sa_flags设置为SA_RESTART。如果在sigaction()代码中设置该标志,它的行为与signal()代码相同。如果这不是你想要的,那么你必须只使用sigaction()

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

在BSD上,当调用信号处理程序时,信号处理不会被重置,并且在处理程序执行时阻止信号的其他实例被传递。此外,如果信号处理程序中断,某些阻塞系统调用会自动重启(参见signal(7))。 BSD语义等同于使用以下标志调用sigaction(2):

       sa.sa_flags = SA_RESTART;
© www.soinside.com 2019 - 2024. All rights reserved.