4

I am currently creating an echo server that disconnects clients after a maxWaitTime of being in idle.

I was hoping the program would block the socket until the client sent data but when I run the program in gdb it goes through the select and blocks on Readline.

I know retval = 0 whenever it goes through the select and that the fd_set sock goes to [256, (31 zeroes)] and after the select, sock goes to [32 zeroes].

The accepting of the connection happens in another function and the connection descriptor is passed to the echo function.

If you are able to help point me in the right direction or let me know how I can disconnect a client after a certain amount of time please let me know.

If you require any further information please let me know.

    FD_ZERO(&sock);
    FD_SET(sockfd,&sock);

    int opt = 3;

    setsockopt(sockfd, SOL_SOCKET, SO_RCVLOWAT,&opt,sizeof(opt));

    timeout.tv_sec = maxWaitTime;
    timeout.tv_usec = 0;

    for ( ; ; ) {
            FD_SET(sockfd,&sock);

            printf("Set is %d\n",FD_ISSET(sockfd,&sock));

            int retval;
            retval = select(1, &sock, NULL, NULL, &timeout);
            
            if(retval)
            {
                    quitProgram(number);
            }
            else
            {
            printf("n is %d\n",retval);

            if ( (n = Readline(sockfd, line, MAXLINE)) == 0)
            {
                    return;         /* connection closed by other end */
            }

            Writen(sockfd, line, n);

    }
3
  • If this is on a POSIX machine (e.g. OSX or Linux) then the first argument to selectshould the the highest numbered socket plus one. In your case sockfd + 1. Also, I guess your timeout maxWaitTime is non-zero? Commented Sep 26, 2012 at 12:55
  • 2
    read the man page of select() very carefully. 3 important things are: 1. The first argument to select must be the largest socket descriptor plus one 2. select returns 0 when the timeout occurs. 3. On Linux, the timeout argument is decremented by select() - thus your current code will eventually run with a timeout of 0 if you're on Linux Commented Sep 26, 2012 at 12:56
  • 1
    Another point, select returns -1 on error, zero on timeout only, and a positive number if sockets are ready (actually the number of sockets ready in the three sets combined). So you can't just check if the return is non-zero for error. Commented Sep 26, 2012 at 12:58

1 Answer 1

8

As others have commented, you have some logic holes in your code. By your own admission:

I know retval = 0 whenever it goes through the select and that the fd_set sock goes to [256, (31 zeroes)] and after the select, sock goes to [32 zeroes].

That should have been an indication to you that something was going wrong. The socket was not in the fd_set after select() exited, which meant the socket was not readible yet. retval=0 means select() timed out.

You have to reset not only the fd_set every time select() is called, but also the timeval as well. Try this instead:

int opt = 3; 
setsockopt(sockfd, SOL_SOCKET, SO_RCVLOWAT,&opt,sizeof(opt)); 

for ( ; ; )
{ 
    timeout.tv_sec = maxWaitTime; 
    timeout.tv_usec = 0; 

    FD_ZERO(&sock); 
    FD_SET(sockfd,&sock); 

    int retval = select(sockfd+1, &sock, NULL, NULL, &timeout); 
    if (retval <= 0) 
    { 
        quitProgram(number); /* error or connection timed out */
    } 
    else 
    { 
        if ( (n = Readline(sockfd, line, MAXLINE)) <= 0) 
        { 
            return; /* error or connection closed by other end */ 
        } 

        Writen(sockfd, line, n); 
    } 
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.