首页 > 其他分享 >.Net Core 实现WebSocket Server 的另外三种方式

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

时间:2023-05-16 22:01:20浏览次数:57  
标签:Core WebSocket string Server key 客户端 服务端 socket


回顾

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

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

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

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

正视WebSocket协议

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

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

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

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

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

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

用新的方法实现WebSocket服务端

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

原生socket支持WebSocket Server

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

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

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

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

WebSocketHelper.cs

/// <summary>
    /// WebSocket帮助类
    /// </summary>
    public static class WebSocketHelper
    {
        /// <summary>
        /// 协议处理-http协议握手
        /// </summary>
        public static byte[] HandshakeMessage(string data)
        {
            /// <summary>
            /// 获取返回验证的key
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            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

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

tcpListener 方案 2

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

HttpListener 方案 3

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

需注意

特别是发送的操作,发送本身不能并发。

以下是 官方 资料引用 [2]

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


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

总结

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

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

资料引用

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



标签:Core,WebSocket,string,Server,key,客户端,服务端,socket
From: https://blog.51cto.com/kesshei/6287451

相关文章

  • Windows Server 2012 域控搭建
     0x01准备1、设置固定ip地址  2、修改计算机名  3、立即重新启动 0x02安装AD1、管理--添加角色和功能2、添加角色和功能向导,直接点击下一步 3、添加角色和功能向导,基于角色或基于功能的安装,下一步。 4、从服务器池中选择服务器,下一步。 5、选择“ActiveDirecyoty域服......
  • SQLSERVER中JSON数组的拆分
    DECLARE@infoParamNVARCHAR(MAX);DECLARE@itemsNVARCHAR(MAX);SET@infoParam='{ "SCHOOL":"某某中学", "SCHOOLCODE":"1234", "USER":[{ "userid":"20XX001", "username......
  • 用QWebsocket时关于信号槽的一个坑
    https://blog.csdn.net/zerolity/article/details/94746977 坑描述:connect(&m_webSocket,&QWebSocket::textMessageReceived,this,&BWebsocket::onTextMessageReceived);1和主机通过websocket通信。接收主机发的指令有时导致重复接收。信号发送者和接受者同一线程。onTe......
  • SQL Server(2008版)还原数据库备份 修改表结构
    昨天接到个小活,前公司一个项目中,有个功能不太正常,需要帮忙排查原因并解决,于是在本地部署环境,还原数据库并运行程序。由于已经从前公司离开3年有余,到这边以后主要是做导航算法相关开发,基本不使用数据库,即便用到的地方也都是Mysql和MongoDB,MSSQLServer被淡忘,操作过程中明明记得有个......
  • js函数式编程: nderscore.js
    nderscore.js是一个JavaScript工具库,它提供了一整套函数式编程的实用功能,弥补了jQuery没有实现的功能,同时又是Backbone必不可少的部分。官方:[url]http://www.bootcss.com/p/underscore/[/url]......
  • gdb如何比较core文件和image及buildid
    gdb从git上看到的提交记录,关键的修改是在elf_core_file_matches_executable_p函数中添加的对于build_id的比较。///@file:gdb-10.1\bfd\elfcore.hbfd_booleanelf_core_file_matches_executable_p(bfd*core_bfd,bfd*exec_bfd){char*corename;/*xvecsmustmatch......
  • 【换模型更简单】如何用 Serverless 一键部署 Stable Diffusion?
    作者:寒斜本篇章是阿里云函数计算部署StableDiffusion系列的第三篇,如果说第一篇是尝试使用云服务来解决用户本地部署Stable Diffusion的问题(显卡成本,部署技术复杂),第二篇是面向技术同学解决云服务Stable Diffusion的实用性问题(自定义模型,扩展),那么本篇则是以更大众的方式实现......
  • SQL SERVER 物理分区和读写分离主从库数据同步
    对于对现有系统进行数据性能优化顺序建议1.先考虑物理分区,因为物理分区对我们代码业务不会有改动,但是有局限性,优化效果不是很好2.再考虑读写分离,读写分离对代码改动不会太多,并且只试用超过读:写=8:2的比例,因为读写分离主要是缓解读数据库的压力,如果读的压力并没有那么大,就不用......
  • sql server 中 COALESCE()函数的使用
    一、sqlserver 中coalesce函数的介绍COALESCE(expression,value1,value2……,valuen); COALESCE()函数的第一个参数expression为待检测的表达式,而其后的参数个数不定。COALESCE()函数将会返回包括expression在内的所有参数中的第一个非空表达式。如果expression不为空......
  • SQL Server 夸数据库查询
    数据需要在两个服务器之间的数据库查询DB1DB2  1.安装MicrosoftSQLServerDataTools 2.把DB1里面要查询的表保存成csv文件,命个名假设叫f.csv3.安装路径里面C:\ProgramFiles(x86)\MicrosoftSQLServer\130\DTS\BinnDTSWizards.exe 点开这个文件选择Fla......