|
Build and Run
Build the project and make sure there is no error.
Without error during the build stage, run the project without debugging.
The following screenshot shows a sample console output. This program needs to be run at the command prompt. |
Invoke the command prompt through the run command or Start > All Programs > Accessories > Command Prompt short cut menu or through the Visual Studio Tools. Then, run the project from command line.
The command line argument used in this sample run is:
fastgetcp -a -c 5 -n 7 -u http://msdn.microsoft.com/en-us/visualc/aa336402.aspx
The following screenshot shows a sample console output.
To compare the 'performance', use different –n and –c values for the arguments. A complete sample console output for the previous sample run is given in the following para.
C:\networkdotnetproject\FastGetCP\Debug>fastgetcp
In main()...
In FastAsyncGetCP::TestMain()
In FastAsyncGetCP::usage()
usage: fastgetcp -c [int] -n [int] -u [URI] -p
-a Allow unsafe authenticated connections
-c int Number of concurrent requests allowed
-d Disable Nagle algorithm
-n int Total number of connections to make
-u URI URI resource to download
-p Enable pipelining
-un string User name
-up string Password
-ud domain Domain
C:\networkdotnetproject\FastGetCP\Debug>fastgetcp -a -c 5 -n 7 -u http://msdn.microsoft.com/en-us/visualc/aa336402.aspx
In main()...
In FastAsyncGetCP::TestMain()
Counting start in ms: 7181734
Getting the pages...
In FastAsyncGetCS::GetPages()
In FastAsyncGetCS::ResponseCallback()
In FastAsyncGetCS::ReadCallBack()
In FastAsyncGetCS::ReadCallBack()
[trimmed]
In FastAsyncGetCS::ReadCallBack()
In FastAsyncGetCS::ReadCallBack()
In FastAsyncGetCS::ResponseCallback()
In FastAsyncGetCS::ReadCallBack()
In FastAsyncGetCS::ReadCallBack()
[trimmed]
In FastAsyncGetCS::ReadCallBack()
In FastAsyncGetCS::ReadCallBack()
In FastAsyncGetCS::ResponseCallback()
In FastAsyncGetCS::ReadCallBack()
In FastAsyncGetCS::ReadCallBack()
[trimmed]
In FastAsyncGetCS::ReadCallBack()
In FastAsyncGetCS::ReadCallBack()
In FastAsyncGetCS::ResponseCallback()
In FastAsyncGetCS::ReadCallBack()
In FastAsyncGetCS::ReadCallBack()
[trimmed]
In FastAsyncGetCS::ReadCallBack()
In FastAsyncGetCS::ReadCallBack()
In FastAsyncGetCS::ResponseCallback()
In FastAsyncGetCS::ReadCallBack()
In FastAsyncGetCS::ReadCallBack()
[trimmed]
In FastAsyncGetCS::ReadCallBack()
In FastAsyncGetCS::ReadCallBack()
Counting end in ms: 7195031
Total count for the elapsed time in ms: 13297
Calculating the total KB/s...
Then total count in seconds 13.297 seconds.
Number of requests in the elapsed time: 0.5264345 requests per second.
It is 20 KB per second.
C:\networkdotnetproject\FastGetCP\Debug>
Developers should be aware that the HTTP verb used can impact performance. When performing a POST operation, the server often responds with a 100 Continue after the request has been accepted. This response is typically sent to prevent the client from sending the entire request when the server rejects it. The 100 Continue logic saves network bandwidth and unneeded processing on the client side when a request is rejected; however, it can cause a bottleneck as an extra roundtrip is required to complete the POST request.
An application can explicitly override the 100 Continue behavior by using the ServicePointManager.Expect100Continue property. By default, when a POST is issued, the Framework waits 350 milliseconds before the body is transmitted unless the server responds with a 100 Continue. This timeout is in place in the event that the server simply expects the client to transmit the body. With the default behavior of waiting for a 100 Continue response, a POST operation incurs two roundtrips plus a possible 350-millisecond delay before the request can complete. Setting the Expect100Continue to false would cause the body to be transmitted immediately, bypassing the 350-millisecond delay.
The GET verb can also suffer from a performance roadblock: the Nagle algorithm. A roadblock is especially likely if authentication is involved. When an application posts multiple GET requests to a server, the Nagle algorithm introduces up to a 200-millisecond delay before sending the requests. As we mentioned earlier, Nagling reduces network load by lumping more data into a single packet; this behavior can introduce significant delays, however, since HTTP GET requests tend to be smaller than the Nagle threshold and therefore incur a delay.
Authenticating a request is a powerful and often necessary task. Of course, this process adds extra overhead to the HTTP request that can significantly affect overall performance. The .NET Framework Web classes support several authentication methods, including basic, digest, NTLM, and Kerberos. Each method incurs its own overhead for authenticating a request depending on the efficiency of the underlying protocol. Table 14-4 compares the performance of different authentication types.
Table 14-4: HTTP Authentication Performance
|
||||
Authentication Type |
Preauthentication |
Unsafe Connection Sharing |
Requests per Second |
CPU Usage |
None |
No |
No |
1,322 |
89 |
Basic |
No |
No |
1,312 |
90 |
Basic |
Yes |
No |
962 |
91 |
Digest |
No |
No |
219 |
63 |
Digest |
Yes |
No |
511 |
60 |
Kerberos |
No |
No |
1,298 |
59 |
NTLM |
No |
No |
95 |
66 |
NTLM |
No |
Yes |
1,261 |
100 |
The table shows the number of requests per second when using a given authentication type to retrieve a 1-KB file along with the default connection limit of two. The CPU usage on the client is also listed. Notice how enabling preauthentication increases performance for those authentication types that support it (Basic and Digest). Also notice that enabling the HttpWebRequest.UnsafeAuthenticatedConnectionSharing increases NTLM performance.
As we mentioned in Chapter 10, NTLM authentication occurs on every request as the default behavior. This can lead to server performance penalties, as illustrated by the rate of 95 connections per second shown in Table 14-4. The reason for this performance degradation is in the middle-tier scenario, where a client is making a request to a back-end server while impersonating another user. If UnsafeAuthenticatedConnectionSharing is used carelessly, then the first connection can be established using the Administrators privileges. If the client later impersonates a regular user, subsequent requests are made with Administrator rights. A way to guard against this risk when unsafe connection sharing is enabled is to use the ConnectionGroupName property to associate all requests from one user together, as shown in the following code sample:
C#
HttpWebRequest request;
NetworkCredential userJoe, userMike;
request = (HttpWebRequest)WebRequest.Create(“http://foo.com”);
userJoe = new NetworkCredential( “Joe", “JoePassWord!” );
userMike = new NetworkCredential( “Mike", “MikePassWord!” );
request.Credentials = userJoe;
request.ConnectionGroupName = userJoe.UserName;
request.UnsafeAuthenticatedConnectionSharing = true;
// Make request for Joe
request = (HttpWebRequest) WebRequest.Create(“http://foo.com”);
request.Credentials = userMike;
request.ConnectionGroupName = userMike.UserName;
request.UnsafeAuthenticatedConnectionSharing = true;
// Make request for Mike
Visual Basic .NET
Dim request As HttpWebRequest
Dim userJoe As NetworkCredential
Dim userMike As NetworkCredential
request = WebRequest.Create("http://foo.com")
userJoe = New NetworkCredential("Joe", "JoePassWord!")
userMike = New NetworkCredential("Mike", "MikePassWord!")
request.Credentials = userJoe
request.ConnectionGroupName = userJoe.UserName
request.UnsafeAuthenticatedConnectionSharing = True
‘ Make request for Joe
request = WebRequest.Create("http://foo.com")
request.Credentials = userMike
request.ConnectionGroupName = userMike.UserName
request.UnsafeAuthenticatedConnectionSharing = True
‘ Make request for Mike
The sample uses two user credentials for Joe and Mike. Joe’s credentials should not be used when making Mike’s request, so ConnectionGroupName is set to the user’s name for each request. This prevents Mike’s request from executing under Joe’s user credentials. A final note about NTLM authentication is that an extra TCP connection is used each time the client authenticates the supplied user credentials. With the default security (i.e., unsafe authentication disabled), the extra connection can exhaust the local port space causing subsequent HTTP requests to fail with a protocol error. Recall that when a socket is created and bound to port zero, it is actually randomly bound to a local port between 1024 and 5000. Each time a request is made with credentials, an extra TCP connection is created to the server that is bound to a port in this range. Once the credentials are verified, the connection is closed, but it goes into a TIME_WAIT state.
< C++/CLI Web Class Performance Measurement Program Example | Main | Chap 15 TOC: Advancement in .NET Framework Networking >