【无标题】

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

参考文献
阮一峰

相关推荐
间彧21 分钟前
Windows Server,如何使用WSFC+nginx实现集群故障转移
后端
间彧27 分钟前
Nginx + Keepalived 实现高可用集群(Linux下)
后端
间彧28 分钟前
在Kubernetes中如何部署高可用的Nginx Ingress Controller?
后端
间彧30 分钟前
Ribbon负载均衡器和Nginx负载均衡器有什么区别
后端
间彧39 分钟前
Nacos详解与项目实战
后端
间彧39 分钟前
nginx、网关Gateway、Nacos、多个服务实例之间的数据链路详解
后端
间彧41 分钟前
Nacos与Eureka在性能上有哪些具体差异?
后端
间彧43 分钟前
详解Nacos健康状态监测机制
后端
间彧44 分钟前
如何利用Nacos实现配置的灰度发布?
后端
毕业设计制作和分享1 小时前
springboot159基于springboot框架开发的景区民宿预约系统的设计与实现
java·spring boot·后端