ASP.NET Core'da WebSockets desteği

Bu makalede, ASP.NET Core'da WebSockets ile çalışmaya başlama açıklanmaktadır. WebSocket (RFC 6455), TCP bağlantıları üzerinden iki yönlü kalıcı iletişim kanalları sağlayan bir protokoldür. Sohbet, pano ve oyun uygulamaları gibi hızlı, gerçek zamanlı iletişimden yararlanan uygulamalarda kullanılır.

Örnek kodu görüntüleme veya indirme (indirme, çalıştırma).

Http/2 WebSockets desteği

HTTP/2 üzerinden WebSockets kullanmak aşağıdaki gibi yeni özelliklerden yararlanır:

  • Üst bilgi sıkıştırma.
  • Sunucuya birden çok istekte bulunurken gereken süreyi ve kaynakları azaltan çoğullama.

Bu desteklenen özellikler tüm HTTP/2 özellikli platformlarda Kestrel kullanılabilir. Sürüm anlaşması tarayıcılarda ve Kestrel'de otomatiktir, bu nedenle yeni API'ler gerekmez.

.NET 7, SignalR ile, Blazor WebAssemblyJavaScript istemcisi ve SignalR için KestrelHTTP/2 desteği üzerinden Websockets'i kullanıma sunar.

Not

HTTP/2 WebSockets GET yerine CONNECT isteklerini kullanır, bu nedenle kendi yollarınızın ve denetleyicilerinizin güncelleştirilmesi gerekebilir. Daha fazla bilgi için bu makaledeki Mevcut denetleyiciler için HTTP/2 WebSockets desteği ekleme konusuna bakın.

Chrome ve Edge'de HTTP/2 WebSockets varsayılan olarak etkindir ve bunu bayrağıyla birlikte network.http.spdy.websockets sayfadaki FireFox'ta about:config etkinleştirebilirsiniz.

WebSockets başlangıçta HTTP/1.1 için tasarlanmıştır ancak o zamandan beri HTTP/2 üzerinde çalışacak şekilde uyarlanmıştır. (RFC 8441)

SignalR

ASP.NET Core SignalR , uygulamalara gerçek zamanlı web işlevselliği eklemeyi kolaylaştıran bir kitaplıktır. Mümkün olduğunda WebSockets kullanır.

Çoğu uygulama için ham WebSockets yerine önerilir SignalR . SignalR:

  • WebSockets'in kullanılamadığı ortamlar için aktarım geri dönüşünü sağlar.
  • Temel bir uzaktan yordam çağrısı uygulama modeli sağlar.
  • Çoğu senaryoda ham WebSockets kullanımıyla karşılaştırıldığında önemli bir performans dezavantajı yoktur.

HTTP/2 üzerinden WebSockets aşağıdakiler için desteklenir:

  • ASP.NET Core SignalR JavaScript istemcisi
  • ile ASP.NET Core SignalRBlazor WebAssembly

Bazı uygulamalar için.NET üzerindeki gRPC, WebSockets'e bir alternatif sağlar.

Önkoşullar

  • ASP.NET Core'u destekleyen tüm işletim sistemi:
    • Windows 7 / Windows Server 2008 veya üzeri
    • Linux
    • macOS
  • Uygulama IIS ile Windows üzerinde çalışıyorsa:
    • Windows 8 / Windows Server 2012 veya üzeri
    • IIS 8 / IIS 8 Express
    • WebSockets etkinleştirilmelidir. IIS/IIS Express desteği bölümüne bakın.
  • Uygulama HTTP.sys üzerinde çalışıyorsa:
    • Windows 8 / Windows Server 2012 veya üzeri
  • Desteklenen tarayıcılar için bkz . Kullanabilir miyim?

Ara yazılımı yapılandırma

içinde WebSockets ara yazılımını Program.csekleyin:

app.UseWebSockets();

Aşağıdaki ayarlar yapılandırılabilir:

  • KeepAliveInterval - Proxy'lerin bağlantıyı açık tutmasını sağlamak için istemciye "ping" çerçeveleri gönderme sıklığı. Varsayılan değer iki dakikadır.
  • AllowedOrigins - WebSocket istekleri için izin verilen Kaynak üst bilgi değerlerinin listesi. Varsayılan olarak tüm çıkış noktalarına izin verilir. Daha fazla bilgi için bu makaledeki WebSocket kaynak kısıtlaması bölümüne bakın.
var webSocketOptions = new WebSocketOptions
{
    KeepAliveInterval = TimeSpan.FromMinutes(2)
};

app.UseWebSockets(webSocketOptions);

WebSocket isteklerini kabul etme

İstek yaşam döngüsünün sonraki bölümlerinde (örneğin, daha sonraki bir işlem yönteminde Program.cs ) bunun bir WebSocket isteği olup olmadığını denetleyin ve WebSocket isteğini kabul edin.

Aşağıdaki örnek, içinde daha sonra verilmiştir 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);
    }

});

WebSocket isteği herhangi bir URL'de gelebilir, ancak bu örnek kod yalnızca için /wsistekleri kabul eder.

Benzer bir yaklaşım bir denetleyici yönteminde de ele alınabilir:

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;
        }
    }

WebSocket kullanırken, bağlantı süresi boyunca ara yazılım işlem hattını çalışır durumda tutmanız gerekir . Ara yazılım işlem hattı sona erdikten sonra WebSocket iletisi göndermeye veya almaya çalışırsanız, aşağıdaki gibi bir özel durumla karşılaşabilirsiniz:

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'.

WebSocket'e veri yazmak için arka plan hizmeti kullanıyorsanız ara yazılım işlem hattını çalışır durumda tuttuğunuzdan emin olun. Bunu bir TaskCompletionSource<TResult>kullanarak yapın. TaskCompletionSource öğesini arka plan hizmetinize geçirin ve WebSocket ile bitirdiğinizde aramasını TrySetResult sağlayın. Task Ardındanawait, aşağıdaki örnekte gösterildiği gibi istek sırasında özelliği:

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

    BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);

    await socketFinishedTcs.Task;
});

WebSocket kapalı özel durumu, bir eylem yönteminden çok erken geri dönerken de oluşabilir. Eylem yönteminde yuva kabul ederken, eylem yönteminden dönmeden önce yuvayı kullanan kodun tamamlanmasını bekleyin.

Önemli iş parçacığı sorunlarına neden olabileceğinden, yuvanın tamamlanmasını beklemek için hiçbir zaman , Task.Resultveya benzer engelleme çağrıları kullanmayınTask.Wait. Her zaman kullanın await.

Mevcut denetleyiciler için HTTP/2 WebSockets desteği ekleme

.NET 7, SignalR ile, Blazor WebAssemblyJavaScript istemcisi ve SignalR için KestrelHTTP/2 desteği üzerinden Websockets'i kullanıma sunar. HTTP/2 WebSockets GET yerine CONNECT isteklerini kullanır. Daha önce Websocket istekleri için denetleyici eylem yönteminizde kullandıysanız [HttpGet("/path")] , bunu kullanmak [Route("/path")] üzere güncelleştirin.

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;
        }
    }

Sıkıştırma

Uyarı

Şifrelenmiş bağlantılar üzerinden sıkıştırmanın etkinleştirilmesi, bir uygulamanın /BREACH saldırılara CRIMEtabi olmasını sağlayabilir. Hassas bilgiler gönderiyorsanız, sıkıştırmayı etkinleştirmekten veya çağrısı WebSocket.SendAsyncyaparken kullanmaktan WebSocketMessageFlags.DisableCompression kaçının. Bu, WebSocket'in her iki tarafı için de geçerlidir. Tarayıcıdaki WebSockets API'sinin gönderme başına sıkıştırmayı devre dışı bırakmak için yapılandırması olmadığını unutmayın.

İletilerin WebSockets üzerinden sıkıştırması isteniyorsa, kabul kodu aşağıdaki gibi sıkıştırmaya izin verdiği belirtmelidir:

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

}

WebSocketAcceptContext.ServerMaxWindowBits ve WebSocketAcceptContext.DisableServerContextTakeover sıkıştırmanın nasıl çalıştığını denetleen gelişmiş seçeneklerdir.

İlk bağlantı kurulurken istemci ile sunucu arasında sıkıştırma anlaşması yapılır. Anlaşma hakkında daha fazla bilgi için bkz. WebSocket RFC için Sıkıştırma Uzantıları.

Not

Sıkıştırma anlaşması sunucu veya istemci tarafından kabul edilirse, bağlantı yine de kurulur. Ancak, bağlantı iletileri gönderirken ve alırken sıkıştırma kullanmaz.

İleti alma ve gönderme

yöntemi TCP AcceptWebSocketAsync bağlantısını bir WebSocket bağlantısına yükselterek bir WebSocket nesne sağlar. WebSocket İleti göndermek ve almak için nesnesini kullanın.

WebSocket isteğini kabul eden daha önce gösterilen kod, nesnesini bir Echo yönteme geçirirWebSocket. Kod bir ileti alır ve hemen aynı iletiyi geri gönderir. İstemci bağlantıyı kapatana kadar iletiler bir döngü içinde gönderilir ve alınır:

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);
}

Döngüye başlamadan önce WebSocket bağlantısını kabul ederken ara yazılım işlem hattı sona erer. Yuva kapatılmaya devam ettikten sonra işlem hattı gevşer. Başka bir ifadeyle, WebSocket kabul edildiğinde istek işlem hattında ilerlemeyi durdurur. Döngü tamamlandığında ve yuva kapatıldığında istek işlem hattını yedekler.

İstemci bağlantısının kesilmesini işleme

Bağlantı kaybı nedeniyle istemcinin bağlantısı kesildiğinde sunucu otomatik olarak bilgilendirilir. Sunucu yalnızca istemci gönderirse bir bağlantı kesme iletisi alır ve bu işlem İnternet bağlantısı kesilirse yapılamaz. Böyle bir durumda işlem yapmak istiyorsanız, istemciden belirli bir zaman penceresi içinde hiçbir şey alınmadığında bir zaman aşımı ayarlayın.

İstemci her zaman ileti göndermiyorsa ve bağlantı boşta olduğu için zaman aşımına uğradıysanız, istemcinin her X saniyede bir ping iletisi göndermek için zamanlayıcı kullanmasını sağlayın. Sunucuda, bir ileti öncekinden sonraki 2*X saniye içinde gelmediyse bağlantıyı sonlandırın ve istemcinin bağlantısının kesildiğini bildirin. Ping iletisini tutabilecek ağ gecikmelerinde fazladan süre bırakmak için beklenen zaman aralığının iki katı kadar bekleyin.

WebSocket kaynak kısıtlaması

CORS tarafından sağlanan korumalar WebSockets için geçerli değildir. Tarayıcılar aşağıdakileri yapmaz:

  • CORS uçuş öncesi istekleri gerçekleştirin.
  • WebSocket istekleri yaparken üst bilgilerde Access-Control belirtilen kısıtlamalara uyun.

Ancak tarayıcılar WebSocket istekleri gönderirken üst bilgiyi gönderir Origin . Uygulamalar, yalnızca beklenen kaynaklardan gelen WebSockets'e izin verildiğinden emin olmak için bu üst bilgileri doğrulayacak şekilde yapılandırılmalıdır.

Sunucunuzu "https://server.com" ve istemcinizi "https://client.com", "https://client.com" webSockets'in AllowedOrigins doğrulanması için listeye gidin.

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

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

app.UseWebSockets(webSocketOptions);

Not

Üst Origin bilgi istemci tarafından denetlenebilir ve üst bilgi gibi Referer sahte olabilir. Bu üst bilgileri kimlik doğrulama mekanizması olarak kullanmayın.

IIS/IIS Express desteği

Windows Server 2012 veya sonraki sürümleri ve IIS/IIS Express 8 veya üzeri yüklü Windows 8 veya sonraki sürümlerin WebSocket protokolü desteği vardır, ancak HTTP/2 üzerinden WebSockets için desteklenmez.

Not

WebSockets, IIS Express kullanılırken her zaman etkinleştirilir.

IIS'de WebSockets'i etkinleştirme

Windows Server 2012 veya sonraki sürümlerde WebSocket protokolü desteğini etkinleştirmek için:

Not

IIS Express kullanılırken bu adımlar gerekli değildir

  1. Yönet menüsünden Rol ve Özellik Ekle sihirbazını veya Sunucu Yöneticisi'ndeki bağlantıyı kullanın.
  2. Rol Tabanlı veya Özellik Tabanlı Yükleme'yi seçin. İleri'yi seçin.
  3. Uygun sunucuyu seçin (yerel sunucu varsayılan olarak seçilidir). İleri'yi seçin.
  4. Roller ağacında Web Sunucusu'nu (IIS) genişletin, Web Sunucusu'nu genişletin ve ardından Uygulama Geliştirme'yi genişletin.
  5. WebSocket Protokolü'ne tıklayın. İleri'yi seçin.
  6. Ek özellikler gerekmiyorsa İleri'yi seçin.
  7. Yükle'yi seçin.
  8. Yükleme tamamlandığında, sihirbazdan çıkmak için Kapat'ı seçin.

Windows 8 veya sonraki sürümlerde WebSocket protokolü desteğini etkinleştirmek için:

Not

IIS Express kullanılırken bu adımlar gerekli değildir

  1. Denetim Masası>Programlar>Programlar ve Özellikler> gidinWindows özelliklerini aç veya kapat seçeneğine gidin (ekranın sol tarafında).
  2. Şu düğümleri açın: Internet Information Services>World Wide Web Services>Uygulama Geliştirme Özellikleri.
  3. WebSocket Protokolü özelliğini seçin. Tamam'ı seçin.

Node.js'da socket.io kullanırken WebSocket'i devre dışı bırakma

Node.js socket.io'de WebSocket desteğini kullanıyorsanız, web.config veya applicationHost.config içindeki öğesini kullanarak varsayılan IIS WebSocket modülünü webSocket devre dışı bırakın. Bu adım gerçekleştirilmezse, IIS WebSocket modülü Node.js ve uygulama yerine WebSocket iletişimini işlemeye çalışır.

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

Örnek uygulama

Bu makaleye eşlik eden örnek uygulama bir yankı uygulamasıdır. WebSocket bağlantılarını yapan bir web sayfası vardır ve sunucu aldığı tüm iletileri istemciye yeniden gönderir. Örnek uygulama, hedeflenen .NET 7 veya üzeri bir çerçeve kullanılırken HTTP/2 üzerinden WebSockets'i destekler.

Uygulamayı çalıştırın:

  • Uygulamayı Visual Studio'da çalıştırmak için: Örnek projeyi Visual Studio'da açın ve hata ayıklayıcı olmadan çalıştırmak için Ctrl+F5 tuşlarına basın.
  • Uygulamayı komut kabuğunda çalıştırmak için: komutunu dotnet run çalıştırın ve tarayıcıda adresine http://localhost:<port>gidin.

Web sayfası bağlantı durumunu gösterir:

WebSockets bağlantısından önceki web sayfasının ilk durumu

Gösterilen URL'ye WebSocket isteği göndermek için Bağlan seçin. Bir test iletisi girin ve Gönder'i seçin. İşiniz bittiğinde Yuvayı Kapat'ı seçin. İletişim Günlüğü bölümü, her bir açma, gönderme ve kapatma eylemini olduğu gibi bildirir.

WebSockets bağlantısı ve test iletileri gönderilip alındıktan sonra web sayfasının son durumu

Bu makalede, ASP.NET Core'da WebSockets ile çalışmaya başlama açıklanmaktadır. WebSocket (RFC 6455), TCP bağlantıları üzerinden iki yönlü kalıcı iletişim kanalları sağlayan bir protokoldür. Sohbet, pano ve oyun uygulamaları gibi hızlı, gerçek zamanlı iletişimden yararlanan uygulamalarda kullanılır.

Örnek kodu görüntüleme veya indirme (indirme, çalıştırma).

Http/2 WebSockets desteği

HTTP/2 üzerinden WebSockets kullanmak aşağıdaki gibi yeni özelliklerden yararlanır:

  • Üst bilgi sıkıştırma.
  • Sunucuya birden çok istekte bulunurken gereken süreyi ve kaynakları azaltan çoğullama.

Bu desteklenen özellikler tüm HTTP/2 özellikli platformlarda Kestrel kullanılabilir. Sürüm anlaşması tarayıcılarda ve Kestrel'de otomatiktir, bu nedenle yeni API'ler gerekmez.

.NET 7, SignalR ile, Blazor WebAssemblyJavaScript istemcisi ve SignalR için KestrelHTTP/2 desteği üzerinden Websockets'i kullanıma sunar.

Not

HTTP/2 WebSockets GET yerine CONNECT isteklerini kullanır, bu nedenle kendi yollarınızın ve denetleyicilerinizin güncelleştirilmesi gerekebilir. Daha fazla bilgi için bu makaledeki Mevcut denetleyiciler için HTTP/2 WebSockets desteği ekleme konusuna bakın.

Chrome ve Edge'de HTTP/2 WebSockets varsayılan olarak etkindir ve bunu bayrağıyla birlikte network.http.spdy.websockets sayfadaki FireFox'ta about:config etkinleştirebilirsiniz.

WebSockets başlangıçta HTTP/1.1 için tasarlanmıştır ancak o zamandan beri HTTP/2 üzerinde çalışacak şekilde uyarlanmıştır. (RFC 8441)

SignalR

ASP.NET Core SignalR , uygulamalara gerçek zamanlı web işlevselliği eklemeyi kolaylaştıran bir kitaplıktır. Mümkün olduğunda WebSockets kullanır.

Çoğu uygulama için ham WebSockets yerine önerilir SignalR . SignalR:

  • WebSockets'in kullanılamadığı ortamlar için aktarım geri dönüşünü sağlar.
  • Temel bir uzaktan yordam çağrısı uygulama modeli sağlar.
  • Çoğu senaryoda ham WebSockets kullanımıyla karşılaştırıldığında önemli bir performans dezavantajı yoktur.

HTTP/2 üzerinden WebSockets aşağıdakiler için desteklenir:

  • ASP.NET Core SignalR JavaScript istemcisi
  • ile ASP.NET Core SignalRBlazor WebAssembly

Bazı uygulamalar için.NET üzerindeki gRPC, WebSockets'e bir alternatif sağlar.

Önkoşullar

  • ASP.NET Core'u destekleyen tüm işletim sistemi:
    • Windows 7 / Windows Server 2008 veya üzeri
    • Linux
    • macOS
  • Uygulama IIS ile Windows üzerinde çalışıyorsa:
    • Windows 8 / Windows Server 2012 veya üzeri
    • IIS 8 / IIS 8 Express
    • WebSockets etkinleştirilmelidir. IIS/IIS Express desteği bölümüne bakın.
  • Uygulama HTTP.sys üzerinde çalışıyorsa:
    • Windows 8 / Windows Server 2012 veya üzeri
  • Desteklenen tarayıcılar için bkz . Kullanabilir miyim?

Ara yazılımı yapılandırma

içinde WebSockets ara yazılımını Program.csekleyin:

app.UseWebSockets();

Aşağıdaki ayarlar yapılandırılabilir:

  • KeepAliveInterval - Proxy'lerin bağlantıyı açık tutmasını sağlamak için istemciye "ping" çerçeveleri gönderme sıklığı. Varsayılan değer iki dakikadır.
  • AllowedOrigins - WebSocket istekleri için izin verilen Kaynak üst bilgi değerlerinin listesi. Varsayılan olarak tüm çıkış noktalarına izin verilir. Daha fazla bilgi için bu makaledeki WebSocket kaynak kısıtlaması bölümüne bakın.
var webSocketOptions = new WebSocketOptions
{
    KeepAliveInterval = TimeSpan.FromMinutes(2)
};

app.UseWebSockets(webSocketOptions);

WebSocket isteklerini kabul etme

İstek yaşam döngüsünün sonraki bölümlerinde (örneğin, daha sonraki bir işlem yönteminde Program.cs ) bunun bir WebSocket isteği olup olmadığını denetleyin ve WebSocket isteğini kabul edin.

Aşağıdaki örnek, içinde daha sonra verilmiştir 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);
    }

});

WebSocket isteği herhangi bir URL'de gelebilir, ancak bu örnek kod yalnızca için /wsistekleri kabul eder.

Benzer bir yaklaşım bir denetleyici yönteminde de ele alınabilir:

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;
        }
    }

WebSocket kullanırken, bağlantı süresi boyunca ara yazılım işlem hattını çalışır durumda tutmanız gerekir . Ara yazılım işlem hattı sona erdikten sonra WebSocket iletisi göndermeye veya almaya çalışırsanız, aşağıdaki gibi bir özel durumla karşılaşabilirsiniz:

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'.

WebSocket'e veri yazmak için arka plan hizmeti kullanıyorsanız ara yazılım işlem hattını çalışır durumda tuttuğunuzdan emin olun. Bunu bir TaskCompletionSource<TResult>kullanarak yapın. TaskCompletionSource öğesini arka plan hizmetinize geçirin ve WebSocket ile bitirdiğinizde aramasını TrySetResult sağlayın. Task Ardındanawait, aşağıdaki örnekte gösterildiği gibi istek sırasında özelliği:

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

    BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);

    await socketFinishedTcs.Task;
});

WebSocket kapalı özel durumu, bir eylem yönteminden çok erken geri dönerken de oluşabilir. Eylem yönteminde yuva kabul ederken, eylem yönteminden dönmeden önce yuvayı kullanan kodun tamamlanmasını bekleyin.

Önemli iş parçacığı sorunlarına neden olabileceğinden, yuvanın tamamlanmasını beklemek için hiçbir zaman , Task.Resultveya benzer engelleme çağrıları kullanmayınTask.Wait. Her zaman kullanın await.

Mevcut denetleyiciler için HTTP/2 WebSockets desteği ekleme

.NET 7, SignalR ile, Blazor WebAssemblyJavaScript istemcisi ve SignalR için KestrelHTTP/2 desteği üzerinden Websockets'i kullanıma sunar. HTTP/2 WebSockets GET yerine CONNECT isteklerini kullanır. Daha önce Websocket istekleri için denetleyici eylem yönteminizde kullandıysanız [HttpGet("/path")] , bunu kullanmak [Route("/path")] üzere güncelleştirin.

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;
        }
    }

Sıkıştırma

Uyarı

Şifrelenmiş bağlantılar üzerinden sıkıştırmanın etkinleştirilmesi, bir uygulamanın /BREACH saldırılara CRIMEtabi olmasını sağlayabilir. Hassas bilgiler gönderiyorsanız, sıkıştırmayı etkinleştirmekten veya çağrısı WebSocket.SendAsyncyaparken kullanmaktan WebSocketMessageFlags.DisableCompression kaçının. Bu, WebSocket'in her iki tarafı için de geçerlidir. Tarayıcıdaki WebSockets API'sinin gönderme başına sıkıştırmayı devre dışı bırakmak için yapılandırması olmadığını unutmayın.

İletilerin WebSockets üzerinden sıkıştırması isteniyorsa, kabul kodu aşağıdaki gibi sıkıştırmaya izin verdiği belirtmelidir:

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

}

WebSocketAcceptContext.ServerMaxWindowBits ve WebSocketAcceptContext.DisableServerContextTakeover sıkıştırmanın nasıl çalıştığını denetleen gelişmiş seçeneklerdir.

İlk bağlantı kurulurken istemci ile sunucu arasında sıkıştırma anlaşması yapılır. Anlaşma hakkında daha fazla bilgi için bkz. WebSocket RFC için Sıkıştırma Uzantıları.

Not

Sıkıştırma anlaşması sunucu veya istemci tarafından kabul edilirse, bağlantı yine de kurulur. Ancak, bağlantı iletileri gönderirken ve alırken sıkıştırma kullanmaz.

İleti alma ve gönderme

yöntemi TCP AcceptWebSocketAsync bağlantısını bir WebSocket bağlantısına yükselterek bir WebSocket nesne sağlar. WebSocket İleti göndermek ve almak için nesnesini kullanın.

WebSocket isteğini kabul eden daha önce gösterilen kod, nesnesini bir Echo yönteme geçirirWebSocket. Kod bir ileti alır ve hemen aynı iletiyi geri gönderir. İstemci bağlantıyı kapatana kadar iletiler bir döngü içinde gönderilir ve alınır:

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);
}

Döngüye başlamadan önce WebSocket bağlantısını kabul ederken ara yazılım işlem hattı sona erer. Yuva kapatılmaya devam ettikten sonra işlem hattı gevşer. Başka bir ifadeyle, WebSocket kabul edildiğinde istek işlem hattında ilerlemeyi durdurur. Döngü tamamlandığında ve yuva kapatıldığında istek işlem hattını yedekler.

İstemci bağlantısının kesilmesini işleme

Bağlantı kaybı nedeniyle istemcinin bağlantısı kesildiğinde sunucu otomatik olarak bilgilendirilir. Sunucu yalnızca istemci gönderirse bir bağlantı kesme iletisi alır ve bu işlem İnternet bağlantısı kesilirse yapılamaz. Böyle bir durumda işlem yapmak istiyorsanız, istemciden belirli bir zaman penceresi içinde hiçbir şey alınmadığında bir zaman aşımı ayarlayın.

İstemci her zaman ileti göndermiyorsa ve bağlantı boşta olduğu için zaman aşımına uğradıysanız, istemcinin her X saniyede bir ping iletisi göndermek için zamanlayıcı kullanmasını sağlayın. Sunucuda, bir ileti öncekinden sonraki 2*X saniye içinde gelmediyse bağlantıyı sonlandırın ve istemcinin bağlantısının kesildiğini bildirin. Ping iletisini tutabilecek ağ gecikmelerinde fazladan süre bırakmak için beklenen zaman aralığının iki katı kadar bekleyin.

WebSocket kaynak kısıtlaması

CORS tarafından sağlanan korumalar WebSockets için geçerli değildir. Tarayıcılar aşağıdakileri yapmaz:

  • CORS uçuş öncesi istekleri gerçekleştirin.
  • WebSocket istekleri yaparken üst bilgilerde Access-Control belirtilen kısıtlamalara uyun.

Ancak tarayıcılar WebSocket istekleri gönderirken üst bilgiyi gönderir Origin . Uygulamalar, yalnızca beklenen kaynaklardan gelen WebSockets'e izin verildiğinden emin olmak için bu üst bilgileri doğrulayacak şekilde yapılandırılmalıdır.

Sunucunuzu "https://server.com" ve istemcinizi "https://client.com", "https://client.com" webSockets'in AllowedOrigins doğrulanması için listeye gidin.

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

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

app.UseWebSockets(webSocketOptions);

Not

Üst Origin bilgi istemci tarafından denetlenebilir ve üst bilgi gibi Referer sahte olabilir. Bu üst bilgileri kimlik doğrulama mekanizması olarak kullanmayın.

IIS/IIS Express desteği

Windows Server 2012 veya sonraki sürümleri ve IIS/IIS Express 8 veya üzeri yüklü Windows 8 veya sonraki sürümlerin WebSocket protokolü desteği vardır, ancak HTTP/2 üzerinden WebSockets için desteklenmez.

Not

WebSockets, IIS Express kullanılırken her zaman etkinleştirilir.

IIS'de WebSockets'i etkinleştirme

Windows Server 2012 veya sonraki sürümlerde WebSocket protokolü desteğini etkinleştirmek için:

Not

IIS Express kullanılırken bu adımlar gerekli değildir

  1. Yönet menüsünden Rol ve Özellik Ekle sihirbazını veya Sunucu Yöneticisi'ndeki bağlantıyı kullanın.
  2. Rol Tabanlı veya Özellik Tabanlı Yükleme'yi seçin. İleri'yi seçin.
  3. Uygun sunucuyu seçin (yerel sunucu varsayılan olarak seçilidir). İleri'yi seçin.
  4. Roller ağacında Web Sunucusu'nu (IIS) genişletin, Web Sunucusu'nu genişletin ve ardından Uygulama Geliştirme'yi genişletin.
  5. WebSocket Protokolü'ne tıklayın. İleri'yi seçin.
  6. Ek özellikler gerekmiyorsa İleri'yi seçin.
  7. Yükle'yi seçin.
  8. Yükleme tamamlandığında, sihirbazdan çıkmak için Kapat'ı seçin.

Windows 8 veya sonraki sürümlerde WebSocket protokolü desteğini etkinleştirmek için:

Not

IIS Express kullanılırken bu adımlar gerekli değildir

  1. Denetim Masası>Programlar>Programlar ve Özellikler> gidinWindows özelliklerini aç veya kapat seçeneğine gidin (ekranın sol tarafında).
  2. Şu düğümleri açın: Internet Information Services>World Wide Web Services>Uygulama Geliştirme Özellikleri.
  3. WebSocket Protokolü özelliğini seçin. Tamam'ı seçin.

Node.js'da socket.io kullanırken WebSocket'i devre dışı bırakma

Node.js socket.io'de WebSocket desteğini kullanıyorsanız, web.config veya applicationHost.config içindeki öğesini kullanarak varsayılan IIS WebSocket modülünü webSocket devre dışı bırakın. Bu adım gerçekleştirilmezse, IIS WebSocket modülü Node.js ve uygulama yerine WebSocket iletişimini işlemeye çalışır.

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

Örnek uygulama

Bu makaleye eşlik eden örnek uygulama bir yankı uygulamasıdır. WebSocket bağlantılarını yapan bir web sayfası vardır ve sunucu aldığı tüm iletileri istemciye yeniden gönderir. Örnek uygulama, hedeflenen .NET 7 veya üzeri bir çerçeve kullanılırken HTTP/2 üzerinden WebSockets'i destekler.

Uygulamayı çalıştırın:

  • Uygulamayı Visual Studio'da çalıştırmak için: Örnek projeyi Visual Studio'da açın ve hata ayıklayıcı olmadan çalıştırmak için Ctrl+F5 tuşlarına basın.
  • Uygulamayı komut kabuğunda çalıştırmak için: komutunu dotnet run çalıştırın ve tarayıcıda adresine http://localhost:<port>gidin.

Web sayfası bağlantı durumunu gösterir:

WebSockets bağlantısından önceki web sayfasının ilk durumu

Gösterilen URL'ye WebSocket isteği göndermek için Bağlan seçin. Bir test iletisi girin ve Gönder'i seçin. İşiniz bittiğinde Yuvayı Kapat'ı seçin. İletişim Günlüğü bölümü, her bir açma, gönderme ve kapatma eylemini olduğu gibi bildirir.

WebSockets bağlantısı ve test iletileri gönderilip alındıktan sonra web sayfasının son durumu

Bu makalede, ASP.NET Core'da WebSockets ile çalışmaya başlama açıklanmaktadır. WebSocket (RFC 6455), TCP bağlantıları üzerinden iki yönlü kalıcı iletişim kanalları sağlayan bir protokoldür. Sohbet, pano ve oyun uygulamaları gibi hızlı, gerçek zamanlı iletişimden yararlanan uygulamalarda kullanılır.

Örnek kodu görüntüleme veya indirme (indirme, çalıştırma).

SignalR

ASP.NET Core SignalR , uygulamalara gerçek zamanlı web işlevselliği eklemeyi kolaylaştıran bir kitaplıktır. Mümkün olduğunda WebSockets kullanır.

Çoğu uygulama için ham WebSockets üzerinden önerilir SignalR . SignalR WebSockets'in kullanılamadığı ortamlar için aktarım geri dönüşünü sağlar. Ayrıca temel bir uzaktan yordam çağrısı uygulama modeli sağlar. Çoğu senaryoda ham SignalR WebSockets kullanımına kıyasla önemli bir performans dezavantajı yoktur.

Bazı uygulamalar için.NET üzerindeki gRPC, WebSockets'e bir alternatif sağlar.

Önkoşullar

  • ASP.NET Core'u destekleyen tüm işletim sistemi:
    • Windows 7 / Windows Server 2008 veya üzeri
    • Linux
    • macOS
  • Uygulama IIS ile Windows üzerinde çalışıyorsa:
    • Windows 8 / Windows Server 2012 veya üzeri
    • IIS 8 / IIS 8 Express
    • WebSockets etkinleştirilmelidir. IIS/IIS Express desteği bölümüne bakın.
  • Uygulama HTTP.sys üzerinde çalışıyorsa:
    • Windows 8 / Windows Server 2012 veya üzeri
  • Desteklenen tarayıcılar için bkz . Kullanabilir miyim?

Ara yazılımı yapılandırma

içinde WebSockets ara yazılımını Program.csekleyin:

app.UseWebSockets();

Aşağıdaki ayarlar yapılandırılabilir:

  • KeepAliveInterval - Proxy'lerin bağlantıyı açık tutmasını sağlamak için istemciye "ping" çerçeveleri gönderme sıklığı. Varsayılan değer iki dakikadır.
  • AllowedOrigins - WebSocket istekleri için izin verilen Kaynak üst bilgi değerlerinin listesi. Varsayılan olarak tüm çıkış noktalarına izin verilir. Daha fazla bilgi için bu makaledeki WebSocket kaynak kısıtlaması bölümüne bakın.
var webSocketOptions = new WebSocketOptions
{
    KeepAliveInterval = TimeSpan.FromMinutes(2)
};

app.UseWebSockets(webSocketOptions);

WebSocket isteklerini kabul etme

İstek yaşam döngüsünün sonraki bölümlerinde (örneğin, daha sonraki bir işlem yönteminde Program.cs ) bunun bir WebSocket isteği olup olmadığını denetleyin ve WebSocket isteğini kabul edin.

Aşağıdaki örnek, içinde daha sonra verilmiştir 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);
    }

});

WebSocket isteği herhangi bir URL'de gelebilir, ancak bu örnek kod yalnızca için /wsistekleri kabul eder.

Benzer bir yaklaşım bir denetleyici yönteminde de ele alınabilir:

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;
        }
    }

WebSocket kullanırken, bağlantı süresi boyunca ara yazılım işlem hattını çalışır durumda tutmanız gerekir . Ara yazılım işlem hattı sona erdikten sonra WebSocket iletisi göndermeye veya almaya çalışırsanız, aşağıdaki gibi bir özel durumla karşılaşabilirsiniz:

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'.

WebSocket'e veri yazmak için arka plan hizmeti kullanıyorsanız ara yazılım işlem hattını çalışır durumda tuttuğunuzdan emin olun. Bunu bir TaskCompletionSource<TResult>kullanarak yapın. TaskCompletionSource öğesini arka plan hizmetinize geçirin ve WebSocket ile bitirdiğinizde aramasını TrySetResult sağlayın. Task Ardındanawait, aşağıdaki örnekte gösterildiği gibi istek sırasında özelliği:

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

    BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);

    await socketFinishedTcs.Task;
});

WebSocket kapalı özel durumu, bir eylem yönteminden çok erken geri dönerken de oluşabilir. Eylem yönteminde yuva kabul ederken, eylem yönteminden dönmeden önce yuvayı kullanan kodun tamamlanmasını bekleyin.

Önemli iş parçacığı sorunlarına neden olabileceğinden, yuvanın tamamlanmasını beklemek için hiçbir zaman , Task.Resultveya benzer engelleme çağrıları kullanmayınTask.Wait. Her zaman kullanın await.

Sıkıştırma

Uyarı

Şifrelenmiş bağlantılar üzerinden sıkıştırmanın etkinleştirilmesi, bir uygulamanın /BREACH saldırılara CRIMEtabi olmasını sağlayabilir. Hassas bilgiler gönderiyorsanız, sıkıştırmayı etkinleştirmekten veya çağrısı WebSocket.SendAsyncyaparken kullanmaktan WebSocketMessageFlags.DisableCompression kaçının. Bu, WebSocket'in her iki tarafı için de geçerlidir. Tarayıcıdaki WebSockets API'sinin gönderme başına sıkıştırmayı devre dışı bırakmak için yapılandırması olmadığını unutmayın.

İletilerin WebSockets üzerinden sıkıştırması isteniyorsa, kabul kodu aşağıdaki gibi sıkıştırmaya izin verdiği belirtmelidir:

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

}

WebSocketAcceptContext.ServerMaxWindowBits ve WebSocketAcceptContext.DisableServerContextTakeover sıkıştırmanın nasıl çalıştığını denetleen gelişmiş seçeneklerdir.

İlk bağlantı kurulurken istemci ile sunucu arasında sıkıştırma anlaşması yapılır. Anlaşma hakkında daha fazla bilgi için bkz. WebSocket RFC için Sıkıştırma Uzantıları.

Not

Sıkıştırma anlaşması sunucu veya istemci tarafından kabul edilirse, bağlantı yine de kurulur. Ancak, bağlantı iletileri gönderirken ve alırken sıkıştırma kullanmaz.

İleti alma ve gönderme

yöntemi TCP AcceptWebSocketAsync bağlantısını bir WebSocket bağlantısına yükselterek bir WebSocket nesne sağlar. WebSocket İleti göndermek ve almak için nesnesini kullanın.

WebSocket isteğini kabul eden daha önce gösterilen kod, nesnesini bir Echo yönteme geçirirWebSocket. Kod bir ileti alır ve hemen aynı iletiyi geri gönderir. İstemci bağlantıyı kapatana kadar iletiler bir döngü içinde gönderilir ve alınır:

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);
}

Döngüye başlamadan önce WebSocket bağlantısını kabul ederken ara yazılım işlem hattı sona erer. Yuva kapatılmaya devam ettikten sonra işlem hattı gevşer. Başka bir ifadeyle, WebSocket kabul edildiğinde istek işlem hattında ilerlemeyi durdurur. Döngü tamamlandığında ve yuva kapatıldığında istek işlem hattını yedekler.

İstemci bağlantısının kesilmesini işleme

Bağlantı kaybı nedeniyle istemcinin bağlantısı kesildiğinde sunucu otomatik olarak bilgilendirilir. Sunucu yalnızca istemci gönderirse bir bağlantı kesme iletisi alır ve bu işlem İnternet bağlantısı kesilirse yapılamaz. Böyle bir durumda işlem yapmak istiyorsanız, istemciden belirli bir zaman penceresi içinde hiçbir şey alınmadığında bir zaman aşımı ayarlayın.

İstemci her zaman ileti göndermiyorsa ve bağlantı boşta olduğu için zaman aşımına uğradıysanız, istemcinin her X saniyede bir ping iletisi göndermek için zamanlayıcı kullanmasını sağlayın. Sunucuda, bir ileti öncekinden sonraki 2*X saniye içinde gelmediyse bağlantıyı sonlandırın ve istemcinin bağlantısının kesildiğini bildirin. Ping iletisini tutabilecek ağ gecikmelerinde fazladan süre bırakmak için beklenen zaman aralığının iki katı kadar bekleyin.

WebSocket kaynak kısıtlaması

CORS tarafından sağlanan korumalar WebSockets için geçerli değildir. Tarayıcılar aşağıdakileri yapmaz:

  • CORS uçuş öncesi istekleri gerçekleştirin.
  • WebSocket istekleri yaparken üst bilgilerde Access-Control belirtilen kısıtlamalara uyun.

Ancak tarayıcılar WebSocket istekleri gönderirken üst bilgiyi gönderir Origin . Uygulamalar, yalnızca beklenen kaynaklardan gelen WebSockets'e izin verildiğinden emin olmak için bu üst bilgileri doğrulayacak şekilde yapılandırılmalıdır.

Sunucunuzu "https://server.com" ve istemcinizi "https://client.com", "https://client.com" webSockets'in AllowedOrigins doğrulanması için listeye gidin.

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

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

app.UseWebSockets(webSocketOptions);

Not

Üst Origin bilgi istemci tarafından denetlenebilir ve üst bilgi gibi Referer sahte olabilir. Bu üst bilgileri kimlik doğrulama mekanizması olarak kullanmayın.

IIS/IIS Express desteği

Windows Server 2012 veya üzeri ve IIS/IIS Express 8 veya üzeri yüklü Windows 8 veya üzeri, WebSocket protokolü desteğine sahiptir.

Not

WebSockets, IIS Express kullanılırken her zaman etkinleştirilir.

IIS'de WebSockets'i etkinleştirme

Windows Server 2012 veya sonraki sürümlerde WebSocket protokolü desteğini etkinleştirmek için:

Not

IIS Express kullanılırken bu adımlar gerekli değildir

  1. Yönet menüsünden Rol ve Özellik Ekle sihirbazını veya Sunucu Yöneticisi'ndeki bağlantıyı kullanın.
  2. Rol Tabanlı veya Özellik Tabanlı Yükleme'yi seçin. İleri'yi seçin.
  3. Uygun sunucuyu seçin (yerel sunucu varsayılan olarak seçilidir). İleri'yi seçin.
  4. Roller ağacında Web Sunucusu'nu (IIS) genişletin, Web Sunucusu'nu genişletin ve ardından Uygulama Geliştirme'yi genişletin.
  5. WebSocket Protokolü'ne tıklayın. İleri'yi seçin.
  6. Ek özellikler gerekmiyorsa İleri'yi seçin.
  7. Yükle'yi seçin.
  8. Yükleme tamamlandığında, sihirbazdan çıkmak için Kapat'ı seçin.

Windows 8 veya sonraki sürümlerde WebSocket protokolü desteğini etkinleştirmek için:

Not

IIS Express kullanılırken bu adımlar gerekli değildir

  1. Denetim Masası>Programlar>Programlar ve Özellikler> gidinWindows özelliklerini aç veya kapat seçeneğine gidin (ekranın sol tarafında).
  2. Şu düğümleri açın: Internet Information Services>World Wide Web Services>Uygulama Geliştirme Özellikleri.
  3. WebSocket Protokolü özelliğini seçin. Tamam'ı seçin.

Node.js'da socket.io kullanırken WebSocket'i devre dışı bırakma

Node.js socket.io'de WebSocket desteğini kullanıyorsanız, web.config veya applicationHost.config içindeki öğesini kullanarak varsayılan IIS WebSocket modülünü webSocket devre dışı bırakın. Bu adım gerçekleştirilmezse, IIS WebSocket modülü Node.js ve uygulama yerine WebSocket iletişimini işlemeye çalışır.

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

Örnek uygulama

Bu makaleye eşlik eden örnek uygulama bir yankı uygulamasıdır. WebSocket bağlantılarını yapan bir web sayfası vardır ve sunucu aldığı tüm iletileri istemciye yeniden gönderir. Örnek uygulama, IIS Express ile Visual Studio'dan çalıştırılacak şekilde yapılandırılmadığından, ile bir komut kabuğunda dotnet run uygulamayı çalıştırın ve tarayıcıda öğesine http://localhost:<port>gidin. Web sayfası bağlantı durumunu gösterir:

WebSockets bağlantısından önceki web sayfasının ilk durumu

Gösterilen URL'ye WebSocket isteği göndermek için Bağlan seçin. Bir test iletisi girin ve Gönder'i seçin. İşiniz bittiğinde Yuvayı Kapat'ı seçin. İletişim Günlüğü bölümü, her bir açma, gönderme ve kapatma eylemini olduğu gibi bildirir.

WebSockets bağlantısı ve test iletileri gönderilip alındıktan sonra web sayfasının son durumu

Bu makalede, ASP.NET Core'da WebSockets ile çalışmaya başlama açıklanmaktadır. WebSocket (RFC 6455), TCP bağlantıları üzerinden iki yönlü kalıcı iletişim kanalları sağlayan bir protokoldür. Sohbet, pano ve oyun uygulamaları gibi hızlı, gerçek zamanlı iletişimden yararlanan uygulamalarda kullanılır.

Örnek kodu görüntüleme veya indirme (indirme). Nasıl çalıştırılır?

SignalR

ASP.NET Core SignalR , uygulamalara gerçek zamanlı web işlevselliği eklemeyi kolaylaştıran bir kitaplıktır. Mümkün olduğunda WebSockets kullanır.

Çoğu uygulama için ham WebSockets üzerinden önerilir SignalR . SignalR WebSockets'in kullanılamadığı ortamlar için aktarım geri dönüşünü sağlar. Ayrıca temel bir uzaktan yordam çağrısı uygulama modeli sağlar. Çoğu senaryoda ham SignalR WebSockets kullanımına kıyasla önemli bir performans dezavantajı yoktur.

Bazı uygulamalar için.NET üzerindeki gRPC, WebSockets'e bir alternatif sağlar.

Önkoşullar

  • ASP.NET Core'u destekleyen tüm işletim sistemi:
    • Windows 7 / Windows Server 2008 veya üzeri
    • Linux
    • macOS
  • Uygulama IIS ile Windows üzerinde çalışıyorsa:
    • Windows 8 / Windows Server 2012 veya üzeri
    • IIS 8 / IIS 8 Express
    • WebSockets etkinleştirilmelidir. IIS/IIS Express desteği bölümüne bakın.
  • Uygulama HTTP.sys üzerinde çalışıyorsa:
    • Windows 8 / Windows Server 2012 veya üzeri
  • Desteklenen tarayıcılar için bkz . Kullanabilir miyim?

Ara yazılımı yapılandırma

Sınıfının yöntemine ConfigureStartup WebSockets ara yazılımını ekleyin:

app.UseWebSockets();

Not

Bir denetleyicide WebSocket isteklerini kabul etmek istiyorsanız çağrısının app.UseWebSockets öncesinde app.UseEndpointsgerçekleşmesi gerekir.

Aşağıdaki ayarlar yapılandırılabilir:

  • KeepAliveInterval - Proxy'lerin bağlantıyı açık tutmasını sağlamak için istemciye "ping" çerçeveleri gönderme sıklığı. Varsayılan değer iki dakikadır.
  • AllowedOrigins - WebSocket istekleri için izin verilen Kaynak üst bilgi değerlerinin listesi. Varsayılan olarak tüm çıkış noktalarına izin verilir. Ayrıntılar için aşağıdaki "WebSocket kaynak kısıtlaması" bölümüne bakın.
var webSocketOptions = new WebSocketOptions()
{
    KeepAliveInterval = TimeSpan.FromSeconds(120),
};

app.UseWebSockets(webSocketOptions);

WebSocket isteklerini kabul etme

İstek yaşam döngüsünün sonraki bölümlerinde (örneğin, yönteminde Configure veya eylem yönteminde) bunun bir WebSocket isteği olup olmadığını denetleyin ve WebSocket isteğini kabul edin.

Aşağıdaki örnek, yönteminin sonraki bölümlerinde verilmiştir 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();
    }

});

WebSocket isteği herhangi bir URL'de gelebilir, ancak bu örnek kod yalnızca için /wsistekleri kabul eder.

Benzer bir yaklaşım bir denetleyici yönteminde de ele alınabilir:

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;
        }
    }

WebSocket kullanırken, bağlantı süresi boyunca ara yazılım işlem hattını çalışır durumda tutmanız gerekir . Ara yazılım işlem hattı sona erdikten sonra WebSocket iletisi göndermeye veya almaya çalışırsanız, aşağıdaki gibi bir özel durumla karşılaşabilirsiniz:

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'.

WebSocket'e veri yazmak için arka plan hizmeti kullanıyorsanız ara yazılım işlem hattını çalışır durumda tuttuğunuzdan emin olun. Bunu bir TaskCompletionSource<TResult>kullanarak yapın. TaskCompletionSource öğesini arka plan hizmetinize geçirin ve WebSocket ile bitirdiğinizde aramasını TrySetResult sağlayın. Task Ardındanawait, aşağıdaki örnekte gösterildiği gibi istek sırasında özelliği:

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

        BackgroundSocketProcessor.AddSocket(webSocket, socketFinishedTcs);

        await socketFinishedTcs.Task;
    }
});

WebSocket kapalı özel durumu, bir eylem yönteminden çok erken geri dönerken de oluşabilir. Eylem yönteminde yuva kabul ederken, eylem yönteminden dönmeden önce yuvayı kullanan kodun tamamlanmasını bekleyin.

Önemli iş parçacığı sorunlarına neden olabileceğinden, yuvanın tamamlanmasını beklemek için hiçbir zaman , Task.Resultveya benzer engelleme çağrıları kullanmayınTask.Wait. Her zaman kullanın await.

İleti alma ve gönderme

yöntemi TCP AcceptWebSocketAsync bağlantısını bir WebSocket bağlantısına yükselterek bir WebSocket nesne sağlar. WebSocket İleti göndermek ve almak için nesnesini kullanın.

WebSocket isteğini kabul eden daha önce gösterilen kod, nesnesini bir Echo yönteme geçirirWebSocket. Kod bir ileti alır ve hemen aynı iletiyi geri gönderir. İstemci bağlantıyı kapatana kadar iletiler bir döngü içinde gönderilir ve alınır:

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);
}

Döngüye başlamadan önce WebSocket bağlantısını kabul ederken ara yazılım işlem hattı sona erer. Yuva kapatılmaya devam ettikten sonra işlem hattı gevşer. Başka bir ifadeyle, WebSocket kabul edildiğinde istek işlem hattında ilerlemeyi durdurur. Döngü tamamlandığında ve yuva kapatıldığında istek işlem hattını yedekler.

İstemci bağlantısının kesilmesini işleme

Bağlantı kaybı nedeniyle istemcinin bağlantısı kesildiğinde sunucu otomatik olarak bilgilendirilir. Sunucu yalnızca istemci gönderirse bir bağlantı kesme iletisi alır ve bu işlem İnternet bağlantısı kesilirse yapılamaz. Böyle bir durumda işlem yapmak istiyorsanız, istemciden belirli bir zaman penceresi içinde hiçbir şey alınmadığında bir zaman aşımı ayarlayın.

İstemci her zaman ileti göndermiyorsa ve bağlantı boşta olduğu için zaman aşımına uğradıysanız, istemcinin her X saniyede bir ping iletisi göndermek için zamanlayıcı kullanmasını sağlayın. Sunucuda, bir ileti öncekinden sonraki 2*X saniye içinde gelmediyse bağlantıyı sonlandırın ve istemcinin bağlantısının kesildiğini bildirin. Ping iletisini tutabilecek ağ gecikmelerinde fazladan süre bırakmak için beklenen zaman aralığının iki katı kadar bekleyin.

Not

ManagedWebSocket İç, seçenek sıfırdan büyükse KeepAliveInterval (varsayılan olarak 30 saniyeye (TimeSpan.FromSeconds(30) ) kadar olan bağlantıyı canlı tutmak için Ping/Pong çerçevelerini örtük olarak işler.

WebSocket kaynak kısıtlaması

CORS tarafından sağlanan korumalar WebSockets için geçerli değildir. Tarayıcılar aşağıdakileri yapmaz:

  • CORS uçuş öncesi istekleri gerçekleştirin.
  • WebSocket istekleri yaparken üst bilgilerde Access-Control belirtilen kısıtlamalara uyun.

Ancak tarayıcılar WebSocket istekleri gönderirken üst bilgiyi gönderir Origin . Uygulamalar, yalnızca beklenen kaynaklardan gelen WebSockets'e izin verildiğinden emin olmak için bu üst bilgileri doğrulayacak şekilde yapılandırılmalıdır.

Sunucunuzu "https://server.com" ve istemcinizi "https://client.com", "https://client.com" webSockets'in AllowedOrigins doğrulanması için listeye gidin.

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

app.UseWebSockets(webSocketOptions);

Not

Üst Origin bilgi istemci tarafından denetlenebilir ve üst bilgi gibi Referer sahte olabilir. Bu üst bilgileri kimlik doğrulama mekanizması olarak kullanmayın.

IIS/IIS Express desteği

Windows Server 2012 veya üzeri ve IIS/IIS Express 8 veya üzeri yüklü Windows 8 veya üzeri, WebSocket protokolü desteğine sahiptir.

Not

WebSockets, IIS Express kullanılırken her zaman etkinleştirilir.

IIS'de WebSockets'i etkinleştirme

Windows Server 2012 veya sonraki sürümlerde WebSocket protokolü desteğini etkinleştirmek için:

Not

IIS Express kullanılırken bu adımlar gerekli değildir

  1. Yönet menüsünden Rol ve Özellik Ekle sihirbazını veya Sunucu Yöneticisi'ndeki bağlantıyı kullanın.
  2. Rol Tabanlı veya Özellik Tabanlı Yükleme'yi seçin. İleri'yi seçin.
  3. Uygun sunucuyu seçin (yerel sunucu varsayılan olarak seçilidir). İleri'yi seçin.
  4. Roller ağacında Web Sunucusu'nu (IIS) genişletin, Web Sunucusu'nu genişletin ve ardından Uygulama Geliştirme'yi genişletin.
  5. WebSocket Protokolü'ne tıklayın. İleri'yi seçin.
  6. Ek özellikler gerekmiyorsa İleri'yi seçin.
  7. Yükle'yi seçin.
  8. Yükleme tamamlandığında, sihirbazdan çıkmak için Kapat'ı seçin.

Windows 8 veya sonraki sürümlerde WebSocket protokolü desteğini etkinleştirmek için:

Not

IIS Express kullanılırken bu adımlar gerekli değildir

  1. Denetim Masası>Programlar>Programlar ve Özellikler> gidinWindows özelliklerini aç veya kapat seçeneğine gidin (ekranın sol tarafında).
  2. Şu düğümleri açın: Internet Information Services>World Wide Web Services>Uygulama Geliştirme Özellikleri.
  3. WebSocket Protokolü özelliğini seçin. Tamam'ı seçin.

Node.js'da socket.io kullanırken WebSocket'i devre dışı bırakma

Node.js socket.io'de WebSocket desteğini kullanıyorsanız, web.config veya applicationHost.config içindeki öğesini kullanarak varsayılan IIS WebSocket modülünü webSocket devre dışı bırakın. Bu adım gerçekleştirilmezse, IIS WebSocket modülü Node.js ve uygulama yerine WebSocket iletişimini işlemeye çalışır.

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

Örnek uygulama

Bu makaleye eşlik eden örnek uygulama bir yankı uygulamasıdır. WebSocket bağlantılarını yapan bir web sayfası vardır ve sunucu aldığı tüm iletileri istemciye yeniden gönderir. Örnek uygulama, IIS Express ile Visual Studio'dan çalıştırılacak şekilde yapılandırılmadığından, ile bir komut kabuğunda dotnet run uygulamayı çalıştırın ve tarayıcıda öğesine http://localhost:5000gidin. Web sayfası bağlantı durumunu gösterir:

WebSockets bağlantısından önceki web sayfasının ilk durumu

Gösterilen URL'ye WebSocket isteği göndermek için Bağlan seçin. Bir test iletisi girin ve Gönder'i seçin. İşiniz bittiğinde Yuvayı Kapat'ı seçin. İletişim Günlüğü bölümü, her bir açma, gönderme ve kapatma eylemini olduğu gibi bildirir.

WebSockets bağlantısı ve test iletileri gönderilip alındıktan sonra web sayfasının son durumu