Переключение между утверждениями, если пользователь что-то вводит: бесконечно и с таймаутом
Чтобы объяснить более четко, что я хочу сделать, я хочу, чтобы мой код проверял, вводит ли пользователь что-то (или если у другого файлового дескриптора, кроме 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
,