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" /> <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>