Synchronous multiplexing for sockets (starring C++11)

Tags: howtos, programming

Published on
« Previous post: Automated mugshots with Python and … — Next post: Tomfoolery with Typography: Introduction »

In my previous post on network sockets, I described a simple implementation of a server and a client socket in C++11. The initial version was only capable of reacting to a new client connection. What about a socket being ready for reading, though?

select() and socket sets

There are numerous ways of doing multiplexing for sockets—of course I used the easiest one which is the worst and slowest. Anyway, after some quality time with the socket documentation, I implemented the following procedure:

  1. Create two empty socket sets, a master and a client socket. The sockets API refers to them as fd_set.
  2. Create a server socket (as in the previous post) and add it to the master set.
  3. Loop forever! Copy the master socket set to the client socket set and call select().
  4. If the call to select() finishes without an error, one of the sockets in the set is ready for something. This something might be a read operation or a new client.
  5. Handle this by creating new client sockets as appropriate, calling the corresponding callback functions using std::async, and updating the socket sets.

Sounds rather straightforward, but the corresponding code is messy and not yet very smart. For example, I am looping over all possible file descriptors and I had to adjust the ClientSocket class to un-register at the server class once a socket is closed. I am not quite content with the implementation.

How to use it?

The API is still using the callback approach introduced in the previous post. The cool thing is that this now also works whenever a client socket has something to say. For example, to implement RFC 862, the Echo protocol, we merely need the following code:

server.onRead( [&] ( std::weak_ptr<ClientSocket> socket )
  if( auto s = socket.lock() )
    auto data = s->read();
    s->write( data );
} );

Note that I have changed the std::unique_ptr to an std::weak_ptr because the server is now responsible for managing the client sockets. Since all handlers are called being asynchronously, it is possible that a socket is already unavailable because it has been closed.

Where is the code?

I have updated the GitHub repository introduced in the last post. The repository now also contains a simple echo server implementation.

The code is released under an MIT licence.