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

时间:2018-09-08 01:25:35

标签: c sockets signals

我有一个处理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系统调用被有效连接到达之前捕获的信号中断;参见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);
}

1 个答案:

答案 0 :(得分: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;