Search code examples
ctcpclientposix-select

TCP client socket, doesn't block on select()



The following code is a test program wriiten to understand the behaviour of select() call in a TCP client program.
What I observe is that the select is not blocking, instead the program is blocking on recv(). The output is as follows:

Wait on select.
Wait on recv.
...

My question is why the select() returns a success? Ideally it should be blocking on the select() instead of recv().
The TCP server is sending a character string of 15 bytes once in 3 seconds.

int clientfd = -1;
int dummyfd = -1;
int maxfd = -1;
struct sockaddr_in server_addr;

char recv_buf[100] = {0};
int msg_len = 0;
int bytes_recv = 0;
fd_set readfd;
int retval = 0;


/* Open the socket and a dummy socket */.
clientfd = socket(AF_INET, SOCK_STREAM, 0);
dummyfd = socket(AF_INET, SOCK_STREAM, 0);
if(-1 == clientfd || -1 == dummyfd)
{
    perror("socket error: ");
    exit(1);
}
printf("Socket opened : %d\n", clientfd);

server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(10000);
//server_addr.sin_addr.s_addr = INADDR_ANY;
inet_aton("127.0.0.1", &(server_addr.sin_addr));
memset(&(server_addr.sin_zero), 0, 8);

/* Connect to server */
if(connect(clientfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)))
{
    perror("connect error: ");
    exit(1);
}
printf("Connect Success\n");
maxfd = (clientfd > dummyfd) ? (clientfd + 1) : (dummyfd + 1);
while(1)
{
    FD_ZERO(&readfd);
    FD_SET(clientfd, &readfd);
    FD_SET(dummyfd, &readfd);
    printf("Wait on select\n");
    retval = select(maxfd , &readfd, NULL, NULL, NULL);
    if(retval <= 0)
    {
        printf("select failed\n");
    }
    else
    {
            printf("Wait on recv\n");
            /* ... The process waits here ... */
            bytes_recv = recv(clientfd, recv_buf, 100, 0);
            printf("%d: Bytes recv = %d\t%s\n", retval, bytes_recv, recv_buf);
            memset(recv_buf, 0 ,100);
    }
}

close(clientfd);
return 0;
}

Edit: Without dummyfd, the program works as intended. A follow up question:
When the server is closed abruptly, how to detect this using select()?
Can the program be modified so that is blocks on select() when the server side, say, crashes?


Solution

  • Use the following to be sure it's the clientfd that's returning from the select:

    else if (FD_ISSET(clientfd, &readfd)) {
    

    Don't have time to test, but I suspect the dummyfd is returning as an EOF from the select, not the clientfd.