【无标题】

AspNet 接入WebSocket


文章目录


前言

提示:WebScoket相信大家都不陌生

WebScoket是与Http协议类似的一种协议,区别在于WebSocket属于服务端和客户端双向通信而Http是无状态式,每次请求都服务端都不清楚客户端是谁,所以Http需要CookieSession来实现识别客户端信息的作用。


提示:以下是本篇文章正文内容,下面案例可供参考

一、Http场景

在普通的Web应用下一般多用于Http实现与服务端通信,由于Http是无状态的在并发、性能方面也相对较好

二、WebScoket场景

WebScoket为了实现一些特殊场景,比如:即时通讯、消息推送等对数据响应速度较快的情况而应对,当然由于这种协议属于双向通信也是一种长时间保持连接的状态,对资源消耗、性能提高、并发量的支持不是很高。

三、图解

四、在Asp.net Web应用如何接入WebSocket

1.WebsocketHelper

代码如下(示例):

csharp 复制代码
public static class WebsocketHelper
    {
        /// <summary>
        /// 记录客户端连接
        /// </summary>
        public static ConcurrentDictionary<string, WebSocket> webSockets = new ConcurrentDictionary<string, WebSocket>();

        //private static List<Authority_User> UserList = new QMS_BaseResource().Authority_User.AsNoTracking().Where(p => p.UserType!=null && (p.UserType == 4 || p.UserType == 0)).ToList();
        /// <summary>
        /// 接受信息
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async static Task ProcessRequest(AspNetWebSocketContext context)
        {
            try
            {
                //获取路由
                string route = context.RawUrl;
                //if (route.Contains("?"))
                //{
                //    route = route.Split('?')[0];
                //}
                string key = context.UserHostAddress + route;
                //传入的context中有当前的websocket对象
                var socket = context.WebSocket;
                //此处将web socket对象加入一个静态字典中.
                if (!webSockets.ContainsKey(key))
                {
                    //将IP地址和路由设置为hashTable的key值,若hashTable中存在该IP地址则不再添加
                    QMS.PMC.LogNet.Log4NetHelper.Info($"{key}连接成功");
                    webSockets.TryAdd(key, socket);
                }
                //进入一个无限循环,当websocket close时循环结束
                while (true)
                {
                    //关闭连接
                    var buffer = new ArraySegment<byte>(new byte[1024]);
                    //对web socket进行异步接收数据
                    var receivedResult = await socket.ReceiveAsync(buffer, CancellationToken.None);
                    int count = receivedResult.Count;
                    if (receivedResult.MessageType == WebSocketMessageType.Close)
                    {
                        //如果client发起close请求,对client进行ack
                        await socket.CloseAsync(WebSocketCloseStatus.Empty, string.Empty, CancellationToken.None);
                        QMS.PMC.LogNet.Log4NetHelper.Info($"{key}断开连接");
                        WebSocket outsocket;
                        if (webSockets.TryRemove(key, out outsocket))
                        {
                            break;
                        }
                    }
                    while (receivedResult != null && !receivedResult.CloseStatus.HasValue)
                    {
                        if (count > buffer.Count)
                        {
                            throw new Exception("receive WebSocket data error");
                        }
                        else if (count == buffer.Array.Count(n=>n!=0))
                        {
                            break;
                        }
                    }
                    // 判断计划员更新数据后,服务端通知对应的班组长(客户端), 如果班组长客户端未登陆, 等待登陆时再抓取当天未读消息
                    // 服务端》客户端 = 班组长角色
                    // string messagebody = Encoding.UTF8.GetString(buffer.Array);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 将数据发送给所有已连接的客户端
        /// </summary>
        /// <param name="data"></param>
        /// <param name="route">接口路由</param>
        public static void SendAll(string data, string route)
        {
            var recvBytes = Encoding.UTF8.GetBytes(data);
            var sendBuffer = new ArraySegment<byte>(recvBytes);
            if (webSockets.Any())
            {
                var webs = webSockets.Where(w => w.Key.Contains(route)).ToList();
                if (webs != null)
                {
                    foreach (var item in webs)
                    {
                        item.Value.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
                    }
                }
            }
        }
    }

2. Controller

通过HTTP做一个代理建立WebScoket握手连接

csharp 复制代码
		[HttpGet]
        public HttpResponseMessage GetConnect(string uid)
        {
            //在服务器端接受WebSocket请求
            HttpContext.Current.AcceptWebSocketRequest(WebsocketHelper.ProcessRequest);

            //Response.
            return Request.CreateResponse(HttpStatusCode.SwitchingProtocols);
        }

总结

小ps:

虽然Web应用可以接入WebScoket,但是这种对应用的并发、性能方面的支持不太好,对于大体量的Web服务还是需要搭建一个独立的WebSocket应用。

参考文献
阮一峰

相关推荐
Easonmax1 小时前
用 Rust 打造可复现的 ASCII 艺术渲染器:从像素到字符的完整工程实践
开发语言·后端·rust
百锦再1 小时前
选择Rust的理由:从内存管理到抛弃抽象
android·java·开发语言·后端·python·rust·go
小羊失眠啦.2 小时前
深入解析Rust的所有权系统:告别空指针和数据竞争
开发语言·后端·rust
q***71852 小时前
Spring Boot 集成 MyBatis 全面讲解
spring boot·后端·mybatis
大象席地抽烟2 小时前
使用 Ollama 本地模型与 Spring AI Alibaba
后端
程序员小假2 小时前
SQL 语句左连接右连接内连接如何使用,区别是什么?
java·后端
小坏讲微服务2 小时前
Spring Cloud Alibaba Gateway 集成 Redis 限流的完整配置
数据库·redis·分布式·后端·spring cloud·架构·gateway
方圆想当图灵3 小时前
Nacos 源码深度畅游:Nacos 配置同步详解(下)
分布式·后端·github
Laravel技术社区3 小时前
海康视频 h5player 配置 proxy 代理websocket播放视频问题(websocket在业务系统https方式访问http的播放视频)
websocket·http·音视频
方圆想当图灵3 小时前
Nacos 源码深度畅游:Nacos 配置同步详解(上)
分布式·后端·github