在本文中,咱们将具体介绍 RFC 6455 WebSocket 标准,并配置一个通用的.NET 5 应用程序通过 WebSocket 连贯与 SignalR 通信。
咱们将深刻底层的概念,以了解底层产生了什么。
对于 WebSocket
引入 WebSocket 是为了实现客户端和服务器之间的双向通信。HTTP 1.0 的一个痛点是每次向服务器发送申请时创立和敞开连贯。然而,在 HTTP 1.1 中,通过应用放弃连贯机制引入了长久连贯(RFC 2616)。这样,连贯能够被多个申请重用——这将缩小提早,因为服务器晓得客户端,它们不须要在每个申请的握手过程中启动。
WebSocket 建设在 HTTP 1.1 标准之上,因为它容许长久连贯。因而,当你第一次创立 WebSocket 连贯时,它实质上是一个 HTTP 1.1 申请(稍后具体介绍)。这使得客户端和服务器之间可能进行实时通信。简略地说,下图形容了在发动(握手)、数据传输和敞开 WS 连贯期间产生的事件。咱们将在前面更深刻地钻研这些概念。
协定中蕴含了两局部:握手和数据传输。
握手
让咱们先从握手开始。
简略地说,WebSocket 连贯基于单个端口上的 HTTP(和作为传输的 TCP)。上面是这些步骤的总结。
- 服务器必须监听传入的 TCP 套接字连贯。这能够是你调配的任何端口—通常是 80 或 443。
- 客户端通过一个 HTTP GET 申请发动开始握手(否则服务器将不晓得与谁对话)——这是“WebSockets”中的“Web”局部。在消息报头中,客户端将申请服务器将连贯降级到 WebSocket。
- 服务器发送一个握手响应,通知客户端它将把协定从 HTTP 更改为 WebSocket。
- 客户端和服务器单方协商连贯细节。任何一方都能够退出。
上面是一个典型的关上 (客户端) 握手申请的样子。
GET /ws-endpoint HTTP/1.1
Host: example.com:80
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: L4kHN+1Bx7zKbxsDbqgzHw==
Sec-WebSocket-Version: 13
留神客户端是如何在申请中发送 Connection: Upgrade 和 Upgrade: websocket 报头的。
并且,服务器握手响应。
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: CTPN8jCb3BUjBjBtdjwSQCytuBo=
数据传输
咱们须要了解的下一个要害概念是数据传输。任何一方都能够在任何给定的工夫发送音讯——因为它是一个全双工通信协议。
音讯由一个或多个帧组成。帧的类型能够是文本 (UTF-8)、二进制和管制帧(例如 0x8 (Close)、0x9 (Ping) 和 0xA (Pong))。
装置
让咱们付诸行动,看看它是如何工作的。
首先创立一个 ASP.NET 5 WebAPI 我的项目。
dotnet new webapi -n WebSocketsTutorial
dotnet new sln
dotnet sln add WebSocketsTutorial
当初增加 SignalR 到我的项目中。
dotnet add WebSocketsTutorial/ package Microsoft.AspNet.SignalR
示例代码
咱们首先将 WebSockets 中间件增加到咱们的 WebAPI 应用程序中。关上 Startup.cs,向 Configure 办法增加上面的代码。
在本教程中,我喜爱放弃简略。因而,我不打算探讨 SignalR。它将齐全基于 WebSocket 通信。你也能够用原始的 WebSockets 实现同样的性能,如果你想让事件变得更简略,你不须要应用 SignalR。
app.UseWebSockets();
接下来,咱们将删除默认的 WeatherForecastController,并增加一个名为 WebSocketsController 的新控制器。留神,咱们将只是应用一个控制器 action,而不是拦挡申请管道。
这个控制器的残缺代码如下所示。
using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace WebSocketsTutorial.Controllers{[ApiController]
[Route("[controller]")]
public class WebSocketsController : ControllerBase
{
private readonly ILogger<WebSocketsController> _logger;
public WebSocketsController(ILogger<WebSocketsController> logger)
{_logger = logger;}
[HttpGet("/ws")]
public async Task Get()
{if (HttpContext.WebSockets.IsWebSocketRequest)
{using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
_logger.Log(LogLevel.Information, "WebSocket connection established");
await Echo(webSocket);
}
else
{HttpContext.Response.StatusCode = 400;}
}
private async Task Echo(WebSocket webSocket)
{var buffer = new byte[1024 * 4];
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
_logger.Log(LogLevel.Information, "Message received from Client");
while (!result.CloseStatus.HasValue)
{var serverMsg = Encoding.UTF8.GetBytes($"Server: Hello. You said: {Encoding.UTF8.GetString(buffer)}");
await webSocket.SendAsync(new ArraySegment<byte>(serverMsg, 0, serverMsg.Length), result.MessageType, result.EndOfMessage, CancellationToken.None);
_logger.Log(LogLevel.Information, "Message sent to Client");
result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
_logger.Log(LogLevel.Information, "Message received from Client");
}
await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
_logger.Log(LogLevel.Information, "WebSocket connection closed");
}
}
}
这是咱们所做的。
1、增加一个名为 ws/ 的新路由。
2、查看以后申请是否通过 WebSockets,否则抛出 400。
3、期待,直到客户端发动申请。
4、进入一个循环,直到客户端敞开连贯。
5、在循环中,咱们将发送“Server: Hello. You said: <client’s message>”信息,并把它发回给客户端。
6、期待,直到客户端发送另一个申请。
留神,在初始握手之后,服务器不须要期待客户端发送申请来将音讯推送到客户端。让咱们运行应用程序,看看它是否工作。
dotnet run --project WebSocketsTutorial
运行应用程序后,请拜访 https://localhost:5001/swagger/index.html,应该看到 Swagger UI。
![上传中 …]()
当初咱们将看到如何让客户端和服务器彼此通信。在这个演示中,我将应用 Chrome 的 DevTools(关上新标签→查看或按 F12→控制台标签)。然而,你能够抉择任何客户端。
首先,咱们将创立一个到服务器终结点的 WebSocket 连贯。
let webSocket = new WebSocket('wss://localhost:5001/ws');
它所做的是,在客户端和服务器之间发动一个连贯。wss:// 是 WebSockets 平安协定,因为咱们的 WebAPI 应用程序是通过 TLS 服务的。
而后,能够通过调用 webSocket.send()办法发送音讯。你的控制台应该相似于上面的控制台。
让咱们认真看看 WebSocket 连贯
如果转到 Network 选项卡,则通过 WS 选项卡过滤掉申请,并单击最初一个称为 WS 的申请。
单击 Messages 选项卡并查看来回传递的音讯。在此期间,如果调用以下命令,将可能看到“This was sent from the Client!”。试试吧!
webSocket.send("Client: Hello");
如你所见,服务器的确须要期待客户端发送响应(即在初始握手之后),并且客户端能够发送音讯而不会被阻塞。这是全双工通信。咱们曾经探讨了 WebSocket 通信的数据传输方面。作为练习,你能够运行一个循环将音讯推送到客户机,以查看它的运行状况。
除此之外,服务器和客户端还能够通过 ping-pong 来查看客户端是否还活着。这是 WebSockets 中的一个理论个性! 如果你真的想看看这些数据包,你能够应用像 WireShark 这样的工具来理解。
它是如何握手的? 好吧,如果你跳转到 Headers 选项卡,你将可能看到咱们在这篇文章的第一局部谈到的申请 - 响应题目。
也能够尝试一下 webSocket.close(),这样咱们就能够齐全笼罩 open-data-close 循环了。
论断
如果你对 WebSocket 的 RFC 感兴趣,请拜访 RFC 6455 并浏览。这篇文章只是涉及了 WebSocket 的外表,还有很多其余的货色咱们能够探讨,比方平安,负载平衡,代理等等。
原文链接:https://sahansera.dev/underst…