【无标题】

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

参考文献
阮一峰

相关推荐
Estar.Lee12 分钟前
时间操作[计算时间差]免费API接口教程
android·网络·后端·网络协议·tcp/ip
新知图书1 小时前
Rust编程与项目实战-模块std::thread(之一)
开发语言·后端·rust
盛夏绽放1 小时前
Node.js 和 Socket.IO 实现实时通信
前端·后端·websocket·node.js
Ares-Wang1 小时前
Asp.net Core Hosted Service(托管服务) Timer (定时任务)
后端·asp.net
Rverdoser3 小时前
RabbitMQ的基本概念和入门
开发语言·后端·ruby
Tech Synapse3 小时前
Java根据前端返回的字段名进行查询数据的方法
java·开发语言·后端
.生产的驴3 小时前
SpringCloud OpenFeign用户转发在请求头中添加用户信息 微服务内部调用
spring boot·后端·spring·spring cloud·微服务·架构
微信-since811924 小时前
[ruby on rails] 安装docker
后端·docker·ruby on rails
代码吐槽菌6 小时前
基于SSM的毕业论文管理系统【附源码】
java·开发语言·数据库·后端·ssm
豌豆花下猫6 小时前
Python 潮流周刊#78:async/await 是糟糕的设计(摘要)
后端·python·ai