Synchronous multiplexing for sockets (starring C++11)
Tags: howtos, programming
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:
- Create two empty socket sets, a master and a client socket. The sockets API refers to them as
fd_set
. - Create a server socket (as in the previous post) and add it to the master set.
- Loop forever! Copy the master socket set to the client socket set and call
select()
. - 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. - 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.