Monday, March 7, 2011

Socket with recv-timeout: What is wrong with this code?

I'm trying to implement a socket with a recv timeout of 1 Second:

int sockfd;
struct sockaddr_in self;
struct sockaddr_in client_addr;
int addrlen=sizeof(client_addr);
ssize_t nBytes;

sockfd = socket(AF_INET, SOCK_STREAM, 0);

self.sin_family = AF_INET;
self.sin_port = htons(PORT);
self.sin_addr.s_addr = INADDR_ANY;

int on = 1;
setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on);

// 1 Sec Timeout
tv.tv_sec  = 1;  
tv.tv_usec = 0;
setsockopt( sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv);

bind(sockfd, (struct sockaddr*)&self, sizeof(self));

listen(sockfd, 20);

clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &addrlen);

nBytes = recv(clientfd, buffer, MAXBUF-1, 0);

Without 'setsockopt( sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv);' the calls to accept and recv work, but recv blocks.

With 'setsockopt( sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv);' the call to accept produces the error 'Resource temporarily unavailable'.

Can somebody please tell me what is wrong with this approach?

From stackoverflow
  • Try using select() before calling recv() or accept().

    select() takes an array of file descriptors (includinig sockets) and returns when at least one of them is ready to receive. It can also return on a timeout.

    In linux you can also try poll() (not sure if Winsock provides this).

    Remy Lebeau - TeamB : No, it does not.
  • Here's a snippet using select

      FD_ZERO(&masterfds);
      FD_SET(sockfd,&masterfds);
      memcpy(&readfds,&masterfds,sizeof(fd_set));
      timeout.tv_sec = 2;
      timeout.tv_usec = 0;
      if (select(sockfd+1, &readfds, NULL, NULL, &timeout) < 0)
      {
       printf("select error");
       exit(1);
      }
    
      if (FD_ISSET(sockfd, &readfds))
      {
       //printf("Read from socket\n");
       // read from the socket
       res = recvfrom(sockfd, (char *)hdrbuf, sizeof(hdrbuf), MSG_PEEK, recvaddr, address_len);
      }
      else
      {
       // the socket timedout
       //printf("Socket timeout started=%d\n",packets_started);
    
  • Which socket do you want to have the one-second timeout on? The one accepting connections, or the one established by accept()?

    I'd assume the latter - so try setting the receive timeout on clientfd AFTER the accept returns. You can also get to where you need to be using select, but you shouldn't need to.

0 comments:

Post a Comment