Podpora webSocketů v ASP.NET Core

Tento článek vysvětluje, jak začít s webSockety v ASP.NET Core. WebSocket (RFC 6455) je protokol, který umožňuje obousměrné trvalé komunikační kanály přes připojení TCP. Používá se v aplikacích, které využívají rychlou komunikaci v reálném čase, jako je chat, řídicí panel a herní aplikace.

Zobrazení nebo stažení vzorového kódu (postup stažení, spuštění)

Podpora protokolu Http/2 WebSocket

Použití webSocketů přes PROTOKOL HTTP/2 využívá nové funkce, jako jsou:

  • Komprese hlaviček.
  • Multiplexing, což zkracuje čas a prostředky potřebné při provádění více požadavků na server.

Tyto podporované funkce jsou dostupné na Kestrel všech platformách s podporou HTTP/2. Vyjednávání verzí je v prohlížečích automatické, Kestreltakže nejsou potřeba žádná nová rozhraní API.

.NET 7 zavedl websockety přes http/2 podporu , KestrelSignalR javascriptového klienta a SignalR s Blazor WebAssembly.

Poznámka:

Protokoly WEBSocket HTTP/2 místo get používají požadavky CONNECT, takže možná bude potřeba aktualizovat vlastní trasy a kontrolery. Další informace naleznete v tématu Přidání podpory protokolu HTTP/2 WebSockets pro existující kontrolery v tomto článku.

Chrome a Edge mají ve výchozím nastavení povolené protokoly WebSocket HTTP/2 a můžete ho povolit v FireFoxu about:config na stránce s příznakem network.http.spdy.websockets .

WebSockety byly původně navrženy pro HTTP/1.1, ale od té doby byly upraveny tak, aby fungovaly přes HTTP/2. (RFC 8441)

SignalR

ASP.NET Core SignalR je knihovna, která zjednodušuje přidávání webových funkcí v reálném čase do aplikací. Používá webSockety, kdykoli je to možné.

Pro většinu aplikací doporučujeme SignalR spíše než nezpracované webSockety. SignalR:

  • Poskytuje záložní přenos pro prostředí, kde webSockety nejsou k dispozici.
  • Poskytuje základní model aplikace volání vzdálené procedury.
  • Nemá žádnou významnou nevýhodu výkonu ve srovnání s používáním nezpracovaných webSocketů ve většině scénářů.

Protokoly WebSocket přes HTTP/2 jsou podporované pro:

  • ASP.NET Core SignalR JavaScript client
  • ASP.NET Core SignalR s Blazor WebAssembly

U některých aplikací poskytuje gRPC v .NET alternativu k webSocketům.

Požadavky

  • Jakýkoli operační systém, který podporuje ASP.NET Core:
    • Windows 7 / Windows Server 2008 nebo novější
    • Linux
    • macOS
  • Pokud aplikace běží ve Windows se službou IIS:
    • Windows 8 / Windows Server 2012 nebo novější
    • IIS 8 / IIS 8 Express
    • Musí být povolené protokoly WebSocket. Viz část podpory SLUŽBY IIS/IIS Express.
  • Pokud aplikace běží na HTTP.sys:
    • Windows 8 / Windows Server 2012 nebo novější
  • Podporované prohlížeče najdete v části Můžu použít.

Konfigurace middlewaru

Přidejte middleware WebSockets v Program.cs:

app.UseWebSockets();

Můžete nakonfigurovat následující nastavení:

  • KeepAliveInterval – Jak často odesílat rámce ping klientovi, aby proxy servery zůstaly otevřené. Výchozí hodnota je dvě minuty.
  • AllowedOrigins – Seznam povolených hodnot hlavičky Origin pro požadavky WebSocket. Ve výchozím nastavení jsou povoleny všechny zdroje. Další informace naleznete v tématu Omezení původu protokolu WebSocket v tomto článku.
var webSocketOptions = new WebSocketOptions
{
    KeepAliveInterval = TimeSpan.FromMinutes(2)
};

app.UseWebSockets(webSocketOptions);

Přijetí požadavků Protokolu WebSocket

Někde později v životním cyklu požadavku (později v Program.cs metodě akce nebo v metodě akce) zkontrolujte, jestli se jedná o požadavek WebSocket, a přijměte požadavek WebSocket.

Následující příklad pochází z pozdějšího příkladu Program.cs:

app.Use(async (context, next) =>
{
    if (context.Request.Path == "/ws")
    {
        if (context.WebSockets.IsWebSocketRequest)
        {
            using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
            await Echo(webSocket);
        }
        else
        {
            context.Response.StatusCode = StatusCodes.Status400BadRequest;
        }
    }
    else
    {
        await next(context);
    }

});

Požadavek WebSocket může přijít na libovolnou adresu URL, ale tento vzorový kód přijímá pouze požadavky na /ws.

Podobný přístup lze provést v metodě kontroleru:

public class WebSocketController : ControllerBase
{
    [Route("/ws")]
    public async Task Get()
    {
        if (HttpContext.WebSockets.IsWebSocketRequest)
        {
            using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
            await Echo(webSocket);
        }
        else
        {
            HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
        }
    }

Při použití protokolu WebSocket je nutné ponechat kanál middlewaru spuštěný po dobu trvání připojení. Pokud se pokusíte odeslat nebo přijmout zprávu WebSocket po ukončení kanálu middlewaru, může se zobrazit výjimka podobná této:

System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake. ---> System.ObjectDisposedException: Cannot write to the response body, the response has completed.
Object name: 'HttpResponseStream'.

Pokud k zápisu dat do protokolu WebSocket používáte službu na pozadí, ujistěte se, že je spuštěný kanál middlewaru. Udělejte to pomocí .TaskCompletionSource<TResult> TaskCompletionSource Předejte službu na pozadí a až skončíte s webSocketem, zavolejte TrySetResult ji. Task Pak await vlastnost během požadavku, jak je znázorněno v následujícím příkladu:

app.Run(async (context) =>
{
    using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
    var socketFinishedTcs = new TaskCompletionSource<object>();

    BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);

    await socketFinishedTcs.Task;
});

Uzavřená výjimka WebSocket může také nastat při vrácení příliš brzy z metody akce. Při přijetí soketu v metodě akce počkejte, než se kód, který používá soket, dokončit, než se vrátí z metody akce.

Nikdy nepoužívejte Task.Wait, Task.Resultnebo podobné blokovací volání čekat na dokončení soketu, protože to může způsobit vážné problémy s vlákny. Vždy používejte await.

Přidání podpory protokolu HTTP/2 WebSocket pro existující kontrolery

.NET 7 zavedl websockety přes http/2 podporu , KestrelSignalR javascriptového klienta a SignalR s Blazor WebAssembly. Protokoly HTTP/2 WebSocket místo get používají požadavky CONNECT. Pokud jste dříve použili [HttpGet("/path")] metodu akce kontroleru pro požadavky Websocket, aktualizujte ji, aby se místo toho používala [Route("/path")] .

public class WebSocketController : ControllerBase
{
    [Route("/ws")]
    public async Task Get()
    {
        if (HttpContext.WebSockets.IsWebSocketRequest)
        {
            using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
            await Echo(webSocket);
        }
        else
        {
            HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
        }
    }

Komprese

Upozorňující

Povolení komprese přes šifrovaná připojení může aplikaci podléhat CRIMEútokům neboBREACH útokům. Pokud odesíláte citlivé informace, vyhněte se povolení komprese nebo použití WebSocketMessageFlags.DisableCompression při volání WebSocket.SendAsync. To platí pro obě strany protokolu WebSocket. Všimněte si, že rozhraní API WebSockets v prohlížeči nemá konfiguraci pro zakázání komprese na odeslání.

Pokud je požadovaná komprese zpráv přes WebSockets, pak musí přijmout kód určit, že umožňuje kompresi následujícím způsobem:

using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(
    new WebSocketAcceptContext { DangerousEnableCompression = true }))
{

}

WebSocketAcceptContext.ServerMaxWindowBits a WebSocketAcceptContext.DisableServerContextTakeover jsou pokročilé možnosti, které řídí, jak komprese funguje.

Komprese se vyjednává mezi klientem a serverem při prvním navázání připojení. Další informace o vyjednávání najdete v dokumentu RFC Komprese rozšíření pro WebSocket.

Poznámka:

Pokud není vyjednávání komprese přijato serverem nebo klientem, připojení je stále navázáno. Připojení ale při odesílání a příjmu zpráv nepoužívá kompresi.

Odesílání a příjem zpráv

Metoda AcceptWebSocketAsync upgraduje připojení TCP na připojení WebSocket a poskytuje WebSocket objekt. Pomocí objektu WebSocket můžete odesílat a přijímat zprávy.

Kód uvedený dříve, který přijímá požadavek WebSocket předá WebSocket objekt metodě Echo . Kód obdrží zprávu a okamžitě odešle stejnou zprávu. Zprávy se odesílají a přijímají ve smyčce, dokud klient připojení nezavře:

private static async Task Echo(WebSocket webSocket)
{
    var buffer = new byte[1024 * 4];
    var receiveResult = await webSocket.ReceiveAsync(
        new ArraySegment<byte>(buffer), CancellationToken.None);

    while (!receiveResult.CloseStatus.HasValue)
    {
        await webSocket.SendAsync(
            new ArraySegment<byte>(buffer, 0, receiveResult.Count),
            receiveResult.MessageType,
            receiveResult.EndOfMessage,
            CancellationToken.None);

        receiveResult = await webSocket.ReceiveAsync(
            new ArraySegment<byte>(buffer), CancellationToken.None);
    }

    await webSocket.CloseAsync(
        receiveResult.CloseStatus.Value,
        receiveResult.CloseStatusDescription,
        CancellationToken.None);
}

Při přijetí připojení WebSocket před zahájením smyčky končí kanál middlewaru. Po zavření soketu se kanál odvíjí. To znamená, že požadavek po přijetí protokolu WebSocket přestane v kanálu pokračovat. Po dokončení smyčky a zavření soketu požadavek zálohuje kanál.

Zpracování odpojení klienta

Server není automaticky informován, když se klient odpojí kvůli ztrátě připojení. Server obdrží zprávu o odpojení jenom v případě, že ho klient odešle, což se nedá udělat, pokud dojde ke ztrátě připojení k internetu. Pokud chcete provést nějakou akci, když k tomu dojde, nastavte časový limit po přijetí nic z klienta v určitém časovém intervalu.

Pokud klient neodesílá zprávy vždy a nechcete vypršení časového limitu časového limitu jenom proto, že připojení probíhá nečinně, požádejte klienta, aby k odeslání zprávy ping každých X sekund používal časovač. Pokud na serveru nepřišela zpráva do 2*X sekund od předchozího, ukončete připojení a nahlašte, že se klient odpojil. Počkejte dvakrát očekávaný časový interval, aby se kvůli zpožděním sítě, která by mohla obsahovat zprávu ping, vynechejte další čas.

Omezení původu protokolu WebSocket

Ochrana poskytovaná CORS se nevztahuje na webSockety. Prohlížeče:

  • Proveďte předběžné žádosti CORS.
  • Při vytváření požadavků WebSocket respektujte omezení zadaná v Access-Control hlavicích.

Prohlížeče však posílají hlavičku Origin při vydávání požadavků WebSocket. Aplikace by měly být nakonfigurované tak, aby ověřily tyto hlavičky, aby se zajistilo, že jsou povoleny pouze protokoly WebSocket pocházející z očekávaných zdrojů.

Pokud hostujete server na "https://server.com" a hostování klienta na "https://client.com", přidejte "https://client.com" AllowedOrigins na seznam pro webSocket k ověření.

var webSocketOptions = new WebSocketOptions
{
    KeepAliveInterval = TimeSpan.FromMinutes(2)
};

webSocketOptions.AllowedOrigins.Add("https://client.com");
webSocketOptions.AllowedOrigins.Add("https://www.client.com");

app.UseWebSockets(webSocketOptions);

Poznámka:

Hlavička Origin je řízena klientem a podobně jako hlavička Referer může být falešně napodobena. Nepoužívejte tyto hlavičky jako ověřovací mechanismus.

Podpora služby IIS/IIS Express

Windows Server 2012 nebo novější a Windows 8 nebo novější se službou IIS/IIS Express 8 nebo novějším má podporu protokolu WebSocket, ale ne pro protokol WebSocket přes HTTP/2.

Poznámka:

Při používání služby IIS Express jsou protokoly WebSocket vždy povolené.

Povolení webSocketů ve službě IIS

Povolení podpory protokolu WebSocket ve Windows Serveru 2012 nebo novějším:

Poznámka:

Při používání služby IIS Express se tyto kroky nevyžadují.

  1. Použijte průvodce přidáním rolí a funkcí z nabídky Správa nebo odkazu ve Správci serveru.
  2. Vyberte instalaci založenou na rolích nebo funkci. Vyberte Další.
  3. Vyberte příslušný server (ve výchozím nastavení je vybraný místní server). Vyberte Další.
  4. Ve stromu Role rozbalte webový server (IIS), rozbalte webový server a poté rozbalte položku Vývoj aplikací.
  5. Vyberte protokol WebSocket. Vyberte Další.
  6. Pokud nejsou potřeba další funkce, vyberte Další.
  7. Vyberte volbu Instalovat.
  8. Po dokončení instalace ukončete průvodce výběrem možnosti Zavřít .

Povolení podpory protokolu WebSocket ve Windows 8 nebo novějším:

Poznámka:

Při používání služby IIS Express se tyto kroky nevyžadují.

  1. Přejděte do části Ovládací panely>Programy>Programy a funkce>Zapnout nebo vypnout funkce systému Windows (na levé straně obrazovky).
  2. Otevřete následující uzly: Internetová informační služba> Funkce vývoje aplikací webové službyWorld>Wide.
  3. Vyberte funkci Protokol WebSocket. Vyberte OK.

Zakázání protokolu WebSocket při použití socket.io na Node.js

Pokud používáte podporu Protokolu WebSocket v socket.io na Node.js, zakažte výchozí modul IIS WebSocket pomocí elementu webSocket web.config nebo applicationHost.config. Pokud tento krok neproběhne, modul IIS WebSocket se pokusí zpracovat komunikaci WebSocket místo Node.js a aplikace.

<system.webServer>
  <webSocket enabled="false" />
</system.webServer>

Ukázková aplikace

Ukázková aplikace, která doprovází tento článek, je aplikace echo. Má webovou stránku, která zajišťuje připojení WebSocket a server znovu odešle všechny zprávy, které obdrží zpět klientovi. Ukázková aplikace podporuje webSockety přes HTTP/2 při použití cílové architektury .NET 7 nebo novější.

Spuštění aplikace:

  • Spuštění aplikace v sadě Visual Studio: Otevřete ukázkový projekt v sadě Visual Studio a stisknutím kombinace kláves Ctrl+F5 spusťte bez ladicího programu.
  • Spuštění aplikace v příkazovém prostředí: Spusťte příkaz dotnet run a přejděte v prohlížeči na http://localhost:<port>.

Na webové stránce se zobrazuje stav připojení:

Počáteční stav webové stránky před připojením WebSockets

Výběrem Připojení odešlete požadavek WebSocket na zobrazenou adresu URL. Zadejte testovací zprávu a vyberte Odeslat. Až budete hotovi, vyberte Zavřít soket. Oddíl Komunikační protokol hlásí každou otevřenou, odesílanou a zavřenou akci, jak se stane.

Konečný stav webové stránky po odeslání a přijetí testovacích zpráv webSocket

Tento článek vysvětluje, jak začít s webSockety v ASP.NET Core. WebSocket (RFC 6455) je protokol, který umožňuje obousměrné trvalé komunikační kanály přes připojení TCP. Používá se v aplikacích, které využívají rychlou komunikaci v reálném čase, jako je chat, řídicí panel a herní aplikace.

Zobrazení nebo stažení vzorového kódu (postup stažení, spuštění)

Podpora protokolu Http/2 WebSocket

Použití webSocketů přes PROTOKOL HTTP/2 využívá nové funkce, jako jsou:

  • Komprese hlaviček.
  • Multiplexing, což zkracuje čas a prostředky potřebné při provádění více požadavků na server.

Tyto podporované funkce jsou dostupné na Kestrel všech platformách s podporou HTTP/2. Vyjednávání verzí je v prohlížečích automatické, Kestreltakže nejsou potřeba žádná nová rozhraní API.

.NET 7 zavedl websockety přes http/2 podporu , KestrelSignalR javascriptového klienta a SignalR s Blazor WebAssembly.

Poznámka:

Protokoly WEBSocket HTTP/2 místo get používají požadavky CONNECT, takže možná bude potřeba aktualizovat vlastní trasy a kontrolery. Další informace naleznete v tématu Přidání podpory protokolu HTTP/2 WebSockets pro existující kontrolery v tomto článku.

Chrome a Edge mají ve výchozím nastavení povolené protokoly WebSocket HTTP/2 a můžete ho povolit v FireFoxu about:config na stránce s příznakem network.http.spdy.websockets .

WebSockety byly původně navrženy pro HTTP/1.1, ale od té doby byly upraveny tak, aby fungovaly přes HTTP/2. (RFC 8441)

SignalR

ASP.NET Core SignalR je knihovna, která zjednodušuje přidávání webových funkcí v reálném čase do aplikací. Používá webSockety, kdykoli je to možné.

Pro většinu aplikací doporučujeme SignalR spíše než nezpracované webSockety. SignalR:

  • Poskytuje záložní přenos pro prostředí, kde webSockety nejsou k dispozici.
  • Poskytuje základní model aplikace volání vzdálené procedury.
  • Nemá žádnou významnou nevýhodu výkonu ve srovnání s používáním nezpracovaných webSocketů ve většině scénářů.

Protokoly WebSocket přes HTTP/2 jsou podporované pro:

  • ASP.NET Core SignalR JavaScript client
  • ASP.NET Core SignalR s Blazor WebAssembly

U některých aplikací poskytuje gRPC v .NET alternativu k webSocketům.

Požadavky

  • Jakýkoli operační systém, který podporuje ASP.NET Core:
    • Windows 7 / Windows Server 2008 nebo novější
    • Linux
    • macOS
  • Pokud aplikace běží ve Windows se službou IIS:
    • Windows 8 / Windows Server 2012 nebo novější
    • IIS 8 / IIS 8 Express
    • Musí být povolené protokoly WebSocket. Viz část podpory SLUŽBY IIS/IIS Express.
  • Pokud aplikace běží na HTTP.sys:
    • Windows 8 / Windows Server 2012 nebo novější
  • Podporované prohlížeče najdete v části Můžu použít.

Konfigurace middlewaru

Přidejte middleware WebSockets v Program.cs:

app.UseWebSockets();

Můžete nakonfigurovat následující nastavení:

  • KeepAliveInterval – Jak často odesílat rámce ping klientovi, aby proxy servery zůstaly otevřené. Výchozí hodnota je dvě minuty.
  • AllowedOrigins – Seznam povolených hodnot hlavičky Origin pro požadavky WebSocket. Ve výchozím nastavení jsou povoleny všechny zdroje. Další informace naleznete v tématu Omezení původu protokolu WebSocket v tomto článku.
var webSocketOptions = new WebSocketOptions
{
    KeepAliveInterval = TimeSpan.FromMinutes(2)
};

app.UseWebSockets(webSocketOptions);

Přijetí požadavků Protokolu WebSocket

Někde později v životním cyklu požadavku (později v Program.cs metodě akce nebo v metodě akce) zkontrolujte, jestli se jedná o požadavek WebSocket, a přijměte požadavek WebSocket.

Následující příklad pochází z pozdějšího příkladu Program.cs:

app.Use(async (context, next) =>
{
    if (context.Request.Path == "/ws")
    {
        if (context.WebSockets.IsWebSocketRequest)
        {
            using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
            await Echo(webSocket);
        }
        else
        {
            context.Response.StatusCode = StatusCodes.Status400BadRequest;
        }
    }
    else
    {
        await next(context);
    }

});

Požadavek WebSocket může přijít na libovolnou adresu URL, ale tento vzorový kód přijímá pouze požadavky na /ws.

Podobný přístup lze provést v metodě kontroleru:

public class WebSocketController : ControllerBase
{
    [Route("/ws")]
    public async Task Get()
    {
        if (HttpContext.WebSockets.IsWebSocketRequest)
        {
            using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
            await Echo(webSocket);
        }
        else
        {
            HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
        }
    }

Při použití protokolu WebSocket je nutné ponechat kanál middlewaru spuštěný po dobu trvání připojení. Pokud se pokusíte odeslat nebo přijmout zprávu WebSocket po ukončení kanálu middlewaru, může se zobrazit výjimka podobná této:

System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake. ---> System.ObjectDisposedException: Cannot write to the response body, the response has completed.
Object name: 'HttpResponseStream'.

Pokud k zápisu dat do protokolu WebSocket používáte službu na pozadí, ujistěte se, že je spuštěný kanál middlewaru. Udělejte to pomocí .TaskCompletionSource<TResult> TaskCompletionSource Předejte službu na pozadí a až skončíte s webSocketem, zavolejte TrySetResult ji. Task Pak await vlastnost během požadavku, jak je znázorněno v následujícím příkladu:

app.Run(async (context) =>
{
    using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
    var socketFinishedTcs = new TaskCompletionSource<object>();

    BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);

    await socketFinishedTcs.Task;
});

Uzavřená výjimka WebSocket může také nastat při vrácení příliš brzy z metody akce. Při přijetí soketu v metodě akce počkejte, než se kód, který používá soket, dokončit, než se vrátí z metody akce.

Nikdy nepoužívejte Task.Wait, Task.Resultnebo podobné blokovací volání čekat na dokončení soketu, protože to může způsobit vážné problémy s vlákny. Vždy používejte await.

Přidání podpory protokolu HTTP/2 WebSocket pro existující kontrolery

.NET 7 zavedl websockety přes http/2 podporu , KestrelSignalR javascriptového klienta a SignalR s Blazor WebAssembly. Protokoly HTTP/2 WebSocket místo get používají požadavky CONNECT. Pokud jste dříve použili [HttpGet("/path")] metodu akce kontroleru pro požadavky Websocket, aktualizujte ji, aby se místo toho používala [Route("/path")] .

public class WebSocketController : ControllerBase
{
    [Route("/ws")]
    public async Task Get()
    {
        if (HttpContext.WebSockets.IsWebSocketRequest)
        {
            using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
            await Echo(webSocket);
        }
        else
        {
            HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
        }
    }

Komprese

Upozorňující

Povolení komprese přes šifrovaná připojení může aplikaci podléhat CRIMEútokům neboBREACH útokům. Pokud odesíláte citlivé informace, vyhněte se povolení komprese nebo použití WebSocketMessageFlags.DisableCompression při volání WebSocket.SendAsync. To platí pro obě strany protokolu WebSocket. Všimněte si, že rozhraní API WebSockets v prohlížeči nemá konfiguraci pro zakázání komprese na odeslání.

Pokud je požadovaná komprese zpráv přes WebSockets, pak musí přijmout kód určit, že umožňuje kompresi následujícím způsobem:

using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(
    new WebSocketAcceptContext { DangerousEnableCompression = true }))
{

}

WebSocketAcceptContext.ServerMaxWindowBits a WebSocketAcceptContext.DisableServerContextTakeover jsou pokročilé možnosti, které řídí, jak komprese funguje.

Komprese se vyjednává mezi klientem a serverem při prvním navázání připojení. Další informace o vyjednávání najdete v dokumentu RFC Komprese rozšíření pro WebSocket.

Poznámka:

Pokud není vyjednávání komprese přijato serverem nebo klientem, připojení je stále navázáno. Připojení ale při odesílání a příjmu zpráv nepoužívá kompresi.

Odesílání a příjem zpráv

Metoda AcceptWebSocketAsync upgraduje připojení TCP na připojení WebSocket a poskytuje WebSocket objekt. Pomocí objektu WebSocket můžete odesílat a přijímat zprávy.

Kód uvedený dříve, který přijímá požadavek WebSocket předá WebSocket objekt metodě Echo . Kód obdrží zprávu a okamžitě odešle stejnou zprávu. Zprávy se odesílají a přijímají ve smyčce, dokud klient připojení nezavře:

private static async Task Echo(WebSocket webSocket)
{
    var buffer = new byte[1024 * 4];
    var receiveResult = await webSocket.ReceiveAsync(
        new ArraySegment<byte>(buffer), CancellationToken.None);

    while (!receiveResult.CloseStatus.HasValue)
    {
        await webSocket.SendAsync(
            new ArraySegment<byte>(buffer, 0, receiveResult.Count),
            receiveResult.MessageType,
            receiveResult.EndOfMessage,
            CancellationToken.None);

        receiveResult = await webSocket.ReceiveAsync(
            new ArraySegment<byte>(buffer), CancellationToken.None);
    }

    await webSocket.CloseAsync(
        receiveResult.CloseStatus.Value,
        receiveResult.CloseStatusDescription,
        CancellationToken.None);
}

Při přijetí připojení WebSocket před zahájením smyčky končí kanál middlewaru. Po zavření soketu se kanál odvíjí. To znamená, že požadavek po přijetí protokolu WebSocket přestane v kanálu pokračovat. Po dokončení smyčky a zavření soketu požadavek zálohuje kanál.

Zpracování odpojení klienta

Server není automaticky informován, když se klient odpojí kvůli ztrátě připojení. Server obdrží zprávu o odpojení jenom v případě, že ho klient odešle, což se nedá udělat, pokud dojde ke ztrátě připojení k internetu. Pokud chcete provést nějakou akci, když k tomu dojde, nastavte časový limit po přijetí nic z klienta v určitém časovém intervalu.

Pokud klient neodesílá zprávy vždy a nechcete vypršení časového limitu časového limitu jenom proto, že připojení probíhá nečinně, požádejte klienta, aby k odeslání zprávy ping každých X sekund používal časovač. Pokud na serveru nepřišela zpráva do 2*X sekund od předchozího, ukončete připojení a nahlašte, že se klient odpojil. Počkejte dvakrát očekávaný časový interval, aby se kvůli zpožděním sítě, která by mohla obsahovat zprávu ping, vynechejte další čas.

Omezení původu protokolu WebSocket

Ochrana poskytovaná CORS se nevztahuje na webSockety. Prohlížeče:

  • Proveďte předběžné žádosti CORS.
  • Při vytváření požadavků WebSocket respektujte omezení zadaná v Access-Control hlavicích.

Prohlížeče však posílají hlavičku Origin při vydávání požadavků WebSocket. Aplikace by měly být nakonfigurované tak, aby ověřily tyto hlavičky, aby se zajistilo, že jsou povoleny pouze protokoly WebSocket pocházející z očekávaných zdrojů.

Pokud hostujete server na "https://server.com" a hostování klienta na "https://client.com", přidejte "https://client.com" AllowedOrigins na seznam pro webSocket k ověření.

var webSocketOptions = new WebSocketOptions
{
    KeepAliveInterval = TimeSpan.FromMinutes(2)
};

webSocketOptions.AllowedOrigins.Add("https://client.com");
webSocketOptions.AllowedOrigins.Add("https://www.client.com");

app.UseWebSockets(webSocketOptions);

Poznámka:

Hlavička Origin je řízena klientem a podobně jako hlavička Referer může být falešně napodobena. Nepoužívejte tyto hlavičky jako ověřovací mechanismus.

Podpora služby IIS/IIS Express

Windows Server 2012 nebo novější a Windows 8 nebo novější se službou IIS/IIS Express 8 nebo novějším má podporu protokolu WebSocket, ale ne pro protokol WebSocket přes HTTP/2.

Poznámka:

Při používání služby IIS Express jsou protokoly WebSocket vždy povolené.

Povolení webSocketů ve službě IIS

Povolení podpory protokolu WebSocket ve Windows Serveru 2012 nebo novějším:

Poznámka:

Při používání služby IIS Express se tyto kroky nevyžadují.

  1. Použijte průvodce přidáním rolí a funkcí z nabídky Správa nebo odkazu ve Správci serveru.
  2. Vyberte instalaci založenou na rolích nebo funkci. Vyberte Další.
  3. Vyberte příslušný server (ve výchozím nastavení je vybraný místní server). Vyberte Další.
  4. Ve stromu Role rozbalte webový server (IIS), rozbalte webový server a poté rozbalte položku Vývoj aplikací.
  5. Vyberte protokol WebSocket. Vyberte Další.
  6. Pokud nejsou potřeba další funkce, vyberte Další.
  7. Vyberte volbu Instalovat.
  8. Po dokončení instalace ukončete průvodce výběrem možnosti Zavřít .

Povolení podpory protokolu WebSocket ve Windows 8 nebo novějším:

Poznámka:

Při používání služby IIS Express se tyto kroky nevyžadují.

  1. Přejděte do části Ovládací panely>Programy>Programy a funkce>Zapnout nebo vypnout funkce systému Windows (na levé straně obrazovky).
  2. Otevřete následující uzly: Internetová informační služba> Funkce vývoje aplikací webové službyWorld>Wide.
  3. Vyberte funkci Protokol WebSocket. Vyberte OK.

Zakázání protokolu WebSocket při použití socket.io na Node.js

Pokud používáte podporu Protokolu WebSocket v socket.io na Node.js, zakažte výchozí modul IIS WebSocket pomocí elementu webSocket web.config nebo applicationHost.config. Pokud tento krok neproběhne, modul IIS WebSocket se pokusí zpracovat komunikaci WebSocket místo Node.js a aplikace.

<system.webServer>
  <webSocket enabled="false" />
</system.webServer>

Ukázková aplikace

Ukázková aplikace, která doprovází tento článek, je aplikace echo. Má webovou stránku, která zajišťuje připojení WebSocket a server znovu odešle všechny zprávy, které obdrží zpět klientovi. Ukázková aplikace podporuje webSockety přes HTTP/2 při použití cílové architektury .NET 7 nebo novější.

Spuštění aplikace:

  • Spuštění aplikace v sadě Visual Studio: Otevřete ukázkový projekt v sadě Visual Studio a stisknutím kombinace kláves Ctrl+F5 spusťte bez ladicího programu.
  • Spuštění aplikace v příkazovém prostředí: Spusťte příkaz dotnet run a přejděte v prohlížeči na http://localhost:<port>.

Na webové stránce se zobrazuje stav připojení:

Počáteční stav webové stránky před připojením WebSockets

Výběrem Připojení odešlete požadavek WebSocket na zobrazenou adresu URL. Zadejte testovací zprávu a vyberte Odeslat. Až budete hotovi, vyberte Zavřít soket. Oddíl Komunikační protokol hlásí každou otevřenou, odesílanou a zavřenou akci, jak se stane.

Konečný stav webové stránky po odeslání a přijetí testovacích zpráv webSocket

Tento článek vysvětluje, jak začít s webSockety v ASP.NET Core. WebSocket (RFC 6455) je protokol, který umožňuje obousměrné trvalé komunikační kanály přes připojení TCP. Používá se v aplikacích, které využívají rychlou komunikaci v reálném čase, jako je chat, řídicí panel a herní aplikace.

Zobrazení nebo stažení vzorového kódu (postup stažení, spuštění)

SignalR

ASP.NET Core SignalR je knihovna, která zjednodušuje přidávání webových funkcí v reálném čase do aplikací. Používá webSockety, kdykoli je to možné.

Pro většinu aplikací doporučujeme SignalR používat nezpracované webSockety. SignalR poskytuje záložní přenos pro prostředí, kde webSockets není k dispozici. Poskytuje také základní model aplikace vzdáleného volání procedur. Ve většině scénářů nemá ve většině scénářů SignalR žádnou významnou nevýhodu výkonu oproti použití nezpracovaných webSocketů.

U některých aplikací poskytuje gRPC v .NET alternativu k webSocketům.

Požadavky

  • Jakýkoli operační systém, který podporuje ASP.NET Core:
    • Windows 7 / Windows Server 2008 nebo novější
    • Linux
    • macOS
  • Pokud aplikace běží ve Windows se službou IIS:
    • Windows 8 / Windows Server 2012 nebo novější
    • IIS 8 / IIS 8 Express
    • Musí být povolené protokoly WebSocket. Viz část podpory SLUŽBY IIS/IIS Express.
  • Pokud aplikace běží na HTTP.sys:
    • Windows 8 / Windows Server 2012 nebo novější
  • Podporované prohlížeče najdete v části Můžu použít.

Konfigurace middlewaru

Přidejte middleware WebSockets v Program.cs:

app.UseWebSockets();

Můžete nakonfigurovat následující nastavení:

  • KeepAliveInterval – Jak často odesílat rámce ping klientovi, aby proxy servery zůstaly otevřené. Výchozí hodnota je dvě minuty.
  • AllowedOrigins – Seznam povolených hodnot hlavičky Origin pro požadavky WebSocket. Ve výchozím nastavení jsou povoleny všechny zdroje. Další informace naleznete v tématu Omezení původu protokolu WebSocket v tomto článku.
var webSocketOptions = new WebSocketOptions
{
    KeepAliveInterval = TimeSpan.FromMinutes(2)
};

app.UseWebSockets(webSocketOptions);

Přijetí požadavků Protokolu WebSocket

Někde později v životním cyklu požadavku (později v Program.cs metodě akce nebo v metodě akce) zkontrolujte, jestli se jedná o požadavek WebSocket, a přijměte požadavek WebSocket.

Následující příklad pochází z pozdějšího příkladu Program.cs:

app.Use(async (context, next) =>
{
    if (context.Request.Path == "/ws")
    {
        if (context.WebSockets.IsWebSocketRequest)
        {
            using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
            await Echo(webSocket);
        }
        else
        {
            context.Response.StatusCode = StatusCodes.Status400BadRequest;
        }
    }
    else
    {
        await next(context);
    }

});

Požadavek WebSocket může přijít na libovolnou adresu URL, ale tento vzorový kód přijímá pouze požadavky na /ws.

Podobný přístup lze provést v metodě kontroleru:

public class WebSocketController : ControllerBase
{
    [HttpGet("/ws")]
    public async Task Get()
    {
        if (HttpContext.WebSockets.IsWebSocketRequest)
        {
            using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
            await Echo(webSocket);
        }
        else
        {
            HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
        }
    }

Při použití protokolu WebSocket je nutné ponechat kanál middlewaru spuštěný po dobu trvání připojení. Pokud se pokusíte odeslat nebo přijmout zprávu WebSocket po ukončení kanálu middlewaru, může se zobrazit výjimka podobná této:

System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake. ---> System.ObjectDisposedException: Cannot write to the response body, the response has completed.
Object name: 'HttpResponseStream'.

Pokud k zápisu dat do protokolu WebSocket používáte službu na pozadí, ujistěte se, že je spuštěný kanál middlewaru. Udělejte to pomocí .TaskCompletionSource<TResult> TaskCompletionSource Předejte službu na pozadí a až skončíte s webSocketem, zavolejte TrySetResult ji. Task Pak await vlastnost během požadavku, jak je znázorněno v následujícím příkladu:

app.Run(async (context) =>
{
    using var webSocket = await context.WebSockets.AcceptWebSocketAsync();
    var socketFinishedTcs = new TaskCompletionSource<object>();

    BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);

    await socketFinishedTcs.Task;
});

Uzavřená výjimka WebSocket může také nastat při vrácení příliš brzy z metody akce. Při přijetí soketu v metodě akce počkejte, než se kód, který používá soket, dokončit, než se vrátí z metody akce.

Nikdy nepoužívejte Task.Wait, Task.Resultnebo podobné blokovací volání čekat na dokončení soketu, protože to může způsobit vážné problémy s vlákny. Vždy používejte await.

Komprese

Upozorňující

Povolení komprese přes šifrovaná připojení může aplikaci podléhat CRIMEútokům neboBREACH útokům. Pokud odesíláte citlivé informace, vyhněte se povolení komprese nebo použití WebSocketMessageFlags.DisableCompression při volání WebSocket.SendAsync. To platí pro obě strany protokolu WebSocket. Všimněte si, že rozhraní API WebSockets v prohlížeči nemá konfiguraci pro zakázání komprese na odeslání.

Pokud je požadovaná komprese zpráv přes WebSockets, pak musí přijmout kód určit, že umožňuje kompresi následujícím způsobem:

using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(
    new WebSocketAcceptContext { DangerousEnableCompression = true }))
{

}

WebSocketAcceptContext.ServerMaxWindowBits a WebSocketAcceptContext.DisableServerContextTakeover jsou pokročilé možnosti, které řídí, jak komprese funguje.

Komprese se vyjednává mezi klientem a serverem při prvním navázání připojení. Další informace o vyjednávání najdete v dokumentu RFC Komprese rozšíření pro WebSocket.

Poznámka:

Pokud není vyjednávání komprese přijato serverem nebo klientem, připojení je stále navázáno. Připojení ale při odesílání a příjmu zpráv nepoužívá kompresi.

Odesílání a příjem zpráv

Metoda AcceptWebSocketAsync upgraduje připojení TCP na připojení WebSocket a poskytuje WebSocket objekt. Pomocí objektu WebSocket můžete odesílat a přijímat zprávy.

Kód uvedený dříve, který přijímá požadavek WebSocket předá WebSocket objekt metodě Echo . Kód obdrží zprávu a okamžitě odešle stejnou zprávu. Zprávy se odesílají a přijímají ve smyčce, dokud klient připojení nezavře:

private static async Task Echo(WebSocket webSocket)
{
    var buffer = new byte[1024 * 4];
    var receiveResult = await webSocket.ReceiveAsync(
        new ArraySegment<byte>(buffer), CancellationToken.None);

    while (!receiveResult.CloseStatus.HasValue)
    {
        await webSocket.SendAsync(
            new ArraySegment<byte>(buffer, 0, receiveResult.Count),
            receiveResult.MessageType,
            receiveResult.EndOfMessage,
            CancellationToken.None);

        receiveResult = await webSocket.ReceiveAsync(
            new ArraySegment<byte>(buffer), CancellationToken.None);
    }

    await webSocket.CloseAsync(
        receiveResult.CloseStatus.Value,
        receiveResult.CloseStatusDescription,
        CancellationToken.None);
}

Při přijetí připojení WebSocket před zahájením smyčky končí kanál middlewaru. Po zavření soketu se kanál odvíjí. To znamená, že požadavek po přijetí protokolu WebSocket přestane v kanálu pokračovat. Po dokončení smyčky a zavření soketu požadavek zálohuje kanál.

Zpracování odpojení klienta

Server není automaticky informován, když se klient odpojí kvůli ztrátě připojení. Server obdrží zprávu o odpojení jenom v případě, že ho klient odešle, což se nedá udělat, pokud dojde ke ztrátě připojení k internetu. Pokud chcete provést nějakou akci, když k tomu dojde, nastavte časový limit po přijetí nic z klienta v určitém časovém intervalu.

Pokud klient neodesílá zprávy vždy a nechcete vypršení časového limitu časového limitu jenom proto, že připojení probíhá nečinně, požádejte klienta, aby k odeslání zprávy ping každých X sekund používal časovač. Pokud na serveru nepřišela zpráva do 2*X sekund od předchozího, ukončete připojení a nahlašte, že se klient odpojil. Počkejte dvakrát očekávaný časový interval, aby se kvůli zpožděním sítě, která by mohla obsahovat zprávu ping, vynechejte další čas.

Omezení původu protokolu WebSocket

Ochrana poskytovaná CORS se nevztahuje na webSockety. Prohlížeče:

  • Proveďte předběžné žádosti CORS.
  • Při vytváření požadavků WebSocket respektujte omezení zadaná v Access-Control hlavicích.

Prohlížeče však posílají hlavičku Origin při vydávání požadavků WebSocket. Aplikace by měly být nakonfigurované tak, aby ověřily tyto hlavičky, aby se zajistilo, že jsou povoleny pouze protokoly WebSocket pocházející z očekávaných zdrojů.

Pokud hostujete server na "https://server.com" a hostování klienta na "https://client.com", přidejte "https://client.com" AllowedOrigins na seznam pro webSocket k ověření.

var webSocketOptions = new WebSocketOptions
{
    KeepAliveInterval = TimeSpan.FromMinutes(2)
};

webSocketOptions.AllowedOrigins.Add("https://client.com");
webSocketOptions.AllowedOrigins.Add("https://www.client.com");

app.UseWebSockets(webSocketOptions);

Poznámka:

Hlavička Origin je řízena klientem a podobně jako hlavička Referer může být falešně napodobena. Nepoužívejte tyto hlavičky jako ověřovací mechanismus.

Podpora služby IIS/IIS Express

Windows Server 2012 nebo novější a Windows 8 nebo novější se službou IIS/IIS Express 8 nebo novějším má podporu protokolu WebSocket.

Poznámka:

Při používání služby IIS Express jsou protokoly WebSocket vždy povolené.

Povolení webSocketů ve službě IIS

Povolení podpory protokolu WebSocket ve Windows Serveru 2012 nebo novějším:

Poznámka:

Při používání služby IIS Express se tyto kroky nevyžadují.

  1. Použijte průvodce přidáním rolí a funkcí z nabídky Správa nebo odkazu ve Správci serveru.
  2. Vyberte instalaci založenou na rolích nebo funkci. Vyberte Další.
  3. Vyberte příslušný server (ve výchozím nastavení je vybraný místní server). Vyberte Další.
  4. Ve stromu Role rozbalte webový server (IIS), rozbalte webový server a poté rozbalte položku Vývoj aplikací.
  5. Vyberte protokol WebSocket. Vyberte Další.
  6. Pokud nejsou potřeba další funkce, vyberte Další.
  7. Vyberte volbu Instalovat.
  8. Po dokončení instalace ukončete průvodce výběrem možnosti Zavřít .

Povolení podpory protokolu WebSocket ve Windows 8 nebo novějším:

Poznámka:

Při používání služby IIS Express se tyto kroky nevyžadují.

  1. Přejděte do části Ovládací panely>Programy>Programy a funkce>Zapnout nebo vypnout funkce systému Windows (na levé straně obrazovky).
  2. Otevřete následující uzly: Internetová informační služba> Funkce vývoje aplikací webové službyWorld>Wide.
  3. Vyberte funkci Protokol WebSocket. Vyberte OK.

Zakázání protokolu WebSocket při použití socket.io na Node.js

Pokud používáte podporu Protokolu WebSocket v socket.io na Node.js, zakažte výchozí modul IIS WebSocket pomocí elementu webSocket web.config nebo applicationHost.config. Pokud tento krok neproběhne, modul IIS WebSocket se pokusí zpracovat komunikaci WebSocket místo Node.js a aplikace.

<system.webServer>
  <webSocket enabled="false" />
</system.webServer>

Ukázková aplikace

Ukázková aplikace, která doprovází tento článek, je aplikace echo. Má webovou stránku, která zajišťuje připojení WebSocket a server znovu odešle všechny zprávy, které obdrží zpět klientovi. Ukázková aplikace není nakonfigurovaná tak, aby běžela ze sady Visual Studio se službou IIS Express, takže aplikaci spusťte v příkazovém prostředí s dotnet run prohlížečem a přejděte do http://localhost:<port>prohlížeče. Na webové stránce se zobrazuje stav připojení:

Počáteční stav webové stránky před připojením WebSockets

Výběrem Připojení odešlete požadavek WebSocket na zobrazenou adresu URL. Zadejte testovací zprávu a vyberte Odeslat. Až budete hotovi, vyberte Zavřít soket. Oddíl Komunikační protokol hlásí každou otevřenou, odesílanou a zavřenou akci, jak se stane.

Konečný stav webové stránky po odeslání a přijetí testovacích zpráv webSocket

Tento článek vysvětluje, jak začít s webSockety v ASP.NET Core. WebSocket (RFC 6455) je protokol, který umožňuje obousměrné trvalé komunikační kanály přes připojení TCP. Používá se v aplikacích, které využívají rychlou komunikaci v reálném čase, jako je chat, řídicí panel a herní aplikace.

Zobrazení nebo stažení vzorového kódu (postup stažení) Postup spuštění

SignalR

ASP.NET Core SignalR je knihovna, která zjednodušuje přidávání webových funkcí v reálném čase do aplikací. Používá webSockety, kdykoli je to možné.

Pro většinu aplikací doporučujeme SignalR používat nezpracované webSockety. SignalR poskytuje záložní přenos pro prostředí, kde webSockets není k dispozici. Poskytuje také základní model aplikace vzdáleného volání procedur. Ve většině scénářů nemá ve většině scénářů SignalR žádnou významnou nevýhodu výkonu oproti použití nezpracovaných webSocketů.

U některých aplikací poskytuje gRPC v .NET alternativu k webSocketům.

Požadavky

  • Jakýkoli operační systém, který podporuje ASP.NET Core:
    • Windows 7 / Windows Server 2008 nebo novější
    • Linux
    • macOS
  • Pokud aplikace běží ve Windows se službou IIS:
    • Windows 8 / Windows Server 2012 nebo novější
    • IIS 8 / IIS 8 Express
    • Musí být povolené protokoly WebSocket. Viz část podpory SLUŽBY IIS/IIS Express.
  • Pokud aplikace běží na HTTP.sys:
    • Windows 8 / Windows Server 2012 nebo novější
  • Podporované prohlížeče najdete v části Můžu použít.

Konfigurace middlewaru

Přidejte middleware WebSockets v Configure metodě Startup třídy:

app.UseWebSockets();

Poznámka:

Chcete-li přijmout požadavky WebSocket v kontroleru, musí dojít k app.UseWebSockets volání před app.UseEndpoints.

Můžete nakonfigurovat následující nastavení:

  • KeepAliveInterval – Jak často odesílat rámce ping klientovi, aby proxy servery zůstaly otevřené. Výchozí hodnota je dvě minuty.
  • AllowedOrigins – Seznam povolených hodnot hlavičky Origin pro požadavky WebSocket. Ve výchozím nastavení jsou povoleny všechny zdroje. Podrobnosti najdete níže v části Omezení původu protokolu WebSocket.
var webSocketOptions = new WebSocketOptions()
{
    KeepAliveInterval = TimeSpan.FromSeconds(120),
};

app.UseWebSockets(webSocketOptions);

Přijetí požadavků Protokolu WebSocket

Někde později v životním cyklu požadavku (později v Configure metodě nebo v metodě akce), zkontrolujte, jestli se jedná o požadavek WebSocket, a přijměte požadavek WebSocket.

Následující příklad pochází z pozdější metody Configure :

app.Use(async (context, next) =>
{
    if (context.Request.Path == "/ws")
    {
        if (context.WebSockets.IsWebSocketRequest)
        {
            using (WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync())
            {
                await Echo(context, webSocket);
            }
        }
        else
        {
            context.Response.StatusCode = (int) HttpStatusCode.BadRequest;
        }
    }
    else
    {
        await next();
    }

});

Požadavek WebSocket může přijít na libovolnou adresu URL, ale tento vzorový kód přijímá pouze požadavky na /ws.

Podobný přístup lze provést v metodě kontroleru:

public class WebSocketController : ControllerBase
{
    [HttpGet("/ws")]
    public async Task Get()
    {
        if (HttpContext.WebSockets.IsWebSocketRequest)
        {
            using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
            await Echo(webSocket);
        }
        else
        {
            HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
        }
    }

Při použití protokolu WebSocket je nutné ponechat kanál middlewaru spuštěný po dobu trvání připojení. Pokud se pokusíte odeslat nebo přijmout zprávu WebSocket po ukončení kanálu middlewaru, může se zobrazit výjimka podobná této:

System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close handshake. ---> System.ObjectDisposedException: Cannot write to the response body, the response has completed.
Object name: 'HttpResponseStream'.

Pokud k zápisu dat do protokolu WebSocket používáte službu na pozadí, ujistěte se, že je spuštěný kanál middlewaru. Udělejte to pomocí .TaskCompletionSource<TResult> TaskCompletionSource Předejte službu na pozadí a až skončíte s webSocketem, zavolejte TrySetResult ji. Task Pak await vlastnost během požadavku, jak je znázorněno v následujícím příkladu:

app.Use(async (context, next) =>
{
    using (WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync())
    {
        var socketFinishedTcs = new TaskCompletionSource<object>();

        BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);

        await socketFinishedTcs.Task;
    }
});

Uzavřená výjimka WebSocket může také nastat při vrácení příliš brzy z metody akce. Při přijetí soketu v metodě akce počkejte, než se kód, který používá soket, dokončit, než se vrátí z metody akce.

Nikdy nepoužívejte Task.Wait, Task.Resultnebo podobné blokovací volání čekat na dokončení soketu, protože to může způsobit vážné problémy s vlákny. Vždy používejte await.

Odesílání a příjem zpráv

Metoda AcceptWebSocketAsync upgraduje připojení TCP na připojení WebSocket a poskytuje WebSocket objekt. Pomocí objektu WebSocket můžete odesílat a přijímat zprávy.

Kód uvedený dříve, který přijímá požadavek WebSocket předá WebSocket objekt metodě Echo . Kód obdrží zprávu a okamžitě odešle stejnou zprávu. Zprávy se odesílají a přijímají ve smyčce, dokud klient připojení nezavře:

private async Task Echo(HttpContext context, WebSocket webSocket)
{
    var buffer = new byte[1024 * 4];
    WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
    while (!result.CloseStatus.HasValue)
    {
        await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType, result.EndOfMessage, CancellationToken.None);

        result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
    }
    await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
}

Při přijetí připojení WebSocket před zahájením smyčky končí kanál middlewaru. Po zavření soketu se kanál odvíjí. To znamená, že požadavek po přijetí protokolu WebSocket přestane v kanálu pokračovat. Po dokončení smyčky a zavření soketu požadavek zálohuje kanál.

Zpracování odpojení klienta

Server není automaticky informován, když se klient odpojí kvůli ztrátě připojení. Server obdrží zprávu o odpojení jenom v případě, že ho klient odešle, což se nedá udělat, pokud dojde ke ztrátě připojení k internetu. Pokud chcete provést nějakou akci, když k tomu dojde, nastavte časový limit po přijetí nic z klienta v určitém časovém intervalu.

Pokud klient neodesílá zprávy vždy a nechcete vypršení časového limitu časového limitu jenom proto, že připojení probíhá nečinně, požádejte klienta, aby k odeslání zprávy ping každých X sekund používal časovač. Pokud na serveru nepřišela zpráva do 2*X sekund od předchozího, ukončete připojení a nahlašte, že se klient odpojil. Počkejte dvakrát očekávaný časový interval, aby se kvůli zpožděním sítě, která by mohla obsahovat zprávu ping, vynechejte další čas.

Poznámka:

Interní ManagedWebSocket zpracovává rámce Ping/Pong implicitně, aby připojení zůstalo aktivní, pokud KeepAliveInterval je možnost větší než nula, což je výchozí hodnota 30 sekund (TimeSpan.FromSeconds(30)).

Omezení původu protokolu WebSocket

Ochrana poskytovaná CORS se nevztahuje na webSockety. Prohlížeče:

  • Proveďte předběžné žádosti CORS.
  • Při vytváření požadavků WebSocket respektujte omezení zadaná v Access-Control hlavicích.

Prohlížeče však posílají hlavičku Origin při vydávání požadavků WebSocket. Aplikace by měly být nakonfigurované tak, aby ověřily tyto hlavičky, aby se zajistilo, že jsou povoleny pouze protokoly WebSocket pocházející z očekávaných zdrojů.

Pokud hostujete server na "https://server.com" a hostování klienta na "https://client.com", přidejte "https://client.com" AllowedOrigins na seznam pro webSocket k ověření.

var webSocketOptions = new WebSocketOptions()
{
    KeepAliveInterval = TimeSpan.FromSeconds(120),
};
webSocketOptions.AllowedOrigins.Add("https://client.com");
webSocketOptions.AllowedOrigins.Add("https://www.client.com");

app.UseWebSockets(webSocketOptions);

Poznámka:

Hlavička Origin je řízena klientem a podobně jako hlavička Referer může být falešně napodobena. Nepoužívejte tyto hlavičky jako ověřovací mechanismus.

Podpora služby IIS/IIS Express

Windows Server 2012 nebo novější a Windows 8 nebo novější se službou IIS/IIS Express 8 nebo novějším má podporu protokolu WebSocket.

Poznámka:

Při používání služby IIS Express jsou protokoly WebSocket vždy povolené.

Povolení webSocketů ve službě IIS

Povolení podpory protokolu WebSocket ve Windows Serveru 2012 nebo novějším:

Poznámka:

Při používání služby IIS Express se tyto kroky nevyžadují.

  1. Použijte průvodce přidáním rolí a funkcí z nabídky Správa nebo odkazu ve Správci serveru.
  2. Vyberte instalaci založenou na rolích nebo funkci. Vyberte Další.
  3. Vyberte příslušný server (ve výchozím nastavení je vybraný místní server). Vyberte Další.
  4. Ve stromu Role rozbalte webový server (IIS), rozbalte webový server a poté rozbalte položku Vývoj aplikací.
  5. Vyberte protokol WebSocket. Vyberte Další.
  6. Pokud nejsou potřeba další funkce, vyberte Další.
  7. Vyberte volbu Instalovat.
  8. Po dokončení instalace ukončete průvodce výběrem možnosti Zavřít .

Povolení podpory protokolu WebSocket ve Windows 8 nebo novějším:

Poznámka:

Při používání služby IIS Express se tyto kroky nevyžadují.

  1. Přejděte do části Ovládací panely>Programy>Programy a funkce>Zapnout nebo vypnout funkce systému Windows (na levé straně obrazovky).
  2. Otevřete následující uzly: Internetová informační služba> Funkce vývoje aplikací webové službyWorld>Wide.
  3. Vyberte funkci Protokol WebSocket. Vyberte OK.

Zakázání protokolu WebSocket při použití socket.io na Node.js

Pokud používáte podporu Protokolu WebSocket v socket.io na Node.js, zakažte výchozí modul IIS WebSocket pomocí elementu webSocket web.config nebo applicationHost.config. Pokud tento krok neproběhne, modul IIS WebSocket se pokusí zpracovat komunikaci WebSocket místo Node.js a aplikace.

<system.webServer>
  <webSocket enabled="false" />
</system.webServer>

Ukázková aplikace

Ukázková aplikace, která doprovází tento článek, je aplikace echo. Má webovou stránku, která zajišťuje připojení WebSocket a server znovu odešle všechny zprávy, které obdrží zpět klientovi. Ukázková aplikace není nakonfigurovaná tak, aby běžela ze sady Visual Studio se službou IIS Express, takže aplikaci spusťte v příkazovém prostředí s dotnet run prohlížečem a přejděte do http://localhost:5000prohlížeče. Na webové stránce se zobrazuje stav připojení:

Počáteční stav webové stránky před připojením WebSockets

Výběrem Připojení odešlete požadavek WebSocket na zobrazenou adresu URL. Zadejte testovací zprávu a vyberte Odeslat. Až budete hotovi, vyberte Zavřít soket. Oddíl Komunikační protokol hlásí každou otevřenou, odesílanou a zavřenou akci, jak se stane.

Konečný stav webové stránky po odeslání a přijetí testovacích zpráv webSocket