csocketsnetwork-programmingposix-select

select() returns with no incoming connection


I'm writing a very simple server application just for the purpose of testing some code. After creating a socket and bind()ing it to my localhost and some port I'd like to use select() to know when an incoming connection arrives to the bound socket. After that the application should print the message up to a certain lenght and then exit().

My question is basically if I need to use listen() and accept() when I'm expecting only one connection (please remember this is just for testing). I believe these functions are not needed in this case and are only needed for accepting multiple incoming requests. Am I wrong?

With the above ideia in mind I wrote the following code

int main()
{
    int fd = TCPcreate(atoh("127.0.0.1"), 15000); /*my localhost address*/
    char *str = malloc(100);
    int a;
    fd_set rfds;

    FD_ZERO(&rfds);
    FD_SET(fd,&rfds);

    a = select(fd+1,&rfds,(fd_set*)NULL,(fd_set*)NULL,(struct timeval*)NULL);

//  printf("select returns %d\nfd = %d\n", a, fd);
//  printf("fd is set? %s\n", FD_ISSET(fd,&rfds) ? "yes" : "no");

    a = TCPrecv(fd, str, 100); /*receive at most 100B */

//  printf("%d\n", a);
    printf("%s\n", str);

    close(fd);
    exit(0);
}

TCPcreate()

int TCPcreate(unsigned long IP, unsigned short port)
{
    int fd;
    struct sockaddr_in address;

    fd = socket(AF_INET, SOCK_STREAM, 0);
    if(fd==-1)
    {
        return -1;
    }

    memset(&address, 0, sizeof(address));
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = htonl(IP);
    address.sin_port = htons(port);

    /* struct sockaddr_in is the same size as struct sockaddr */
    if(bind(fd, (struct sockaddr*)&address, sizeof(address))==-1)
    {
        return -2;
    }

    return fd;
}

atoh() simply returns its argument in host byte order.

What happens when I run the program is that select() doesn't block waiting for a connection. Instead, it immediately returns 1. If I uncomment the printf()s what I get is

select returns 1
fd = 3
is set? yes
-1
(blank line)

What am I missing here?...


Solution

  • If you look at the POSIX specification of select(), the file descriptors returned are ready for reading, writing, or have an error condition on them. This does not list 'a socket on which listen() would succeed' as one of the detectable conditions. So, you will need to use listen() and accept(); only after you've accepted the connection can you use select() on the descriptors.

    As Gonçalo Ribeiro notes, the specification for select() also says:

    If the socket is currently listening, then it shall be marked as readable if an incoming connection request has been received, and a call to the accept() function shall complete without blocking.

    That means you must have done a listen() on the bound socket, but you can wait on multiple sockets for incoming connections.