Search code examples
csocketsselect-function

Knowing which file-descriptors are ready after select() call in C


I'm new to socket programming and I've been introduced to the select() system call. My question is, lets say I'm writing a server in C (which I am attempting to do) and I want to use the select() call in my implementation for practice. I'm trying to write a server that receives information from a client, so my approach is to use select(), followed by read() and just output the information.

According to the documentation I've read select() returns the number of file descriptors in the input set which are ready for i/o. My question is, how do know which file descriptors in the original set are the ones that are ready for i/o? I can't seem to find this in my searches or examples I've looked at for the past while.

Let's say my code looks like the below:

int main() {
/* Create socket/server variables */
    int select_value;
    int this_socket;
    int maxfd;
    struct sockadder_in address; 
    fd_set allset;

    /* Bind the socket to a port */
    main_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (main_socket < 0) {
        perror("socket()");
        exit(1);
    }

    Connect(main_socket, (struct sockaddr *)&address, sizeof(address));

    /* Add the socket to the list of fds to be monitored */
    FD_ZERO(&allset);
    FD_SET(main_socket, &allset);

    fd_set read_ready = allset;
    fd_set write_ready = allset;

    while (1) {
        /* Listen for a connection */
        /* Accept a connection */
        select_value = Select(maxfd+1, &read_ready, &write_ready, NULL, NULL);
        if (select_value == -1) {
            perror("select()");
            exit(1);
        }
        else if(select_value > 0) {
            /* How to access i/o ready file descriptors
            now that we know there are some available? */
        }
    }
} 

Solution

  • One can do this using the FD_ISSET macro that is part of <sys/select.h>.

    When your select unblocks and a file descriptor is ready, you can test all of your file descriptors using the FD_ISSET macro in a simple loop. This can be translated to the following sample :

    for (i = 0; i < FD_SETSIZE; ++i) {
        if (FD_ISSET (i, &read_fd_set)) {
            if (i == bound_socket) {
                // A new client is waiting to be accepted
                new = accept(sock, (struct sockaddr *) &clientname, &size);
                // ...
                FD_SET (new, &active_fd_set);
            }
            else {
              // There is something to be read on the file descriptor.
              data = read_from_client_on(i);
            }
        }
    }
    

    Of course, this is just sample which is obviously lacking any error handling, which you should handle in your application.