Mark Taylor
Mark Taylor

Reputation: 501

Can you achieve Http/2 multiplexing with .Net Core HttpClient?

Summary

The Http/2 protocol provides the ability to multiplex multiple requests over a single connection. This allows for more efficient use of connections - see https://http2.github.io/faq/#why-is-http2-multiplexed

I would expect to be able to use the .Net Core HttpClient to achieve this. My test (based on the below) however indicate that there is a 1:1 ratio of request to TCP connections are made.

Is multiplexing supported under .Net Core HttpClient? And if so, how is it achieved?

Work so far

I have a sample app (repo can be found here, with the following code;

using (var httpClient = new HttpClient())
{
   var request1 = new HttpRequestMessage(HttpMethod.Get, "https://www.google.com");
   request1.Version = new Version(2, 0);

   var request2 = new HttpRequestMessage(HttpMethod.Get, "https://www.google.com");
   request2.Version = new Version(2, 0);

   var task1 = httpClient.SendAsync(request1);
   var task2 = httpClient.SendAsync(request2);

   Task.WaitAll(task1, task2);

   var response1 = task1.Result;
   var response2 = task2.Result;

   Console.WriteLine($"Response 1 - Http Version: {response1.Version}, Http Status Code: {response1.StatusCode}");
   Console.WriteLine($"Response 2 - Http Version: {response2.Version}, Http Status Code: {response2.StatusCode}");
}

This code produces the following results (so I know Http/2 is being used);

Response 1 - Http Version: 2.0, Http Status Code: OK
Response 2 - Http Version: 2.0, Http Status Code: OK

I can see from Wireshark that 2 connections have been created - each having to go through TLS setup;

Wireshark Capture

If HttpClient was multiplexing the requests, I would expect see a single connection (1 port, 1 handshake, etc).

Upvotes: 18

Views: 5328

Answers (1)

Mark Taylor
Mark Taylor

Reputation: 501

The problem with my code is that request2 is being received by the HttpClient BEFORE it has had a chance to create a TCP connection for request1. As such, as far as HttpClient is concerned, there is no existing connection to multiplex on.

If however, I create an initial request (request0 in the below) and allow HttpClient to open the connection, then the subsequent requests (1 & 2) use that existing connection.

The code:

using (var httpClient = new HttpClient())
{
   // Setup first connection
   var request0 = new HttpRequestMessage(HttpMethod.Get, "https://www.google.com");
   request0.Version = new Version(2, 0);

   var task0 = httpClient.SendAsync(request0);
   var response0 = task0.Result;

   Console.WriteLine($"Response 0 - Http Version: {response0.Version}, Http Status Code: {response0.StatusCode}");

   // Now send the multiplexed requests
   var request1 = new HttpRequestMessage(HttpMethod.Get, "https://www.google.com");
   request1.Version = new Version(2, 0);

   var request2 = new HttpRequestMessage(HttpMethod.Get, "https://www.google.com");
   request2.Version = new Version(2, 0);

   var task1 = httpClient.SendAsync(request1);
   var task2 = httpClient.SendAsync(request2);

   Task.WaitAll(task1, task2);

   var response1 = task1.Result;
   var response2 = task2.Result;

   Console.WriteLine($"Response 1 - Http Version: {response1.Version}, Http Status Code: {response1.StatusCode}");
   Console.WriteLine($"Response 2 - Http Version: {response2.Version}, Http Status Code: {response2.StatusCode}");
}

And the Wireshark proof (only 1 port, 1 handshake):

Wireshark capture

Upvotes: 8

Related Questions