You can decide if you want to use the socket as blocking, or nonblocking. Here is the code that switches between the 2 modes:
inline bool SetSocketBlocking(SOCKET sock, bool blocking)
{
unsigned long nonblocking_long = blocking ? 0 : 1;
if (ioctlsocket(sock, FIONBIO, &nonblocking_long) == SOCKET_ERROR)
return false;
return true;
}
If you use 1 listener/accepter thread in your server program and 1 thread per client with simple protocol, then its much easier to use blocking sockets I think. If you want an IO model where there are no threads per client but rather there is a "reactor" design pattern implementation where 1 thread (or sometimes more) serves a lot of sockets, then its easier to use non-blocking sockets.
For blocking sockets all recv/send/connect/accept operations are blocking until the operation either failes or succeeds. For nonblocking sockets its more complicated, but none of the previously mentioned functions block. With nonblocking sockets you usually do the read/write operations by waiting for sockets to become readable or writeable by using APIs like the crossplatform
select()
method, or the windows specific
WSAEventSelect()
or some IO completion ports if you want an MMO server. :) For example if the socket becomes writeable you call
send()
on it, and
send()
will return how many bytes was it able to write out. If it was able to write all bytes, you can call it again until it returns with error. In case of an error you have to check
WSAGetLastError()
if its
WSAEWOULDBLOCK
, because it means that this isn't really an error, only the send buffer of the socket (within the OS) is full, and you should wait again for the socket to become writeable. You have to check for this with almost every socket operations in case of nonblocking sockets. Connecting and accepting are also returning immediately with nonblocking sockets. In case of connection you have to wait for the socket to become writeable with
select()
(if you use the berkeley API) to detect when the connection becomes complete, or it will return with an exception flag set from
select()
in case of error. Or you can use the windows specific
WSAEventSelect()
that has a specific flag for connection detection. Same with accept, you have to wait for the listen socket to become readable with
select()
, or if you prefer windows specific API then
WSAEventSelect()
has special flags for testing the "accept ready" state. Maybe the
select()
is easier to use for the first time that the other APIs, and its also cross-platform.
Socket programming/debugging can become very-very complicated... Good luck, and ask again is something isn't clear or goes wrong! :D