Porting a Winsock application to Linux...select(2) is not as simple as MSDN makes it seem

— richardwb on Friday, April 10, 2009 @ 17:54

I'm in the middle of porting bits of a Winsock application to Linux. Luckily when I first wrote the networking bits I had made an effort to write it in a somewhat cross platform manner. As a result, I stuck to select(), send(), recv(), and all the other function calls that Winsock provides that are close to the Berkeley socket interface. Things go pretty smoothly, although for some reason there's this really weird pause when connecting that didn't exist before...

Finally I hit a point where, for some reason, I couldn't establish a connection to the server and it just times out. That's really strange, so I threw good old debug statements all over the place and find out that this select() call is not doing much of a select:

if (select(0, &rdset, &wtset, &errset, &tv) > 0)

Notice the 0? MSDN states that it is:

nfds
Ignored. The nfds parameter is included only for compatibility with Berkeley sockets.

Then I check the equivalent docs on the Linux side of things:

nfds is the highest-numbered file descriptor in any of the three sets, plus 1.

Well, if I set nfds to 0, select() won't be doing very much selecting! Windows has FD_SETSIZE at 64 by default, and it ignores nfds and just checks whatever descriptors are in the fd_sets that you pass to it. Linux considers sockets and files the same thing, and thus has a much higher FD_SETSIZE (1024 and 4096 seem to be common). You don't want select() checking 4096 descriptors, so you set nfds to the highest file descriptor you want it to check, plus one. (As an aside, setting nfds to FD_SETSIZE is a bad idea.)

if (select(my_socket + 1, &rdset, &wtset, &errset, &tv) > 0)

Where my_socket is an appropriate file descriptor (such as the one returned by socket()). This works just fine in Windows too, since it ignores the nfds parameter.

Armed with this newfound knowledge, I go and fix all the other select() statements in my code, which ends up fixing the weird pause as well. Effectively, without a proper nfds value, select() just acts as a timer and blocks until the specified amount of time has elapsed.

comments powered by Disqus