【无标题】

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

参考文献
阮一峰

相关推荐
0zxm6 分钟前
06 - Django 视图view
网络·后端·python·django
m0_748257186 分钟前
Spring Boot FileUpLoad and Interceptor(文件上传和拦截器,Web入门知识)
前端·spring boot·后端
小_太_阳1 小时前
Scala_【1】概述
开发语言·后端·scala·intellij-idea
智慧老师1 小时前
Spring基础分析13-Spring Security框架
java·后端·spring
搬码后生仔2 小时前
asp.net core webapi项目中 在生产环境中 进不去swagger
chrome·后端·asp.net
凡人的AI工具箱3 小时前
每天40分玩转Django:Django国际化
数据库·人工智能·后端·python·django·sqlite
Lx3523 小时前
Pandas数据重命名:列名与索引为标题
后端·python·pandas
小池先生3 小时前
springboot启动不了 因一个spring-boot-starter-web底下的tomcat-embed-core依赖丢失
java·spring boot·后端
百罹鸟4 小时前
【vue高频面试题—场景篇】:实现一个实时更新的倒计时组件,如何确保倒计时在页面切换时能够正常暂停和恢复?
vue.js·后端·面试
小蜗牛慢慢爬行5 小时前
如何在 Spring Boot 微服务中设置和管理多个数据库
java·数据库·spring boot·后端·微服务·架构·hibernate