.Net Core 实现WebSocket Server 的另外三种方式

回顾
之前已经写过关于《WebSocket 原生socket实现》和《.Net Core WebSocket 服务端与客户端完整示例》以及《基于.Net TcpListener 实现 WebSocketServer 通讯》。

其中除了 《.Net Core WebSocket 服务端与客户端完整示例》外,都是基于自己对Websocket协议的实现,这种实现在生产环境的时候,会有各种需要解决的问题,那么,就又回到了WebSocket的协议上去了。

所以,还是缺少一种轻量级的WebSocket客户端和服务端的支持,对于那些不想用第三方框架的人来说(第三方可能重,也可能复杂),所以,一个官方支持websocket使用,才是最好的。

这样,就不用自己去实现握手啊,Websocket底层协议了,以及Websocket实现的大包分包了和所谓socket的粘包,半包了。

正视WebSocket协议
图片
之前可能都是简单的使用,并没有太过认真的去瞧这个协议。

现在认真去看,才发现,其实WebSocket已经把所谓的大包分包和socket的粘包,掉包(半包)等问题通过它自己的协议给解决了。

Websocket 自己还实现了ping和pong心跳支持。

这对通过原生socket支持来讲,相当于已经有人把使用socket的顾虑都给解决了,还是通过标准协议解决的,那么,我们使用的时候,应该更加简单,方便才对,而不是更加的复杂,难用。

这是我对这个协议又深入研究后的结果。

用新的方法实现WebSocket服务端
这里我介绍除了 《.Net Core WebSocket 服务端与客户端完整示例》的另外三种实现方式,主要是针对服务端,客户端的话,直接用ClientWebSocket就搞定了。

原生socket支持WebSocket Server
大部分在刚开始实现的时候,因为找不到库,只能用第三方,或者自己使用协议实现。

但是,其实,也是可以直接把Socket 转为 WebSocket对象的,这个方法,我也是在看官方源码的时候,找到的,才知道它的用处(网上一搜,用的人真少。)

后来发现少的原因,原来这个方法的支持是在.NET Core 2.1版本之后才有的。

原生的实现都得自己实现握手协议,也很简单。

WebSocketHelper.cs
///
/// WebSocket帮助类
///
public static class WebSocketHelper
{
///
/// 协议处理-http协议握手
///
public static byte[] HandshakeMessage(string data)
{
///
/// 获取返回验证的key
///
///
///
static string getResponseKey(string key)
{
var MagicKey = “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”;
if (string.IsNullOrEmpty(key))
{
return string.Empty;
}
else
{
key += MagicKey;
key = Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key.Trim())));
return key;
}
}

        string key = string.Empty;
        string info = data;
        //一步一步来
        string[] list = info.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
        foreach (var item in list.Reverse())
        {
            if (item.IndexOf("Sec-WebSocket-Key") > -1)
            {
                key = item.Split(new string[] { ": " }, StringSplitOptions.None)[1];
                break;
            }
        }
        //获取标准的key
        key = getResponseKey(key);
        //拼装返回的协议内容
        var responseBuilder = new StringBuilder();
        responseBuilder.Append("HTTP/1.1 101 Switching Protocols" + "\r\n");
        responseBuilder.Append("Upgrade: websocket" + "\r\n");
        responseBuilder.Append("Connection: Upgrade" + "\r\n");
        responseBuilder.Append("Sec-WebSocket-Accept: " + key + "\r\n\r\n");
        return Encoding.UTF8.GetBytes(responseBuilder.ToString());
    }
}

核心代码
主要是对 socket 转 websocket server对象部分。

socket = ServerSocket.Accept();
WebSocket = WebSocket.CreateFromStream(new NetworkStream(socket), true, null, TimeSpan.FromSeconds(5));
原生socket接收到的客户端socket对象,直接转换就可以了。

TcpListener 支持WebSocket Server
大致同上,同一个原理,都需要自己处理握手

TcpClient s = listener.AcceptTcpClient();
WebSocket = WebSocket.CreateFromStream(s.GetStream(), true, null, TimeSpan.FromSeconds(5));
HttpListener 方式实现 WebSocket Server
这种方式,是我认为最轻量化的实现方式,连握手都不需要处理。

HttpListenerContext httpListenerContext = await this.listener.GetContextAsync();
HttpListenerWebSocketContext webSocketContext = await httpListenerContext.AcceptWebSocketAsync(null);
WebSocket = webSocketContext.WebSocket;
方式对比
加上以前的方案,目前一共有四种官方实现WebSocket Server 的方案。

  1. asp.net core useWebSocket

  2. socket WebSocket.CreateFromStream

  3. tcpListener WebSocket.CreateFromStream

  4. HttpListener AcceptWebSocketAsync

我个人认为,最好的方式就是第一种和第四种。其他两种自己还要实现握手。

另外,第一种与第四种的区别是起服务的引擎不同。asp.net core 是内置了 Kestrel 与 HTTP.sys 两种 webserver 服务引擎,而 HttpListener 可能就是默认的实现了 (具体也没查到),相对来讲更轻量一些。

结果展示
测试的大致逻辑是

  1. 先启动服务端,再启动客户端

  2. 客户端循环发送数据,先发送19次文字,再发送一个633M的视频大文件

  3. 服务端收到后,如果是文字,就回复给客户端,如果不是文字,就输出大文件的大小

这个逻辑用来测试,应该没啥大问题。

socket 方案 1
图片
tcpListener 方案 2
图片
HttpListener 方案 3
图片
需注意
特别是发送的操作,发送本身不能并发。

官方 资料引用 [2]

所以,在处理接收的时候,我们一般都是一个接收,但是,发送的地方经常被忽视。这个地方需要特殊处理的。

总结
只有复杂的实际应用才能深入了解各个方面,果真是天降大任于斯人也,深入挖掘才能掌握更多知识。

还是要勤于思考,勤于总结,我发现好多自己写过的东西都直接帮助到了我,这也许就是反哺己身吧。

资料引用
https://learn.microsoft.com/zh-cn/dotnet/api/system.net.websockets.websocket.createfromstream

https://learn.microsoft.com/en-us/dotnet/api/system.net.websockets.clientwebsocket.sendasync

代码地址
https://github.com/kesshei/WebSocketServerDemo2.git

https://gitee.com/kesshei/WebSocketServerDemo2.git

蓝创精英团队

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,以下是一个使用 ASP.NET Core 6 控制器创建 WebSocket 服务的示例,同时也包含了客户端代码: 在控制台应用程序或 ASP.NET Core Web 应用程序中,首先需要添加对 `Microsoft.AspNetCore.WebSockets` NuGet 包的引用。 在控制器中,需要注入 `IWebSocketFactory` 接口,并在 Action 中使用它来创建 WebSocket 连接。以下是示例代码: ```csharp using System.Net.WebSockets; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; namespace MyWebSocketApp.Controllers { [ApiController] [Route("[controller]")] public class MyWebSocketController : ControllerBase { private readonly ILogger<MyWebSocketController> _logger; private readonly IWebSocketFactory _webSocketFactory; public MyWebSocketController(ILogger<MyWebSocketController> logger, IWebSocketFactory webSocketFactory) { _logger = logger; _webSocketFactory = webSocketFactory; } [HttpGet("{id}")] public async Task Get(string id) { if (!HttpContext.WebSockets.IsWebSocketRequest) { HttpContext.Response.StatusCode = 400; return; } WebSocket webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync(); _logger.LogInformation($"WebSocket connection with ID {id} established"); await HandleWebSocketConnection(webSocket); _logger.LogInformation($"WebSocket connection with ID {id} closed"); } private async Task HandleWebSocketConnection(WebSocket webSocket) { // handle incoming WebSocket messages here } } } ``` 在客户端代码中,可以使用 `WebSocket` 类来连接 WebSocket 服务。以下是示例代码: ```csharp using System; using System.Net.WebSockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace MyWebSocketClient { class Program { private static readonly Uri _uri = new Uri("ws://localhost:5000/MyWebSocket/123"); static async Task Main(string[] args) { using (ClientWebSocket webSocket = new ClientWebSocket()) { await webSocket.ConnectAsync(_uri, CancellationToken.None); // send a message to the server string message = "Hello, server!"; byte[] messageBytes = Encoding.UTF8.GetBytes(message); await webSocket.SendAsync(new ArraySegment<byte>(messageBytes), WebSocketMessageType.Text, true, CancellationToken.None); // receive incoming WebSocket messages here byte[] buffer = new byte[1024]; while (webSocket.State == WebSocketState.Open) { WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); string incomingMessage = Encoding.UTF8.GetString(buffer, 0, result.Count); Console.WriteLine($"Received message from server: {incomingMessage}"); } } } } } ``` 当客户端连接到 `ws://localhost:5000/MyWebSocket/123` 时,将创建一个新的 WebSocket 连接,并在控制台中记录连接消息。在 `HandleWebSocketConnection` 方法中,可以处理从客户端发送的所有 WebSocket 消息。 这只是一个简单的示例,实际情况可能更复杂。但是,这应该足以让你开始构建自己的 ASP.NET Core 6 WebSocket 服务了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gp865542

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值