In Windows, when nonblock send return -1, WSAGetLastError() returns WSAENOBUFS, not WSAEWOULDBLOCK, which is different from linux.
How can I have WSAGetLastError() return WSAEWOULDBLOCK?
In Windows, when nonblock send return -1, WSAGetLastError() returns WSAENOBUFS, not WSAEWOULDBLOCK, which is different from linux.
How can I have WSAGetLastError() return WSAEWOULDBLOCK?
Those are two completely different error conditions.
WSAEWOULDBLOCK
means the socket send buffer is full and cannot accept more data without blocking the calling thread.
WSAENOBUFS
means the underlying kernel buffer itself is full and cannot accept more data at all. This is an good indication that you are sending way too much data to the socket at one time. Under normal conditions, you should not be getting this error.
Here is an interesting tidbit from Microsoft's KB:
Design issues - Sending small data segments over TCP with Winsock
To optimize performance at the application layer, Winsock copies data buffers from application send calls to a Winsock kernel buffer. Then, the stack uses its own heuristics (such as Nagle algorithm) to determine when to actually put the packet on the wire. You can change the amount of Winsock kernel buffer allocated to the socket using the SO_SNDBUF option (it is 8K by default). If necessary, Winsock can buffer significantly more than the SO_SNDBUF buffer size. In most cases, the send completion in the application only indicates the data buffer in an application send call is copied to the Winsock kernel buffer and does not indicate that the data has hit the network medium. The only exception is when you disable the Winsock buffering by setting SO_SNDBUF to 0.
Winsock uses the following rules to indicate a send completion to the application (depending on how the send is invoked, the completion notification could be the function returning from a blocking call, signaling an event or calling a notification function, and so forth):
•If the socket is still within SO_SNDBUF quota, Winsock copies the data from the application send and indicates the send completion to the application.
•If the socket is beyond SO_SNDBUF quota and there is only one previously buffered send still in the stack kernel buffer, Winsock copies the data from the application send and indicates the send completion to the application.
•If the socket is beyond SO_SNDBUF quota and there is more than one previously buffered send in the stack kernel buffer, Winsock copies the data from the application send. Winsock does not indicate the send completion to the application until the stack completes enough sends to put the socket back within SO_SNDBUF quota or only one outstanding send condition.
WSAENOBUFS
is reported when you are trying to send more data than the kernel can physically handle.
WSAENOBUFS
10055
No buffer space available.
An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.
You need to break up your data into smaller chunks so that you do not overwhelm the kernel. Ideally, for best performance, you should not exceed the buffer size reported by getsockopt(SO_SNDBUF)-1
. But either way, when you do encounter WSAEWOULDBLOCK
(which you should encounter before WSAENOBUFS
), STOP SENDING DATA until the socket is ready to receive more data. Depending on your code, that could be indicated by select()
reporting the socket is writable, or by you receiving an FD_WRITE
notification from WSAAsyncSelect()
/WSAEventSelect()
.