views:

435

answers:

5

I'm porting a windows network application to linux and faced a timeout problem with select call on linux. The following function blocks for the entire timeout value and returns while I checked with a packet sniffer that client has already sent the data.

int recvTimeOutTCP( SOCKET socket, long sec, long usec )
{
  struct timeval timeout;
  fd_set fds;.

  timeout.tv_sec = sec;
  timeout.tv_usec = usec;
  FD_ZERO( &fds );
  FD_SET( socket, &fds );

  // Possible return values:
  // -1: error occurred
  // 0: timed out
  // > 0: data ready to be read
  cerr << "Waiting on fd " << socket << endl;
  return select(1, &fds, 0, 0, &timeout);
}
+9  A: 

I think the first parameter to select() should be socket+1.

You really should use another name as socket also is used for other things. Usually sock is used.

epatel
@jamessan Ah, yes I meant that ;)
epatel
Yes, Thanks, That solved my problem.
Ali Nadalizadeh
Right. `int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);` where nfds is `the highest-numbered file descriptor in any of the three sets, plus 1`.
jamessan
So we can imply that select() implementation in Windows is ignoring the first parameter ! Cool !
Ali Nadalizadeh
No need to imply - it's explicitly stated here in Microsoft's documentation for `select()`:http://msdn.microsoft.com/en-us/library/ms740141%28VS.85%29.aspx
mskfisher
A: 

From the man page of select:

int
 select(int nfds, fd_set *restrict readfds, fd_set *restrict writefds,
     fd_set *restrict errorfds, struct timeval *restrict timeout);

The first nfds descriptors are checked in each set; i.e., the descriptors from 0 through nfds-1 in the descriptor sets are examined.

Thus the first parameter to select should be socket + 1.

return select(socket + 1, &fds, 0, 0, &timeout);
Martin York
A: 

The first parameter to select(...) is the number of file descriptor to check in the set. Your call is telling it to only look at file descriptor 0, which is almost certainly not what socket is set to.

tatsu
+1  A: 

select on Windows ignores the first parameter. From MSDN:

C++
int select(
  __in     int nfds,
  __inout  fd_set *readfds,
  __inout  fd_set *writefds,
  __inout  fd_set *exceptfds,
  __in     const struct timeval *timeout
);

Parameters

nfds [in]

    Ignored. The nfds parameter is included only for
    compatibility with Berkeley sockets.
...
Nikolai N Fetissov
+1  A: 

The issue is that the fd_set in linux is a bit array ( originally it was just a int, but then you could only watch the first 16 io's of your process ). In windows fd_set is an array of sockets with a length at the front (which is why windows doesn't need to know how many bits to watch).

The poll() function takes an array of records to watch on linux and has other benefits which make it a better choice than select().

int recvTimeOutTCP( SOCKET socket, long msec )
{
    int iret ;
    struct polldf   sockpoll ;

    sockpoll.fd= socket ;
    sockpoll.events= POLLIN ;

    return poll(& sockpoll, 1, msec) ;
}   
woolstar
Thanks for the info, is this poll() function cross platform by any chance ?
Ali Nadalizadeh
Hmm, on Linux you really want to use epoll, preferably in edge-triggered mode.
Nikolai N Fetissov