Search code examples
cmultithreadingsocketstcpposix-select

select() on TCP socket works only the first loop


void async_socket_rcv(int clientfd);

int main(int argc, char *argv[])
{
    //Configure buffer to output immediately
    setvbuf(stdout, 0, _IONBF, 0);

    //Mysql version
    printf("MySQL client version: %s\n", mysql_get_client_info());

    //Initialize the FDs for the sockets
    int socketfd, clientfd;

    //Initialize the list of FDs to monitor for input
    fd_set fd_monitor;
    int select_res;
    FD_ZERO(&fd_monitor);

    struct timeval select_timeout;
    select_timeout.tv_sec = 3;
    select_timeout.tv_usec = 0;


    //Initialize the thread id
    pthread_t thread;

    ...

    //Create the listen socket
    socketfd = create_inet_server_socket("0.0.0.0", "5671", LIBSOCKET_TCP, LIBSOCKET_IPv4, 0);

    if(socketfd < 0){
        printf("Error creating listen socket!");
        return -1;
    }else{
        printf("Listening...");
    }

    FD_SET(socketfd, &fd_monitor);
    //FD_SET(STDIN_FILENO, &fd_monitor);

    while(1)
    {
        select_res = select(sizeof(fd_monitor) * 8, &fd_monitor, NULL, NULL, &select_timeout);

        if(FD_ISSET(socketfd, &fd_monitor))
        {
            clientfd = accept_inet_stream_socket(socketfd,0,0,0,0,0,0);
            pthread_create(&thread, NULL, async_socket_rcv, clientfd);
        }
        select_timeout.tv_sec = 3;
        select_timeout.tv_usec = 0;
    }

    return 0;

}

I am trying to use the select() function to call a function when a client connects without having to block on the accept() function. I need to be able to accept stdin without interrupting the server.

My code above works, but only once. When I step through the code, i can see that select_res is 1 only if I connect to the server within the first iteration of select(). After that, nothing happens.

What am I doing wrong?


Solution

  • select alters the passed in fd_sets, setting the descriptors that have activity and unsetting those that don't. Since you don't reset fd_monitor in your loop, you used the altered fd_set.

    Move the FD_ZERO and FD_SET calls to the beginning of the loop.