Переключение между утверждениями, если пользователь что-то вводит: бесконечно и с таймаутом

Чтобы объяснить более четко, что я хочу сделать, я хочу, чтобы мой код проверял, вводит ли пользователь что-то (или если у другого файлового дескриптора, кроме 0, есть данные для чтения) каждые (скажем,) 2,5 секунды и так до тех пор, пока программа не остановится.

Если пользователь вводит что-то, простой printf() уведомит его, а затем программа снова проверит, вводит ли пользователь что-либо в течение следующих 2,5 секунд.

В противном случае следует просто напечатать, что время истекло, а затем снова проверить ввод пользователя в течение следующих 2,5 секунд.

А вот фрагмент кода, который я украл из Руководства Beej по сетевому программированию и изменил, чтобы (попытаться) выполнить мои требования:

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#define STDIN 0  // file descriptor for standard input

int main(void){
    struct timeval tv;
    fd_set readfds;

    FD_ZERO(&readfds);
    FD_SET(STDIN, &readfds);

    tv.tv_sec = 2;
    tv.tv_usec = 500000;

    while(1){
        select(STDIN+1, &readfds, NULL, NULL, &tv);

        if (FD_ISSET(STDIN, &readfds)){
            printf("A key was pressed!\n");
            tv.tv_sec = 2;
            tv.tv_usec = 500000;

        }else{
            printf("Timed out.\n");
            tv.tv_sec = 2;
            tv.tv_usec = 500000;

        }

    }
    return 0;
}

Пока я не нажимаю любую клавишу, все работает нормально и выдает "Timed out". каждые 2,5 секунды. Но если я что-то ввожу, кажется, что пользователь игнорирует ввод и продолжает печатать "Timed out".

С другой стороны, если я объявлю fd_set и struct timeval внутри бесконечного цикла, когда я что-то ввожу, это печатает бесконечно, что клавиша была нажата, как будто она игнорирует тайм-аут.

Я понятия не имею, почему такой простой код не работает. Я предполагаю, что упускаю из виду некоторые дескрипторы файлов, о которых я не знаю.

1 ответ

Потому что вы должны сбросить -> FD_ZERO(&readfds) ваш readfds и добавьте дескриптор файла -> FD_SET(STDIN, &readfds) каждый раз select возвращается, поскольку по тайм-ауту дескриптор файла удаляется из набора

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#define STDIN 0  // file descriptor for standard input

int main(void){
    struct timeval tv;
    fd_set readfds;

    while (1) {
        int count; /* how many descriptors are contained in the set. */

        FD_ZERO(&readfds);
        FD_SET(STDIN, &readfds);

        tv.tv_sec = 2;
        tv.tv_usec = 500000;

        count = select(STDIN + 1, &readfds, NULL, NULL, &tv);
        if ((count > 0) && (FD_ISSET(STDIN, &readfds) != 0)) {
            printf("A key was pressed!\n");
        } else if (count == -1)
            /* check for the error here */
        } else {
            printf("Timed out.\n");
        }
    }
    return 0;
}

как вы видите, вы также должны проверить возвращаемое значение из select, чтобы проверить наличие ошибки, в случае ошибки, затем проверьте errno чтобы увидеть, что произошло, а затем вы проверите его, дескриптор файла, который вас интересует, содержится в readfds,

Другие вопросы по тегам