【问题标题】:signal alarm fails too soon信号报警过早失效
【发布时间】:2018-10-02 03:58:52
【问题描述】:

我有一个signal,我在其中设置了一个回调处理程序,然后在我的函数中调用alarm(1),这样我的程序将在1 秒后超时。超时后,我希望它重试相同的阻塞调用recvfrom(),直到设置为 5 的MAX_ATTEMPTS

问题:

在退出程序之前只重试 2 次。知道可能出了什么问题吗?

/* declate signal for setting alarm */
signal(SIGALRM, timeout_hdler);
int attempts = 0;

while(1) {
    if(attempts > MAX_ATTEMPTS) {
        printf("Connection is not working, EXITING program");
        s.curr_state = CLOSED;
        /* we assume connection is failing so we shut down */
        exit(-1);
    }

    if (s.curr_state == CLOSED) {

        printf("Sending SYN_packet with seqnum: %d...\n", SYN_packet->seqnum);

        if (sendto(sockfd, SYN_packet, sizeof(SYN_packet), 0, server, socklen) == -1) {
            perror("Sendto error");
            exit(-1);
        }

        s.curr_state = SYN_SENT;

        printf("Current state SYN_SENT: %d\n", s.curr_state);
    }

    if (s.curr_state == SYN_SENT) {



        alarm(1);
        attempts++;
        printf("\nAttempt number: %d\n", attempts);
        printf("Waiting for SYNACK_packet...\n");

        if (recvfrom(
                sockfd, SYNACK_packet, sizeof(*SYNACK_packet), 0, (struct sockaddr *) &server, &socklen) == -1)
        {
            if (errno != EINTR) {
                perror("Recvfrom SYNACK_packet error\n");
                s.curr_state = CLOSED;
                exit(-1);
            }
        }

        if ((SYNACK_packet->type == SYNACK) && (validate_packet(SYNACK_packet) == 1)) {

            printf("SYNACK_packet received\n");

            s.address = *(struct sockaddr *) &server;
            s.sock_len = socklen;
            s.curr_state = ESTABLISHED;
            s.seq_num = SYNACK_packet->seqnum;
            printf("Current state ESTABLISHED: %d\n", s.curr_state);
            return sockfd;
        }
    }
}

处理程序(除了打印什么都不做):

void timeout_hdler(int signum) {
    printf("TIMEOUT has occured with signum: %d", signum);
}

这是我控制台中的输出(来自printf 语句):

In Connect() with socket: 4, server: 2, socklen: 16
Sending SYN_packet with seqnum: 67...
Current state SYN_SENT: 1

Attempt number: 1
Waiting for SYNACK_packet...
TIMEOUT has occured with signum: 14
Attempt number: 2
Waiting for SYNACK_packet...
Alarm clock

为什么只尝试了 2 次就退出程序?理想情况下,我希望它在关闭连接之前重试 5 次(这是使用 UDP 的 Go Back N 实现)

更新

我通过在我的处理程序中重新安装 signal: signal(SIGALRM, timeout_hdler); 解决了这个问题。但这是为什么呢?我做错了吗?

void timeout_hdler(int signum) {
    printf("TIMEOUT has occured with signum: %d", signum);
    signal(SIGALRM, timeout_hdler);
}

【问题讨论】:

标签: c udp signals go-back-n


【解决方案1】:

signal 的语义取决于操作系统和 libc。但是根据您在特定情况下的输出,信号处理程序处理程序在第一次调用处理程序函数后重置为默认值。如果再次触发信号,则默认值会导致程序退出,即 Alarm clock 并退出您在输出中看到的内容。

来自the documentation of signal in Linux

signal() 的唯一可移植用途是将信号的处置设置为 SIG_DFL 或 SIG_IGN。 ....
在最初的 UNIX 系统中,当一个处理程序被建立 使用 signal() 被传递的信号调用,信号的处置将重置为 SIG_DFL,并且系统没有 阻止信号的进一步实例的传递。 ...

换句话说:不要使用signal。相反,您应该使用sigaction:

POSIX.1 通过指定 sigaction(2) 解决了可移植性问题,它 当信号处理程序运行时,提供对语义的显式控制 被调用;使用该接口而不是 signal()。

【讨论】:

  • sigaction 通话愉快。它比仅使用 signal 更复杂,想知道我是否可以在处理程序中仅实例化信号...
  • @Cyzanfar:在调用信号处理程序之前,处理程序被重置为默认值,这意味着在重新建立处理程序之前另一个 ALARM 将导致程序退出。不过,这很可能会影响您的具体情况。请注意,您也可以使用 SO_SNDTIMEO 和 SO_RCVTIMEO 完全不使用信号处理程序。
  • 有道理我会尝试的。感谢@Steffen 的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多