Switching between statements if the user inputs something: infinitely and with a timeout

76 views Asked by At

To explain more clearly what I want to do, I want my code to check if the user inputs something (or if another file descriptor than 0 has data to read) every (let's say) 2.5 seconds and so until the program stops.

If the user inputs something, a simple printf() will notify him and then the program will check again if the user inputs something in the next 2,5 seconds.

Else, it should simply print that the time ran out and then check again for the user input in the next 2,5 seconds.

And here's the code snippet I stole from Beej's Guide to Network Programming and modified to (try to) fulfill my requirements:

#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;
}

As long I don't press any key, this works fine and prints "Timed out." every 2,5 seconds. But if I enter something, it seems to ignore the user input and keeps printing "Timed out.".

On the other hand, if I declare the fd_set and the struct timeval inside the infinite loop, once I enter something, this prints infinitely that a key has been pressed as if it ignores the timeout.

I have no idea why such a simple code doesn't work. I guess I'm missing some point about file descriptors I don't know about.

1

There are 1 answers

2
Iharob Al Asimi On

Because you should reset -> FD_ZERO(&readfds) your readfds and add the file desciptor -> FD_SET(STDIN, &readfds) every time select returns, since on timeout the file descriptor is removed from the set

#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;
}

as you see you should also check the return value from select, to check for an error, in case of an error, then check errno to see what happened, and then you check it the file descritor you're interested in is contained in readfds.