2
votes

I need help with socket programming in C. I need to write a server-client program in C where two IPs communicate with each other on the sockets created. I was successful doing this. But now I want to add timer to the sockets. I've researched a bit and found out that it can be achieved with select() wherein we give the timeout value. I tried doing it but in vain. In the code shown below, I try to connect to a client and read on the new socket created for 10secs. If the client sends some message within those 10secs, the server should take in that message and send an acknowledgement back. If not, an error message must be given out saying that it timed out.

My server code is as follows:

    #include<stdio.h>
    #include<unistd.h>
    #include<sys/time.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<netinet/in.h>
    #include<stdlib.h>
    void error(char *msg)
    {
        perror(msg);
        exit(1);
    }

    int main(int argc, char *argv[])
    {
        int a=1;
        fd_set readfds,writefds;
        int ready_for_reading,reading;
        struct timeval time_out;
        FD_ZERO(&readfds);
  //    FD_ZERO(&writefds);
        FD_SET(a,&readfds);

        time_out.tv_sec = 10;    // 10 seconds
        time_out.tv_usec = 0;    // 0 milliseconds

  //    ready_for_reading=select(1,&readfds,NULL,NULL,&time_out);


        int sockfd, newsockfd, portno,n,clilen;;
        struct sockaddr_in serv_addr,cli_addr;
        char buffer[256];
        portno=atoi(argv[1]);
        sockfd=socket(AF_INET,SOCK_STREAM,0);
        if(sockfd==-1)
            error("\nError creating socket");
        serv_addr.sin_family=AF_INET;
        serv_addr.sin_port=htons(portno);
        serv_addr.sin_addr.s_addr=INADDR_ANY;

        n=bind(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
        if(n<0)
            error("\nError binding socket");
        listen(sockfd,5);
        clilen=sizeof(cli_addr);
        printf("\nAccept call reached");
        newsockfd=accept(sockfd,(struct sockaddr *)&cli_addr,&clilen);
        printf("\nnewSockfd=%d",newsockfd);
        printf("\ntesting value:%d",sizeof(readfds));
        if(newsockfd==-1)
            error("\nError on accept");
    //  FD_SET(a,&readfds);
        ready_for_reading=select(sizeof(readfds)*8,&readfds,NULL,NULL,&time_out);
        printf("\nready_for_reading=%d",ready_for_reading);
        if (ready_for_reading == -1) 
        {
            /* Some error has occured in input */
             printf("Unable to read your input\n");
             return -1;
        }
         else 
        {
                  if (ready_for_reading) 
              {
                     reading = read(newsockfd, buffer, 255);
                     printf("Read, %d bytes from input : %s \n", reading,buffer);
                  } 
              else 
              {
                     printf(" 10 Seconds are over - no data input \n");
             return 0;
                  }
            }

    /*  n=read(newsockfd,buffer,255);
        if(n<0)
            error("\nError in reading client's msg");
    */
        printf("\nClient's msg is:%s\n",buffer);
        n=write(newsockfd,"I got your message",25);
        if(n<0)
            error("\nError on writing");

        return 0;
    }

The select() function always returns '0'. I need help with this. Thanks in advance, Richard.

2

2 Answers

4
votes
      int a=1;
      fd_set readfds,writefds;
      int ready_for_reading,reading;
      struct timeval time_out;
      FD_ZERO(&readfds);
//    FD_ZERO(&writefds);
      FD_SET(a,&readfds); // a?!

You're selecting on file descriptor 1, stdout. You should be selecting on the file descriptor you got back from accept.

0
votes

For your particular problem, you can use the SO_RCVTIMEO socket option.

#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>

ssize_t recv_with_timeout (int s, void *buf, size_t len, int flags,
                           struct timeval *timeout)
{
    if (timeout) {
        ssize_t bytes;
        int r;
        struct timeval last;
        socklen_t lastlen = sizeof(last);
        r = getsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &last, &lastlen);
        if (r < 0) return r;
        r = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, timeout, sizeof(*timeout));
        if (r < 0) return r;
        bytes = recv(s, buf, len, flags);
        r = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &last, lastlen);
        assert(r == 0);
        return bytes;
    }
    return recv(s, buf, len, flags);
}

From the manual page:

SO_RCVTIMEO
Sets the timeout value that specifies the maximum amount of time an input function waits until it completes. It accepts a timeval structure with the number of seconds and microseconds specifying the limit on how long to wait for an input operation to complete. If a receive operation has blocked for this much time without receiving additional data, it shall return with a partial count or errno set to [EAGAIN] or [EWOULDBLOCK] if no data is received. The default for this option is zero, which indicates that a receive operation shall not time out. This option takes a timeval structure. Note that not all implementations allow this option to be set.