Today we will finally revisit our client and add a little bit of code to it while discussing connection pools.  For those of you familiar with concepts such as thread pools, connection pools are similar in a number of ways.  Connection pools apply only to outgoing connections – not to incoming connections.  If you wish to limit incoming connections, you will simply need to reject the  excess incoming connections with a suggestion of when it is best to retry.

 

Connection pools for outgoing connections are required in situations where you only have a certain number of connection ‘lines’.  A particular example of this is telephony – where you can only make a certain number of outgoing calls on the lines provided from your carrier.  So, say you have ten lines but you need to make a thousand outgoing calls – in this case a connection pool will help greatly.  The connection pool will make sure connections are not made until a position in the pool opens up.

 

I thought a bit about changing our client to create multiple connections to the server but decided against unnecessarily complicating our client in this way.  Let’s add some code to see how connection pools work though.  In RegisterEndpoint, in IDKStudioClientManager of the client, add the following code right before we call BeginRegister.

 

// Determine when a connection pool has been added or removed

_connectionManager.ConnectionPoolAdded += new EventHandler<CollectionChangedEventArgs<ConnectionPool>>(_connectionManager_ConnectionPoolAdded);

_connectionManager.ConnectionPoolRemoved += new EventHandler<CollectionChangedEventArgs<ConnectionPool>>(_connectionManager_ConnectionPoolRemoved);

 

In order to get access to the ConnectionPool object, we are listening for when the connection manager adds or removes a connection pool.  By default, a connection manager does not create a connection pool.  It only does this when it receives its first outgoing connection.  The following code allows us to see how connection pools work in our client.

 

/// <summary>

/// Called when a connection pool is removed

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

void _connectionManager_ConnectionPoolRemoved(object sender, CollectionChangedEventArgs<ConnectionPool> e)

{

    RecordProgress("A connection pool was removed.");

    e.Item.ConnectionAdded -= Item_ConnectionAdded;

    e.Item.ConnectionRemoved -= Item_ConnectionRemoved;

}

 

/// <summary>

/// Called when a connection pool is added

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

void _connectionManager_ConnectionPoolAdded(object sender, CollectionChangedEventArgs<ConnectionPool> e)

{

    RecordProgress("A connection pool was added.");

   

    // Hook up the ConnectionAdded and ConnectionRemoved events

    e.Item.ConnectionAdded += new EventHandler<CollectionChangedEventArgs<RealTimeConnection>>(Item_ConnectionAdded);

    e.Item.ConnectionRemoved += new EventHandler<CollectionChangedEventArgs<RealTimeConnection>>(Item_ConnectionRemoved);

}

 

/// <summary>

/// Occurs when a connection is removed from the pool

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

void Item_ConnectionRemoved(object sender, CollectionChangedEventArgs<RealTimeConnection> e)

{

    RecordProgress("The following connection was removed\nLocal:{0}\nRemote:{1}",

        e.Item.LocalEndpoint == null ? "no local" : e.Item.LocalEndpoint.Address.ToString(),

        e.Item.RemoteEndpoint == null ? "no remote" : e.Item.RemoteEndpoint.Address.ToString());

}

 

/// <summary>

/// Occurs when a connection is added to the pool

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

void Item_ConnectionAdded(object sender, CollectionChangedEventArgs<RealTimeConnection> e)

{

    RecordProgress("The following connection was added\nLocal:{0}\nRemote:{1}",

        e.Item.LocalEndpoint == null ? "no local" : e.Item.LocalEndpoint.Address.ToString(),

        e.Item.RemoteEndpoint == null ? "no remote" : e.Item.RemoteEndpoint.Address.ToString());

}

 

When we receive a ConnectionPoolAdded event, we hook up to the ConnectionAdded and ConnectionReceived events.  In these events, we simply display some information about the connection.  I needed to check the endpoints for null because on my machine, where I run the client and server on the same machine, the local and remote endpoints are null in ConnectionAdded and are not null in ConnectionRemoved.

 

If you run the client with our server also running, you will notice that we add a connection pool and then remove it when it is no longer needed.  In order to release a connection from the pool, you must call BeginTerminate on the session.   The code by itself here is not very useful, but if you had a number of outgoing connections you would set the value of MaximumNumberOfConnections in the connection pool in the ConnectionPoolAdded event handler.

 

You can also change MaximumNumberOfConnections after other connections have been added.  One way you can do this is through the ConnectionPool property of the RealTimeConnection object that can be accessed through the SignalingSession’s Connection property – or SignalingSession.Connection.ConnectionPool.  If you set the value to be greater than the current value, the pool size will immediately increase, though a new connection must be created or an old one terminated for the change to take effect.  If you set the value to one less than the current value, the pool size will shrink but if the value is less than the current connection count, the connection count will exceed the pool size until the appropriate number of connections have been terminated.

 

Connection pools are a great feature that allow you to throttle the number of connections you have without spending very much effort coding this functionality.