Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
WebSocket-protokollet möjliggör dubbelriktad kommunikation mellan en klient och en fjärrvärd. Den System.Net.WebSockets.ClientWebSocket exponerar möjligheten att upprätta WebSocket-anslutning via en inledande handskakning, som skapas och skickas av metoden ConnectAsync.
Skillnader i HTTP/1.1 och HTTP/2 WebSockets
WebSockets via HTTP/1.1 använder en enda TCP-anslutning, därför hanteras den av anslutningsomfattande rubriker. Mer information finns i RFC 6455. Tänk dig följande exempel på hur du upprättar WebSocket via HTTP/1.1:
Uri uri = new("ws://corefx-net-http11.azurewebsites.net/WebSocket/EchoWebSocket.ashx");
using ClientWebSocket ws = new();
await ws.ConnectAsync(uri, default);
var bytes = new byte[1024];
var result = await ws.ReceiveAsync(bytes, default);
string res = Encoding.UTF8.GetString(bytes, 0, result.Count);
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "Client closed", default);
En annan metod måste användas med HTTP/2 på grund av dess multiplexeringskaraktär. WebSockets etableras per datastream, för mer information, se RFC 8441. Med HTTP/2 är det möjligt att använda en anslutning för flera webbsocketsströmmar tillsammans med vanliga HTTP-strömmar och utöka HTTP/2:s effektivare användning av nätverket till WebSockets. Det finns en särskild överlagring av ConnectAsync(Uri, HttpMessageInvoker, CancellationToken) som accepterar en HttpMessageInvoker för att möjliggöra återanvändning av befintliga poolsammankopplingar.
using SocketsHttpHandler handler = new();
using ClientWebSocket ws = new();
await ws.ConnectAsync(uri, new HttpMessageInvoker(handler), cancellationToken);
Konfigurera HTTP-version och -princip
Som standard använder ClientWebSocket HTTP/1.1 för att skicka en inledande handskakning och tillåter nedgradering. I .NET 7 finns webbsocketer över HTTP/2 tillgängliga. Det kan ändras innan du anropar ConnectAsync:
using SocketsHttpHandler handler = new();
using ClientWebSocket ws = new();
ws.Options.HttpVersion = HttpVersion.Version20;
ws.Options.HttpVersionPolicy = HttpVersionPolicy.RequestVersionOrHigher;
await ws.ConnectAsync(uri, new HttpMessageInvoker(handler), cancellationToken);
Inkompatibla alternativ
ClientWebSocket har egenskaper System.Net.WebSockets.ClientWebSocketOptions som användaren kan konfigurera innan anslutningen upprättas. Men när HttpMessageInvoker tillhandahålls har den även dessa egenskaper. För att undvika tvetydighet bör i så fall egenskaper anges på HttpMessageInvokeroch ClientWebSocketOptions ska ha standardvärden. Annars, om ClientWebSocketOptions ändras, kommer överbelastning av ConnectAsync att kasta en ArgumentException.
using HttpClientHandler handler = new()
{
CookieContainer = cookies;
UseCookies = cookies != null;
ServerCertificateCustomValidationCallback = remoteCertificateValidationCallback;
Credentials = useDefaultCredentials
? CredentialCache.DefaultCredentials
: credentials;
};
if (proxy is null)
{
handler.UseProxy = false;
}
else
{
handler.Proxy = proxy;
}
if (clientCertificates?.Count > 0)
{
handler.ClientCertificates.AddRange(clientCertificates);
}
HttpMessageInvoker invoker = new(handler);
using ClientWebSocket cws = new();
await cws.ConnectAsync(uri, invoker, cancellationToken);
Komprimering
WebSocket-protokollet stöder deflate per meddelande enligt definitionen i RFC 7692. Den styrs av System.Net.WebSockets.ClientWebSocketOptions.DangerousDeflateOptions. I nuläget skickas alternativen till servern under handskakningsfasen. Om servern stöder deflate per meddelande och alternativen godkänns skapas ClientWebSocket-instansen med komprimering aktiverad som standard för alla meddelanden.
using ClientWebSocket ws = new()
{
Options =
{
DangerousDeflateOptions = new WebSocketDeflateOptions()
{
ClientMaxWindowBits = 10,
ServerMaxWindowBits = 10
}
}
};
Viktig
Innan du använder komprimering bör du vara medveten om att om du aktiverar komprimering kan applikationen bli utsatt för CRIME/BREACH-attacker. För mer information, se även CRIME och BREACH. Vi rekommenderar starkt att du inaktiverar komprimering när du skickar data som innehåller hemligheter genom att ange flaggan DisableCompression för sådana meddelanden.
Keep-Alive strategier
På .NET 8 och tidigare är den enda tillgängliga Keep-Alive-strategin Ouppmanad PONG. Den här strategin räcker för att förhindra att den underliggande TCP-anslutningen går ut på tomgång. Men om en fjärrvärd slutar svara (till exempel en fjärrserver kraschar) är det enda sättet att identifiera sådana situationer med Oönskad PONG att vara beroende av TCP-timeouten.
.NET 9 introducerade den önskade PING/PONG- Keep-Alive-strategin och kompletterade den befintliga inställningen för KeepAliveInterval med den nya inställningen KeepAliveTimeout. Från och med .NET 9 väljs Keep-Alive strategi på följande sätt:
- Keep-Alive är OFF, om
-
KeepAliveIntervalärTimeSpan.ZeroellerTimeout.InfiniteTimeSpan
-
-
Oönskad PONG, om
-
KeepAliveIntervalär en positiv ändligTimeSpan, -AND- -
KeepAliveTimeoutärTimeSpan.ZeroellerTimeout.InfiniteTimeSpan
-
-
PING/PONG, om
-
KeepAliveIntervalär en positiv ändligTimeSpan, -AND- -
KeepAliveTimeoutär en positiv ändligTimeSpan
-
Standardvärdet KeepAliveTimeout är Timeout.InfiniteTimeSpan, så standardbeteendet för Keep-Alive förblir konsekvent mellan .NET-versioner.
Om du använder ClientWebSocketär standardvärdet ClientWebSocketOptions.KeepAliveIntervalWebSocket.DefaultKeepAliveInterval (vanligtvis 30 sekunder). Det innebär att ClientWebSocket har Keep-Alive PÅ som standard, med Oönskad PONG som standardstrategi.
Om du vill växla till PING/PONG-strategin räcker det med att åsidosätta ClientWebSocketOptions.KeepAliveTimeout:
var ws = new ClientWebSocket();
ws.Options.KeepAliveTimeout = TimeSpan.FromSeconds(20);
await ws.ConnectAsync(uri, cts.Token);
För en grundläggande WebSocketär Keep-Alive AV som standard. Om du vill använda PING/PONG-strategin måste både WebSocketCreationOptions.KeepAliveInterval och WebSocketCreationOptions.KeepAliveTimeout anges:
var options = new WebSocketCreationOptions()
{
KeepAliveInterval = WebSocket.DefaultKeepAliveInterval,
KeepAliveTimeout = TimeSpan.FromSeconds(20)
};
var ws = WebSocket.CreateFromStream(stream, options);
Om den oönskade PONG-strategin används används PONG-ramar som en enkelriktad pulsslag. De skickas regelbundet med KeepAliveInterval intervall, oavsett om fjärrslutpunkten kommunicerar eller inte.
Om PING/PONG-strategin är aktiv skickas en PING-ram efter KeepAliveInterval tid har gått sedan den senaste kommunikationen från fjärrslutpunkten. Varje PING-ram innehåller en heltalstoken som ska kopplas till det förväntade PONG-svaret. Om inget PONG-svar kom efter att KeepAliveTimeout förflutit anses fjärrslutpunkten inte svara och WebSocket-anslutningen avbryts automatiskt.
var ws = new ClientWebSocket();
ws.Options.KeepAliveInterval = TimeSpan.FromSeconds(10);
ws.Options.KeepAliveTimeout = TimeSpan.FromSeconds(10);
await ws.ConnectAsync(uri, cts.Token);
// NOTE: There must be an outstanding read at all times to ensure
// incoming PONGs are processed
var result = await _webSocket.ReceiveAsync(buffer, cts.Token);
Om tidsgränsen förflutit ut utlöser en enastående ReceiveAsync en OperationCanceledException:
System.OperationCanceledException: Aborted
---> System.AggregateException: One or more errors occurred. (The WebSocket didn't receive a Pong frame in response to a Ping frame within the configured KeepAliveTimeout.) (Unable to read data from the transport connection: The I/O operation has been aborted because of either a thread exit or an application request..)
---> System.Net.WebSockets.WebSocketException (0x80004005): The WebSocket didn't receive a Pong frame in response to a Ping frame within the configured KeepAliveTimeout.
at System.Net.WebSockets.ManagedWebSocket.KeepAlivePingHeartBeat()
...
Fortsätt läsa för att bearbeta PONG:er
Not
För närvarande bearbetar WebSocket ENDAST inkommande bildrutor medan en ReceiveAsync väntar.
Viktig
Om du vill använda Keep-Alive timeout är det viktigt att PONG-svar bearbetas snabbt. Även om fjärrslutpunkten är vid liv och skickar PONG-svaret korrekt, kan ändå WebSocket inte bearbeta de inkommande bildrutorna, och mekanismen Keep-Alive kan utfärda en "falsk positiv" abort. Det här problemet kan inträffa om PONG-ramen aldrig plockas upp från transportströmmen innan timeouten har gått ut.
För att undvika att ta bort bra anslutningar rekommenderar vi att användarna behåller en väntande läsning på alla WebSockets som har Keep-Alive timeout konfigurerad.