Understanding System.Net Connection Management and ServicepointManager
If you are already using System.Net.HttpWebRequest class and familiar with request/response programming model for WebRequest in .net frameworks, you might be interested in getting inside the connection management handling of HttpWebRequest and to understand how you could apply it effectively in your application.
In this article, you will understand the basics of connection management story of HttpWebRequest and how ServicepointManager and HttpWebRequest properties could be used to tune the connection management.
For the simplicity I did narrow down this post to simple scenarios to focus on connection management mechanism
a) Request is Anonymous (no authentication)
b) “GET” request,
c) No Proxy server is involved,
d) No caching involved - .net frameworks 2.0 added support for caching on HttpWebRequest, but for simplicity here we assume caching is disabled,
e) Request timeouts are also not described here,
In future posting I promise to provide more details about specific scenarios like POST request, authentication, proxy server and also for other protocols like FtpWebRequest and SmtpClient, which were added in .net frameworks 2.0.
Creating first WebRequest
Before we jump into details of connection management, take a fresh first look on the things happening behind the scene, when you are making first HttpWebRequest from your application. Following are two simple line of code would create a request and send it on the wire.
WebRequest request = WebRequest.Create(“https://blogs.msdn.com/adarshk”);
WebResponse response = request.GetResponse();
So as soon as your application invoke the GetResponse() method there are number things happened. Following is the sequence of operations took place.
a) System.Net see it is a first request, it creates a connection group for it,
b) Since this is new connection group, it also creates a servicepoint on this group (for the sack of simplicity, assume that there is no authentication involved and servicepoint is on per host basis),
c) It creates a new connection and open a new socket connection to remote host,
d) A NetworkStream is created on top of the connection and complete http request,
e) It wait for http response header data from remote host and once all headers are received, response.Headers structure is filled,
Next thing you might be doing in your application is either looking into response headers or reading response for the request as below
Stream readStream = response.GetResponseStream();
At this point the stream composed for the current connection and handed over to the user code, so user app could read the actual content of the request. After complete the reading on the stream, user app suppose to close the response stream.
So when readStream is closed, we indicate the System.Net that that app code is done with this request and connection is now freely available for upcoming other requests. If this request object had specifically set the “KeepAlive = false”, then connection would be closed at this point, by default KeepAlive = true. Let’s assume we did make the request with KeepAlive enabled.
Following diagram is sort of representing, the the relationship between ServicePoint, ConnectionGroup, Coonections.
> > Next HttpWebRequest
Now we are done with the first http request in application and let’s make second request. There are many possible scenarios to handle on second request. Let’s assume your second request is going on the same server:port as in previous request.
Second Request after finishing the previous request
This is simplest scenario, because you already closed the response Stream, connection is now freely available for second request. Second request would be send on the same connection as previous request, no new connection is created. Same sequence of operations would be followed as for the normal first request.
Second Request before finishing the first request – Pipelining
If we are making second request without finishing the first one then connection limit come to the picture. Default value of connection limit is 2, it is as per following the guidelines of http RFC2616. If we didn’t reach at connection limit, then on same service point new connection would get created and request would be send on new connection, but if we had reached the maximum connection limit then request would be queued on the one of the connection. How request would be queued depends on the pipelining.
Pipelining turned on
If pipelining is turned on (pipelining is available only against http 1.1 servers), request could be send to the server even if previous request was not completed as shown on following figure.
Server will respond on the requests in the same sequence as it received.
Pipelining turned off
If pipelining is turned off, then server can not accept the new request, unless it completed the previous requests, so new requests would be kept in a pending queue and when the current responseStream for current request is closed by the user then this new request is send on the wire as displayed on following diagram.
Following flowchart is a simplified representation of sequence of operations on connection management.
Queuing multiple requests
I believe now you have a better picture about what happened on first request and what happened with the connection on subsequent next request. If application continues to make requests, all pending requests would be queued on the ServicePoint and processed sequentially. If pipeline is turned on, then request is send on the connection and put in the queue of the connection. If pipelining is turned off then request would remain on the queue of the servicepoint and would be sending on the connection, as soon as free connection is available. Following diagram explains this in detail.
Recycling the connection
After getting inside of all this basic connection management, next natural question arise is how long we will keep the connection alive, when should we cleaned the connection and create new connections.
Whenever server chooses to close the connection, then off course client side has to close the connection. New connection would be created for future requests to same server. When server is not closing the connection from its side, then client need to optimize the connection management and only keep necessary connections alive via closing unwanted connections.
There are some properties on Servicepoint and ServicepointManager classes, which controls the lifetime of the connections.
Each ServicePoint instance maintains its connection only until it has been idle longer than the time specified in the MaxIdleTime property. Once a ServicePoint exceeds the MaxIdleTime, connection can be recycled (closed). The default value of MaxIdleTime is set by the MaxServicePointIdleTime property on ServicePointManager.
By default, when KeepAlive is true for a request, the MaxIdleTime property sets the timeout for closing ServicePoint connections due to inactivity. If the ServicePoint has active connections, MaxIdleTime has no effect and the connections remain open indefinitely.
Connection lease timeout
This property is added in .net frameworks 2.0. There are some specific scenarios where it is more optimal to close the current active connection to the server and establish a new connection, especially in case where server side have load balancing mechanism (e.g. Web Garden scenario, where load is dynamically distributed across multiple servers for load balncing). This Servicepoint.ConnectionLeaseTimeout allows user to close the active connection and new connection would be created for subsequent requests.
One important thing to note about connection cleanup, there is no separate thread is monitoring the connection status, cleanup of connection is performed when user application is making the requests, at that ServicePointManager verify the state of the connection and perform cleanup operation if required.
This posting is provided "AS IS" with no warranties, and confers no rights