net core websockets 消息推送

 

来源:理解ASP.NET Core 中的WebSocket_aspnetcore websocket-CSDN博客

 

 

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Common
{
    /// <summary>
    /// 创建保存 WebSocket 的类
    /// </summary>
    public class WebSocketsManager
    {
        private readonly ConcurrentDictionary<string, WebSocket> _connections =
            new ConcurrentDictionary<string, WebSocket>();

        /// <summary>
        /// 获取所有 sockets 的字典集合
        /// </summary>
        /// <returns></returns>
        public ConcurrentDictionary<string, WebSocket> GetAllConnections()
        {
            return _connections;
        }

        /// <summary>
        ///  获取指定 id 的 socket
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public WebSocket GetSocketById(string id)
        {
            return _connections.FirstOrDefault(x => x.Key == id).Value;
        }

        /// <summary>
        /// 根据socket 获取其id
        /// </summary>
        /// <param name="socket"></param>
        /// <returns></returns>
        public string GetId(WebSocket socket)
        {
            return _connections.FirstOrDefault(x => x.Value == socket).Key;
        }

        /// <summary>
        /// 删除指定 id 的 socket,并关闭该链接
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task RemoveSocketAsync(string id)
        {
            _connections.TryRemove(id, out var socket);
            await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "socket connection closed",
                CancellationToken.None);
        }

        /// <summary>
        /// 添加一个 socket
        /// </summary>
        /// <param name="socket"></param>
        public void AddSocket(WebSocket socket)
        {
            _connections.TryAdd(CreateId(), socket);
        }

        /// <summary>
        /// 创建 id
        /// </summary>
        /// <returns></returns>
        private string CreateId()
        {
            return Guid.NewGuid().ToString("N");
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Common
{
    /// <summary>
    /// 管理和操作 WebSocket 的基类
    /// 处理 socket 的连接和断连,以及接收和发送消
    /// </summary>
    public abstract class WebSocketsHandler
    {
        public WebSocketsManager WebSockets { get; set; }

        protected WebSocketsHandler(WebSocketsManager webSockets)
        {
            WebSockets = webSockets;
        }

        /// <summary>
        /// 连接一个 socket
        /// </summary>
        /// <param name="socket"></param>
        /// <returns></returns>
        public virtual async Task OnConnected(WebSocket socket)
        {
            await Task.Run(() => { WebSockets.AddSocket(socket); });
        }

        /// <summary>
        /// 断开指定 socket
        /// </summary>
        /// <param name="socket"></param>
        /// <returns></returns>
        public virtual async Task OnDisconnected(WebSocket socket)
        {
            await WebSockets.RemoveSocketAsync(WebSockets.GetId(socket));
        }

        /// <summary>
        /// 发送消息给指定 socket
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public async Task SendMessage(WebSocket socket, string message)
        {
            if (socket.State != WebSocketState.Open) return;

            await socket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(message)),
                WebSocketMessageType.Text, true, CancellationToken.None);
        }

        /// <summary>
        /// 发送消息给指定 id 的 socket
        /// </summary>
        /// <param name="id"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public async Task SendMessage(string id, string message)
        {
            await SendMessage(WebSockets.GetSocketById(id), message);
        }

        /// <summary>
        /// 给所有 sockets 发送消息
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public async Task SendMessageToAll(string message)
        {
            foreach (var connection in WebSockets.GetAllConnections()) await SendMessage(connection.Value, message);
        }

        /// <summary>
        /// 接收到消息
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="result"></param>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public abstract Task Receive(WebSocket socket, WebSocketReceiveResult result,
            byte[] buffer);
    }
}
using System;
using System.Buffers;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Common
{
    /// <summary>
    /// 创建 WebSocket 管理子类
    /// </summary>
    public class WebSocketsHelper : WebSocketsHandler
    {
        public WebSocketsHelper(WebSocketsManager webSockets) : base(webSockets)
        {

        }

        public override async Task OnConnected(WebSocket socket)
        {
            await base.OnConnected(socket);
            var socketId = WebSockets.GetId(socket);
            await SendMessageToAll($"{socketId}已加入");
        }

        public override async Task OnDisconnected(WebSocket socket)
        {
            await base.OnDisconnected(socket);
            var socketId = WebSockets.GetId(socket);
            await SendMessageToAll($"{socketId}离开了");
        }

        public override async Task Receive(WebSocket socket, WebSocketReceiveResult result, byte[] buffer)
        {
            var socketId = WebSockets.GetId(socket);
            var message = $"{socketId} 发送了消息:{Encoding.UTF8.GetString(buffer, 0, result.Count)}";
            await SendMessageToAll(message);
        }
    }
}
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 Common
{
    /// <summary>
    /// webSocket 中间件
    /// </summary>
    public class WebSocketsMiddleware
    {
        private readonly RequestDelegate _next;
        private WebSocketsHandler WebSockets { get; }

        public WebSocketsMiddleware(RequestDelegate next, WebSocketsHandler webSockets)
        {
            _next = next;
            WebSockets = webSockets;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            if (context.WebSockets.IsWebSocketRequest)
            {
                // 转换当前连接为一个 ws 连接
                var socket = await context.WebSockets.AcceptWebSocketAsync();
                await WebSockets.OnConnected(socket);

                // 接收消息的 buffer
                var buffer = new byte[1024 * 4];
                // 判断连接类型,并执行相应操作
                while (socket.State == WebSocketState.Open)
                {
                    // 这句执行之后,buffer 就是接收到的消息体,可以根据需要进行转换。
                    var result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                    switch (result.MessageType)
                    {
                        case WebSocketMessageType.Text:
                            await WebSockets.Receive(socket, result, buffer);
                            break;
                        case WebSocketMessageType.Close:
                            await WebSockets.OnDisconnected(socket);
                            break;
                        case WebSocketMessageType.Binary:
                            break;
                        default:
                            throw new ArgumentOutOfRangeException();
                    }
                }
            }
            else
            {
                await _next(context);
            }
        }

    }
}
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Common
{
    /// <summary>
    /// 
    /// </summary>
    public static class WebSocketsExtension
    {
        public static IServiceCollection AddWebSocketManager(this IServiceCollection services)
        {
            services.AddTransient<WebSocketsManager>();
            services.AddScoped<WebSocketsHelper>();
            return services;
        }

        public static IApplicationBuilder MapSockets(this IApplicationBuilder app, PathString path, WebSocketsHandler socket)
        {
            return app.Map(path, x => x.UseMiddleware<WebSocketsMiddleware>(socket));
        }

    }
}

 

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
</head>
<body>
    webSocket Server demo
    <div id="message" style="border: solid 1px #333; padding: 4px; width: 550px; overflow: auto; background-color: #404040; height: 300px; margin-bottom: 8px; font-size: 14px;">
    </div>
    <input id="text" type="text" onkeypress="enter(event);" style="width: 340px" />
    &nbsp;&nbsp;
    <button id="send" onclick="send();">发送</button>
    <button onclick="quit();">停止</button>
</body>
</html>
<script type="text/javascript">
    var ws;
    var msgContainer = document.getElementById('message');
    var text = document.getElementById('text');
    window.onload = function () {
        ws = new WebSocket("ws://localhost:5000/ws");
        ws.onopen = function (e) {
            var msg = document.createElement('div');
            msg.style.color = '#0f0';
            msg.innerHTML = "Server > connection open.";
            msgContainer.appendChild(msg);
        };
        ws.onmessage = function (e) {
            var msg = document.createElement('div');
            msg.style.color = '#0f0';
            msg.innerHTML = e.data;
            msgContainer.appendChild(msg);
            msgContainer.scrollTop = msgContainer.scrollHeight;
        };
        ws.onerror = function (e) {
            var msg = document.createElement('div');
            msg.style.color = '#0f0';
            msg.innerHTML = 'Server > ' + e.data;
            msgContainer.appendChild(msg);
        };
        ws.onclose = function (e) {
            var msg = document.createElement('div');
            msg.style.color = '#0f0';
            msg.innerHTML = 'Server > connection closed.';
            msgContainer.appendChild(msg);
            ws = null;
        };
    }
    function quit() {
        if (ws) {
            ws.close();
            var msg = document.createElement('div');
            msg.style.color = '#0f0';
            msg.innerHTML = 'Server >start closed.';
            msgContainer.appendChild(msg);
            ws = null;
        }
    }
    function send() {
        ws.send(text.value);
        var htmlValue = "客户端: " + text.value + "  " + getNowTime();
        var msg = document.createElement('div');
        msg.style.color = '#ffff00';
        msg.innerHTML = htmlValue;
        msgContainer.appendChild(msg);
        text.value = "";
        msgContainer.scrollTop = msgContainer.scrollHeight;
    }
    function enter(event) {
        if (event.keyCode == 13) {
            send();
        }
    }
    //获取当前时间
    function getNowTime() {
        var date = new Date();
        //年 getFullYear():四位数字返回年份
        var year = date.getFullYear(); //getFullYear()代替getYear()
        //月 getMonth():0 ~ 11
        var month = date.getMonth() + 1;
        //日 getDate():(1 ~ 31)
        var day = date.getDate();
        //时 getHours():(0 ~ 23)
        var hour = date.getHours();
        //分 getMinutes(): (0 ~ 59)
        var minute = date.getMinutes();
        //秒 getSeconds():(0 ~ 59)
        var second = date.getSeconds();
        var time = year + '/' + addZero(month) + '/' + addZero(day) + ' ' + addZero(hour) + ':' + addZero(minute) + ':' + addZero(second);
        return time;
    }
    //小于10的拼接上0字符串
    function addZero(s) {
        return s < 10 ? ('0' + s) : s;
    }
</script>

 

posted on 2024-06-26 16:34  夕颜博客  阅读(64)  评论(0编辑  收藏  举报

导航