【无标题】

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应用。

参考文献
阮一峰

相关推荐
2401_865854882 小时前
iOS应用想要下载到手机上只能苹果签名吗?
后端·ios·iphone
AskHarries2 小时前
Spring Boot集成Access DB实现数据导入和解析
java·spring boot·后端
2401_857622662 小时前
SpringBoot健身房管理:敏捷与自动化
spring boot·后端·自动化
程序员阿龙2 小时前
基于SpringBoot的医疗陪护系统设计与实现(源码+定制+开发)
java·spring boot·后端·医疗陪护管理平台·患者护理服务平台·医疗信息管理系统·患者陪护服务平台
程思扬3 小时前
为什么Uptime+Kuma本地部署与远程使用是网站监控新选择?
linux·服务器·网络·经验分享·后端·网络协议·1024程序员节
阿华的代码王国3 小时前
【Spring】——SpringBoot项目创建
java·spring boot·后端·启动类·target文件
九鼎科技-Leo3 小时前
什么是 ASP.NET Core?与 ASP.NET MVC 有什么区别?
windows·后端·c#·asp.net·mvc·.net
阿芯爱编程3 小时前
平衡二叉树
java·后端·算法
程序员清风4 小时前
浅析Web实时通信技术!
java·后端·面试
dessler4 小时前
Linux系统-rocky系统安装
linux·运维·后端