Olego (olego) wrote,

  • Music:

WinSock 2.2

I've been working with Windows Sockets recently, and I want to summarise a few things that I've learned, just in case I'll need to remember them in the future.

(1) Berkeley Sockets are supported, and work fine for console applications. They aren't ideal if you need to mix in threads or message pumps. Also, select() behaves slightly differently on Windows than it does on Unix. If you are waiting for 2 sockets and only the second is signalled, then in Unix FD_ISSET(0, read_set) is false and FD_ISSET(1, read_set) is true. In Windows, read_set.fd_count is 1, and read_set.fd_array[0] is the handle of the second socket (since sockets aren't created in a nice arithmetic progression).

(2) There's a way to have select() work directly with window messages: WSAAsyncSelect(). But you need to create a window in that thread, which obviously limits the current number of running threads. There's also WSAEventSelect(), which requires a call to WaitForMultipleObjects() instead of a window. It's slightly simpler to use.

(3) The most straightforward way to write multi-socket servers is to use IoCompletionPorts. Every operation is asynchronous; once the operation finishes you can find out the result by calling a blocking function GetQueriedCompletionStatus (from any thread--which is a big advantage).

(4) In order to use techniques 2 or 3, you need to create "overlapped" sockets (using socket() or WSASocket(WSA_FLAG_OVERLAPPED). If you're calling accept()/WSAAccept(), then the new socket will be "overlapped" if the listening socket is overlapped (which is important!). I still can find no reason to create a non-overlapped socket intentionally, since passing a NULL lpOverlapped converts any function into a blocking function (this is true only for sockets).

(5) Neither accept() nor WSAAccept() (same applies for variants of connect()) are overlapped calls, so they cannot be serviced by the threads that are looping over GetQueriedCompletionStatus(). You can either have a thread dedicated to accept() (or connect()) calls, or use a bizarre WinSock2 extension called SIO_GET_EXTENSION_FUNCTION_POINTER, which associates your listening socket (or connecting socket) with a Completion Port, so that you can have homogeneous loops. Here's what it looks like:

#include <mswsock.h>

unsigned long dummy = 0;
SOCKET listeningSocket = CreateListeningSocket(80);
CreateIoCompletionPort((HANDLE) listeningSocket, currentCompletionPort, 42, 0);

// Load the AcceptEx extension function from the provider for this socket
&guidAcceptEx, sizeof(guidAcceptEx),
&fnAcceptEx, sizeof(fnAcceptEx),
&dummy, NULL, NULL);
fnAcceptEx(/*Crazy parameters*/);

It's not as bad as it looks--but depending on the design of your application, WSAAsyncSelect may be all that you need. :-)

  • Stories

    Some time ago, I came up with an idea of a story about a guy, not unlike myself, who got transported to a foreign land and learned that magic is…

  • Bioshock Infinite

    After beating Bioshock Infinite, I have just 1 relatively spoiler-free complaint about it. Despite the fact that its story, and its female character,…

  • Sous-vide

    I finally had a chance to try Sous-vide. Sous-vide is a method of cooking food (mostly meats) in a vacuum-sealed container, which is submerged in a…

  • Post a new comment


    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded