One of the questions that comes up time and again from users of The Server Framework is “How to I access the list of current connections within the framework”. My answer is, you don’t, you build your own collection and manage it yourself. Usually these people want to write some form of chat or gateway server; client A connects to the server and needs to send data to client B who is also connected to the server. This really isn’t a terribly hard problem to solve but, as always, the devil is in the details and enough people get it wrong to warrant some work on my part to make it easier for them.
There are several situations where you might want to have one connection communicating with another and, at its simplest, the server itself might wish to initiate communication with a connection in a manner that is not related to incoming data; for example, a server might need to send out data on a connection every time some external device changes state, or whatever. Time based server initiated connection activity is easy to achieve using the
CCallbackTimerQueue class and there are already plenty of examples in the framework that use this technique but server initiated communication that requires the server to ’look up’ a connection based on some external key or communication from one connection to others based on keys or collections is slightly more complex and, up until now, isn’t supported directly by the framework. It’s one of those things that I’ve always viewed as ’too easy’ to bother with including in the framework but, like most aspects of the framework I eventually harvest code from other projects into the core framework…
The common factor to the scenarios above is that the server needs to hold on to a socket in a collection of some kind so that it can look it up later and use it. Due to the fact that sockets are a reference counted data structure the server must increase the reference count when the socket is placed in such a collection and must then reduce the reference count again when the socket is removed. The problem that many people seem to have is knowing exactly when and how to do this.
To help with this I’ve added several new connection collection classes and examples that use them. All operate in a similar manner but each offers slightly different functionality. The collections use a single writer multiple reader lock to allow multiple concurrent lookups whilst protecting the collection from concurrent access during additions and removals and allow safe use of the stored sockets by correctly managing the reference count on the socket whilst it’s in the collection and when it’s returned to you for use after lookup.
The simplest collection is the
CStreamSocketConnectionCollection which creates a unique id for each connection added and allows you to lookup connections by id. It’s up to you how you use the id but the general usage pattern is that you would add the connection to the collection in the server’s
OnConnectionEstablished() call and remove it in
OnConnectionReset(). The server should also remove the connection by id at any point that it wishes if an external event requires that the connection be closed.
The next collection adds the ability to broadcast to all or a selection of connections. The reason that this collection is separate to the
CStreamSocketConnectionCollection class is that it requires that you pass in an instance of
IAllocateBufferHandles to the constructor so that it can broadcast instances of
IBuffer without needing to duplicate the data within the buffer for each connection.
CStreamSocketBroadcastableConnectionCollection simply adds two
Broadcast() methods, one which takes a list of connection ids and one which broadcasts to all connections.
The final collection allows the caller to name the connection rather than simply having the collection assign an arbitrary id. Obviously you could build a name to id map on top of one of the other collections but ’named’ connections are quite a common thing and it’s more efficient to have a single collection that maps names to connections rather than two separate mappings and associated locks.
Hopefully these classes will help those of you who have trouble with this area of The Server Framework and, even if they’re not a 100% exact fit for your problem, you can use them as design ideas.