【问题标题】:C: Performing an I/O operation and sending a signal result in select() continously being interrupted?C:执行 I/O 操作并发送信号导致 select() 不断被中断?
【发布时间】:2020-03-05 14:46:25
【问题描述】:

我正在尝试处理来自不同进程的套接字连接,同时异步处理来自alarm 函数的 SIGALRM。为了模拟和测试这一点,我使用了 Linux 命令nc 127.0.0.1 [port]kill -14 $(myprocess)。但是,当运行kill 命令后跟nc 命令时,select 会立即以类似方式的无限循环返回。包含select 语句的C 代码如下。

int main() {
    int port = 4555;
    int master_sockfd;
    bind_and_listen(&master_sockfd, port);
    signal(SIGALRM, handle_alarm);

    for (;;) {
        fd_set readfds;
        int max_fd = master_sockfd;
        FD_ZERO(&readfds);
        FD_SET(master_sockfd, &readfds);

        printf("waiting for master_sockfd to be set\n");

        int activity = select(max_fd + 1, &readfds, NULL, NULL, NULL);

        if ((activity < 0) && (errno != EINTR)) {
            perror("select() ");
            exit(EXIT_FAILURE);

        } else if (errno == EINTR) {
            perror("select() ");
            if (FD_ISSET(master_sockfd, &readfds)) {
                printf("Why is sockfd ready for I/O if select was interrupted with a signal?\n");
            }
            continue;

        } else if (FD_ISSET(master_sockfd, &readfds)) {
            printf("Reading from socket\n");
            // handle client
        }
    }
    return 0;
}

void handle_alarm() {
    printf("handling alarm\n");
}

然后,在执行kill -14 $(myprocess); nc 127.0.0.1 4555 输出如下:

select() : Interrupted system call
Why is sockfd ready for I/O if select was interrupted with a signal?
waiting for master_sockfd to be set
select() : Interrupted system call
Why is sockfd ready for I/O if select was interrupted with a signal?
waiting for master_sockfd to be set
select() : Interrupted system call
Why is sockfd ready for I/O if select was interrupted with a signal?
waiting for master_sockfd to be set
.
.
.

无限打印。

为什么会这样?

【问题讨论】:

    标签: c sockets select signals


    【解决方案1】:

    当 select() 失败时,您不能依赖其中的参数值。它们可能反映了某些东西、什么都没有或某种中间状态。在您的情况下,看起来 select() 根本没有更新 fdset;所以它们反映了你的初始值。这是有道理的;它被中断了,所以它从来没有写回它的结果。

    你的错误检测也不太对,应该是:

    if (activity < 0) {
        /* select failed */
        if (errno != EINTR) {
            /* handle non-eintr cases */
        } else {
            /* handle eintr case */
        }
    } else {
        /*select succeeded */
    }
    

    【讨论】:

      猜你喜欢
      • 2019-06-25
      • 2021-06-28
      • 1970-01-01
      • 2020-08-21
      • 2021-02-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多