Client (TCP and Named Pipe) Connection Pooling

Using the TCP and Named Pipe bindings give you a very clean mapping between IDuplexSessionChannel and the underlying network resource (socket or pipe). Namely, you can effectively treat a channel as 1-1 to a socket (I will use socket as shorthand for the generic “network resource” for the remainder of this post :)).

That being said, the lifetime of the underlying socket is not necessarily 1-1 with the lifetime of the channel. Due to our connection pooling feature in WCF, a connection can be reused over the lifetime of multiple channels. We perform connection pooling for both buffered and streaming channels. Our connection pool is configurable through TcpConnectionPoolSettings/NamedPipeConnectionPoolSettings. These settings include a GroupName that we use for isolation, an upper bound on our cache size (MaxOutboundConnectionsPerEndpoint), and timeout values for reliability and NLB support

The way connection pooling works on the client is as follows:

  • When you open a channel we will first look for a connection in our pool. This lookup is performed based on IP+port for sockets and based on endpoint Uri name for Pipes.
  • If we find an available connection in our pool then we will attempt our open handshake using .Net Framing. If this succeeds then we will associate the connection with the new channel and return from Open. If it fails then we’ll discard the connection. If we have not yet exceeded the binding’s OpenTimeout then we will repeat the “look in pool” process.
  • If no [valid] connections are found in our pool then we will establish a new connection (again, using up to the time remaining in OpenTimeout).
  • When you close a channel, after we perform our close handshake we will consider returning the connection to our pool. If we already have reached MaxOutboundConnectionsPerEndpoint, or the connection’s lifetime has exceeded LeaseTimeout then we will close the connection instead. The connection that is returned to the pool is the “raw” connection (the one that was initially accepted, prior to any security upgrades). In this way we can provide a transparent pool without leaking any security or other information.

I was going to cover the server-side usage of connection pooling in this same post, but the process of accepting and reusing connections on the server is worthy of its own topic next time 😉

7 thoughts on “Client (TCP and Named Pipe) Connection Pooling

  1. Yuri Kozlov

    Hallo Kenny,

    I have one question concerning porting Remoting to WCF.

    I my Remoting-based application i used now and then the Remoting’s capabilities to immediately marshal interfaces; this means, i can pass interface of client’s object to the server, store this interface reference at server side in some variable, and later call back from server to the client through this interface refernece. All i need is to derive client’s class from MarshalByRefObject and normally to overwrite InitializeLifetimeService() so that the latter returns null.

    What is the best way to port this code to WCF? I notice that i cannot pass the interface reference as remote method’s parameter in WCF : WCF ignores MarshalByRefObject and tries to serialize the client’s object whose refernce is passed. All my server objects are SingleCall activated and i want this to stay, which means i cannot do WCF sessions. Do i need Duplex functionality for this or is there some other way to marshal interfaces’ references?

    Thank you in advance.

    Yu. Kozlov

    Reply
  2. Pingback: More details on MaxConnections at kennyw.com

  3. Shashi

    Hi Kenny,

    Thanks for the description of connection pooling.

    I’m a novice user of WCF. Forgive me if my question is silly.

    Is there a way to disable the “connection pooling” feature for buffered channels?

    I’m interested in creating a unique tcp connection for each channel. Is there an alternative way to tell the framework to create a new TCP connection for every new channel? Specifically, any attributes/members in the netTCPBinding that I can tweak to achieve this?

    Thanks.

    Reply
  4. Kenny

    @Shashi: you can disable this feature by either setting TcpTransportBindingElement.ConnectionPoolSettings.MaxOutboundConnectionsPerEndpoint to zero or TcpTransportBindingElement.ConnectionPoolSettings.IdleTimeout to TimeSpan.Zero.

    @Rajeev: There is a nominal cost to CF.CreateChannel (a few allocations if all you have is TCP or the out of the box NetTcpBinding). Note that if you are using Security or WS-RM sessions then you will be establishing a new security/RM session for each channel, as they don’t cache their sessions.

    Reply
  5. Konstantin

    There is a forum post http://social.msdn.microsoft.com/forums/en-US/wcf/thread/770ba6c2-cc19-4336-bc09-53d5750105d3, leading to your article. It refers to the problem of WCF error logs, while there is no obvious error from user perspective. I’ve tried using custom binding with both IdleTimeout and LeaseTimeout being larger on server than on client and numerous other options, but the error persisted. Is there any other way to diagnose the problem?

    Reply
  6. Pingback: Are connections pools shared between ChannelFactories? « Sajay.com

Leave a Reply

Your email address will not be published. Required fields are marked *