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?
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;
If HttpClient was multiplexing the requests, I would expect see a single connection (1 port, 1 handshake, etc).
You can't use HTTP/2 with HttpClient in . NET Core 2.1 or 2.2, even if you explicitly set the version in the request.
Multiplexing in HTTP 2.0 is the type of relationship between the browser and the server that use a single connection to deliver multiple requests and responses in parallel, creating many individual frames in this process.
HTTP multiplexing is the re-use of established server connections for multiple clients connections. The best way to understand this feature is to compare non-multiplexing behavior to multiplexing behavior.
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):
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With