Differences Between Windows and Unix Non-Blocking Sockets

While working on Twisted's networking, I discovered a series of differences between socket APIs on Windows and Unix/Linux. This page is intended to document them for the benefit of those who are developing their own networking code. Some caveats:

My main sources of information were the relevant MSDN pages, Volume 1 of Unix Network Programming (2nd Edition), and experimentation and results from running systems. I recommend all three for verifying this information.

For more differences see Warren Young's BSD Sockets Compatibility page.

select(2) limited to 64 FDs on Windows
In order to fix this, you can do #define FD_SETSIZE 512 (or some larger number if you wish). Python does this for you already.
WSA errnos
Socket APIs will return WSA errnos, rather than the standard ones (e.g. WSAEWOULDBLOCK, although Windows also has EWOULDBLOCK). Except when they don't. Refer to MSDN.
select(2) doesn't block on empty lists of fds
If you don't pass any socket fds to select(2) on Unix, it will block for the specified timeout. On Windows, it will return immediately with an error. This may be a Python oddity.
Peculiar errnos from select(2)
I've seen errnos 0 and 2 returned on Win32 for no reason I understood, apparently when passing empty read or write list.
Detecting failed connects is done using exception list of select(2)
On Unix, a failed connect will return an error upon reading or writing from the socket, and select() will mark the socket as notified. The exception list in select(2) is used for detecting OOB data. On Windows, not the read or write lists but rather the exception list is used for detecting failed connects.
On Windows failed connects, reads and writes still return WSAEWOULDBLOCK
Reads or writes to the socket will return a WSAEWOULDBLOCK even if connection failed. The errno is available via getsockopt with SO_ERROR.
WSAEINVAL is equivalent to WSAEWOULDBLOCK for connect(2)
You need to treat both as equivalent on Windows. (This makes me suspicious after rereading issue before previous, might be untrue and I screwed up somewhere - verify this sometime.)
SO_REUSEADDR is weird
On Windows it lets you bind to the same TCP port multiple times without errors. Verified experimentally by failing test, I never bothered to check out MSDN docs for this one, I just don't use it on Windows.
UDP blocking on recvfrom returns WSAECONNRESET for connection refused
On Unix you get ECONNREFUSED.
Differences in partial writes to TCP sockets (contributed by James Knight).
In Unix, socket.send(buf) will buffer as much of buf as it has space for, and then return how much it accepted. This could be 0 or up to something around 128K. If you send some data and then some more, it will append to the previous buffer.

In Windows, socket.send(buf) will either accept the entire buffer or raise ENOBUFS. Testing indicates that it will internally buffer any amount up to 50MB (this seems to be the total for either the process or the OS, I'm not sure). However, it will not incrementally accept more data to append to a socket's buffer until the big buffer has been completely emptied (seemingly down to the SO_SNDBUF length, which is 8192), but rather raises WSAEWOULDBLOCK instead.

Return to homepage