在本文中,咱们将具体介绍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…