zoukankan      html  css  js  c++  java
  • Net Core Web 使用 WebSocket 实现监控在线人数

    Net Core Web 使用 WebSocket 实现链接人数

    Net Core Web 使用 WebSocket 实现监控人数

    点我,跳转到最后看实现效果

    在 Startup.cs  文件中的方法 Configure() 中加入如下中间件(尽量往前面放,尽量在 app.UseCors()的后面(如果有的话)):

                app.UseWebSockets();
                app.Use(async (context, next) =>
                {
                    //是否为WebSocket请求
                    if (context.WebSockets.IsWebSocketRequest)
                    {
                        using (IServiceScope scope = app.ApplicationServices.CreateScope())
                        {
                            //执行...
                            WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
                            await new WebSocketFilter().Echo(context, webSocket);
                        }
                    }
                    else
                    {
                        //下一个中间件...
                        await next();
                    }
                });
    

      

    创建一个文件 WebSocketFilter.cs 拷贝如下代码:

    using Microsoft.AspNetCore.Http;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net.WebSockets;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace YGNT.DtSchoolAdmin.Filter
    {
        public class WebSocketFilter
        {
            //用户连接池
            private static Dictionary<string, WebSocket> UserPool = new Dictionary<string, WebSocket>();
            //监控连接池(全部)
            private static Dictionary<string, WebSocket> MonitoringPool1 = new Dictionary<string, WebSocket>();
    
            /// <summary>
            /// webSocket的处理
            /// </summary>
            public async Task Echo(HttpContext context, WebSocket webSocket)
            {
                try
                {
                    //链接的唯一标识符
                    var ConnectionId = context.Connection.Id;
    
                    //用户={user_id}
                    string user = context.Request.Query["user"];
                    //监控={1全部,2机构,3企业}
                    string monitoring = context.Request.Query["monitoring"];
    
                    if (!string.IsNullOrWhiteSpace(user))
                    {
                        //第一次open时,添加到连接池中
                        if (!UserPool.ContainsKey(user))
                        {
                            UserPool.Add(user, webSocket);
    
                            foreach (var item in MonitoringPool1)
                                SendTextAsync(item.Value, $"人数为{UserPool.Count}");
                        }
                        else
                        {
                            await UserPool[user].CloseAsync(WebSocketCloseStatus.NormalClosure, "此用户被占领,强制关闭", CancellationToken.None);
                            UserPool[user] = webSocket;
                        }
                    }
                    else if (!string.IsNullOrWhiteSpace(monitoring))
                    {
                        if (monitoring == "1")
                        {
                            if (!MonitoringPool1.ContainsKey(ConnectionId))
                                MonitoringPool1.Add(ConnectionId, webSocket);
    
                            await SendTextAsync(webSocket, $"人数为{UserPool.Count}");
                        }
                    }
    
    
                    //全部消息容器
                    List<byte> bs = new List<byte>();
                    //缓冲区
                    var buffer = new byte[1024 * 4];
                    //监听Socket信息
                    WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                    //是否关闭
                    while (!result.CloseStatus.HasValue)
                    {
                        //文本消息
                        if (result.MessageType == WebSocketMessageType.Text)
                        {
                            bs.AddRange(buffer.Take(result.Count));
    
                            //消息是否已接收完全
                            if (result.EndOfMessage)
                            {
                                //发送过来的消息
                                string userMsg = Encoding.UTF8.GetString(bs.ToArray(), 0, bs.Count);
                                var reply = $"服务器收到你的信息为({userMsg})【{DateTime.Now}】";
    
                                await SendTextAsync(webSocket, reply);
    
                                //清空消息容器
                                bs = new List<byte>();
                            }
                        }
    
                        //继续监听Socket信息
                        result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                    }
                    //关闭WebSocket(客户端发起)
                    await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
    
                    if (!string.IsNullOrWhiteSpace(user))
                        if (UserPool.ContainsKey(user))
                            UserPool.Remove(user);
                    if (!string.IsNullOrWhiteSpace(ConnectionId))
                        if (MonitoringPool1.ContainsKey(ConnectionId))
                            MonitoringPool1.Remove(ConnectionId);
    
                    foreach (var item in MonitoringPool1)
                        SendTextAsync(item.Value, $"人数为{UserPool.Count}");
                }
                catch (Exception ex)
                {
                    await SendTextAsync(webSocket, $"服务器发生错误,正在关闭WebSocket。错误堆载为【{ex}】");
                    //关闭WebSocket(服务端发起)
                    await webSocket.CloseAsync(WebSocketCloseStatus.InternalServerError, ex.Message, CancellationToken.None);
                }
            }
    
            /// <summary>
            /// 发送文本消息
            /// </summary>
            /// <param name="webSocket"></param>
            /// <param name="mess"></param>
            /// <returns></returns>
            private static async Task SendTextAsync(WebSocket webSocket, string mess)
            {
                var replyMess = Encoding.UTF8.GetBytes(mess);
    
                if (webSocket != null && webSocket.State == WebSocketState.Open)
                    //发送消息
                    await webSocket.SendAsync(new ArraySegment<byte>(replyMess), WebSocketMessageType.Text, true, CancellationToken.None);
            }
    
        }
    }
    

      

    在 Startup.cs  文件中的方法 Configure() 中加入如下中间件(可以放在 app.UseWebSockets() 的前面):

    app.UseStaticFiles();
    

      

    在web项目中创建文件夹 wwwroot  (如果没有的话)(注:vs会自动改变样式),并在下面创建一个文件名为WebSocket.html 的文件,如图:

    并将如下代码拷贝在 WebSocket.html 文件中:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <title>WebSocket示例应用程序</title>
        <style>
            body {
                background-color: #DDDDDD;
            }
    
            table {
                border: 0
            }
    
            .connection-status {
                color: orangered;
            }
    
            .connection-status2 {
                color: blueviolet;
            }
    
            .commslog-data {
                font-family: Consolas, Courier New, Courier, monospace;
            }
    
            .commslog-server {
                background-color: red;
                color: white
            }
    
            .commslog-client {
                background-color: green;
                color: white
            }
        </style>
    </head>
    <body>
        <h1>WebSocket示例应用程序</h1>
    
        <p>
            当前状态:
            <label id="stateLabel" class="connection-status">准备连接</label>
        </p>
    
        <div>
            <label>可用参数:</label>
            <label class="connection-status2">?user=1&monitoring=1</label>
        </div>
        <div>
            <label for="connectionUrl">WebSocket服务器URL:</label>
            <input id="connectionUrl" />
            <button id="connectButton" type="submit">连接</button>
        </div>
        <br />
        <div>
            <label for="sendMessage">发送消息:</label>
            <input id="sendMessage" disabled />
            <button id="sendButton" type="submit" disabled>发送</button>
            <button id="closeButton" disabled>关闭WebSocket</button>
            <button id="emptyButton">清空消息</button>
        </div>
    
        <h2>通信记录</h2>
        <table style=" 800px">
            <thead>
                <tr>
                    <td style=" 100px">发送者</td>
                    <td style=" 100px">接收者</td>
                    <td>消息</td>
                </tr>
            </thead>
            <tbody id="commsLog">
            </tbody>
        </table>
    
        <script>
            var connectionUrl = document.getElementById("connectionUrl");
            var connectButton = document.getElementById("connectButton");
            var stateLabel = document.getElementById("stateLabel");
            var sendMessage = document.getElementById("sendMessage");
            var sendButton = document.getElementById("sendButton");
            var commsLog = document.getElementById("commsLog");
            var closeButton = document.getElementById("closeButton");
            var emptyButton = document.getElementById("emptyButton");
            var socket;
    
            var scheme = document.location.protocol === "https:" ? "wss" : "ws";
            var port = document.location.port ? (":" + document.location.port) : "";
    
            //connectionUrl.value = scheme + "://" + document.location.hostname + port + "/ws";
            connectionUrl.value = scheme + "://" + document.location.hostname + port;
    
            function updateState() {
                function disable() {
                    sendMessage.disabled = true;
                    sendButton.disabled = true;
                    closeButton.disabled = true;
                }
                function enable() {
                    sendMessage.disabled = false;
                    sendButton.disabled = false;
                    closeButton.disabled = false;
                }
    
                connectionUrl.disabled = true;
                connectButton.disabled = true;
    
                if (!socket) {
                    disable();
                } else {
                    switch (socket.readyState) {
                        case WebSocket.CLOSED:
                            stateLabel.innerHTML = "关闭";
                            disable();
                            connectionUrl.disabled = false;
                            connectButton.disabled = false;
                            break;
                        case WebSocket.CLOSING:
                            stateLabel.innerHTML = "关闭中...";
                            disable();
                            break;
                        case WebSocket.CONNECTING:
                            stateLabel.innerHTML = "连接中...";
                            disable();
                            break;
                        case WebSocket.OPEN:
                            stateLabel.innerHTML = "打开";
                            enable();
                            break;
                        default:
                            stateLabel.innerHTML = "未知的WebSocket状态: " + htmlEscape(socket.readyState);
                            disable();
                            break;
                    }
                }
            }
    
            closeButton.onclick = function () {
                if (!socket || socket.readyState !== WebSocket.OPEN) {
                    alert("没有连接Socket");
                }
                socket.close(1000, "从客户端关闭");
            };
            emptyButton.onclick = function () {
                commsLog.innerHTML = ""
            };
    
            sendButton.onclick = function () {
                if (!socket || socket.readyState !== WebSocket.OPEN) {
                    alert("没有连接Socket");
                }
                var data = sendMessage.value;
                socket.send(data);
                commsLog.innerHTML += '<tr>' +
                    '<td class="commslog-client">客户端</td>' +
                    '<td class="commslog-server">服务端</td>' +
                    '<td class="commslog-data">' + htmlEscape(data) + '</td></tr>';
            };
    
            connectButton.onclick = function () {
                stateLabel.innerHTML = "连接中";
                socket = new WebSocket(connectionUrl.value);
                socket.onopen = function (event) {
                    updateState();
                    commsLog.innerHTML += '<tr>' +
                        '<td colspan="3" class="commslog-data">连接已打开</td>' +
                        '</tr>';
                };
                socket.onclose = function (event) {
                    updateState();
                    commsLog.innerHTML += '<tr>' +
                        '<td colspan="3" class="commslog-data">连接关闭了。错误码: ' + htmlEscape(event.code) + '。原因:' + htmlEscape(event.reason) + '</td>' +
                        '</tr>';
                };
                socket.onerror = updateState;
                socket.onmessage = function (event) {
                    commsLog.innerHTML += '<tr>' +
                        '<td class="commslog-server">服务端</td>' +
                        '<td class="commslog-client">客户端</td>' +
                        '<td class="commslog-data">' + htmlEscape(event.data) + '</td></tr>';
                };
            };
    
            function htmlEscape(str) {
                return str.toString()
                    .replace(/&/g, '&')
                    .replace(/"/g, '"')
                    .replace(/'/g, ''')
                    .replace(/</g, '<')
                    .replace(/>/g, '>');
            }
        </script>
    </body>
    </html>
    

      

    完成,运行项目,跳转到我们的测试页面(如我的为:https://localhost:5001/WebSocket.html):

     

    我们链接一个观察者的身份:

     然后登陆一个用户A:(可以看到监控者收到了一条消息“人数为1”)

     然后登陆一个用户B:(可以看到监控者收到了一条消息“人数为2”)

     

     然后关闭用户A的浏览器:(可以看到监控者收到了一条消息“人数为1”) 

    【额外】并且还实现了用户给服务器发送消息,服务器对用户回复原来的消息和回复时间。(可以稍微改一下就可以实现聊天对话和群聊功能)

    【额外】并且还实现了用户被同一个用户挤下线的情况

    完毕

  • 相关阅读:
    TensorFlow 1.2.0新版本完美支持Python3.6,windows在cmd中输入pip install tensorflow就能下载应用最新tensorflow
    两眼论&矩阵变现理论结合打造赚钱大模式
    《影响力》6个使人顺从的武器之一互惠原理深入剖析
    电子书如何定位、如何取名呢?电子书文案模型的6个要点
    《影响力》顺从心理学6个使人顺从的策略
    SEO三种职位类型:编辑型SEO、技术型SEO、营销型SEO详解
    json-lib-2.4-jdk15.jar所需全部JAR包.rar java jsoup解析开彩网api接口json数据实例
    防DNS劫持教程,手动修复本地DNS教程
    拆分字符串
    计算目录下文件数
  • 原文地址:https://www.cnblogs.com/ping9719/p/13578078.html
Copyright © 2011-2022 走看看