сигнал тревоги не срабатывает слишком рано - PullRequest
0 голосов
/ 02 октября 2018

У меня есть signal, где я устанавливаю обработчик обратного вызова, а затем в своей функции я вызываю alarm(1), чтобы моя программа истекла через 1 секунду.По истечении времени ожидания я бы хотел, чтобы он повторил тот же самый блокирующий вызов recvfrom() до набора MAX_ATTEMPTS, равного 5.

Проблема:

Это только повторные попытки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 раз перед закрытием соединения (это реализация Go Back N с использованием UDP)

UPDATE

Я решил проблему путем переустановкиsignal: signal(SIGALRM, timeout_hdler); в моем обработчике.Но почему это так?Я делаю это неправильно?

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

1 Ответ

0 голосов
/ 02 октября 2018

Семантика signal зависит от ОС и libc.Но согласно вашему выводу в вашем конкретном случае обработчики сигнала сбрасываются до значения по умолчанию после первого вызова функции обработчика.По умолчанию в этом случае происходит выход из программы, если сигнал запускается снова, т. Е. Alarm clock, и выход, который вы видите на выходе.

С документация по сигналу в Linux :

Единственное переносимое использование signal () - установить расположение сигнала в SIG_DFL или SIG_IGN.....
В исходных системах UNIX, когда обработчик, который был установлен с использованием signal (), был вызван доставкой сигнала, расположение сигнала будет сброшено на SIG_DFL , исистема не блокировала доставку дальнейших экземпляров сигнала....

Другими словами: не используйте signal.Вместо этого вы должны использовать sigaction:

POSIX.1 решил проблему переносимости, указав sigaction (2), которая обеспечивает явный контроль семантики при вызове обработчика сигнала;используйте этот интерфейс вместо signal ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...