来源:https://blog.csdn.net/i2blue/article/details/125288034
Program.cs
Program.cs
#region WebSockets // https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/websockets?view=aspnetcore-7.0 // 启用WebSockets, // KeepAliveInterval - 向客户端发送“ping”帧的频率,以确保代理保持连接处于打开状态。 // 默认值为 2 分钟。 // AllowedOrigins - 用于 WebSocket 请求的允许的 Origin 标头值列表。 // 默认情况下,允许使用所有源。 有关详细信息,请参阅本文中的 WebSocket 源限制。 var webSocketOptions = new WebSocketOptions { KeepAliveInterval = TimeSpan.FromMinutes(2) }; // 设置允许WebSocket连接的来源地址 //webSocketOptions.AllowedOrigins.Add("https://client.com"); //webSocketOptions.AllowedOrigins.Add("https://www.client.com"); app.UseWebSockets(webSocketOptions); //app.Use(async (context, next) => //{ // if (context.Request.Path == "/ws") // { // if (context.WebSockets.IsWebSocketRequest) // { // using var webSocket = await context.WebSockets.AcceptWebSocketAsync(); // await Echo(webSocket); // } // else // { // context.Response.StatusCode = StatusCodes.Status400BadRequest; // } // } // else // { // await next(context); // } //}); #endregion
controller版
public class WebSocketCenterController : Controller { private readonly ILogger<WebSocketCenterController> _logger; public WebSocketCenterController(ILogger<WebSocketCenterController> logger) { _logger = logger; } //原文链接:https://blog.csdn.net/i2blue/article/details/125288034 [HttpGet("/ws")] public async Task WebSocketServer() { // 判断为WebSocket请求 if (HttpContext.WebSockets.IsWebSocketRequest) { try { var socket = await HttpContext.WebSockets.AcceptWebSocketAsync(); await new WebSocketHelper().WebSocketReceive(socket); } catch (Exception ex) { _logger.LogError(ex, "WebSocketException"); } } } }
WebSocketHelper
public class WebSocketHelper { public async Task WebSocketReceive(WebSocket webSocket) { StringBuilder receiveBuilder = new StringBuilder(); var id = Guid.NewGuid().ToString("N"); //var buffer = ArrayPool<byte>.Shared.Rent(10); int byteLen = 10;//每次读取的字节数 var tempBuffs = new byte[byteLen]; List<byte> data = new List<byte>(); try { //循环接收,每次接收固定长度的字节。 while (webSocket.State == WebSocketState.Open) { var result = await webSocket.ReceiveAsync(tempBuffs, CancellationToken.None); if (result.MessageType == WebSocketMessageType.Close) { throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely, result.CloseStatusDescription); } //读取字节数小于字节数组长度,则说明数据已读取完毕。 if (result.Count < byteLen) { for (int i = 0; i < result.Count; i++) { data.Add(tempBuffs[i]); } //读取结束 var dataArray = data.ToArray(); //dataArray.AsSpan(0, dataArray.Length) var text = Encoding.UTF8.GetString(dataArray); var sendStr = Encoding.UTF8.GetBytes($"服务端 {id} : {text} -{DateTime.Now}"); await webSocket.SendAsync(sendStr, WebSocketMessageType.Text, true, CancellationToken.None); data.Clear(); } else { data.AddRange(tempBuffs.ToList()); } } } finally { //ArrayPool<byte>.Shared.Return(buffer); tempBuffs = null; data.Clear(); } } /// <summary> /// 创建客户端实例 /// </summary> /// <param name="cancellationToken"></param> /// <returns></returns> public static async Task<ClientWebSocket> CreateAsync(string ServerUri) { var webSocket = new ClientWebSocket(); webSocket.Options.RemoteCertificateValidationCallback = delegate { return true; }; await webSocket.ConnectAsync(new Uri(ServerUri), CancellationToken.None); if (webSocket.State == WebSocketState.Open) { return webSocket; } return null; } }
后端调用
[HttpPost] public async Task<IActionResult> Test() { ApiResult<string> result = new ApiResult<string>(); try { var webSocket = await WebSocketHelper.CreateAsync("ws://localhost:5196/ws"); if (webSocket != null) { Func<Task<string>> task = new Func<Task<string>>(async () => { int byteLen = 10;//每次读取的字节数 var tempBuffs = new byte[byteLen]; List<byte> data = new List<byte>(); string dataStr = ""; try { while (webSocket.State == WebSocketState.Open) { var result = await webSocket.ReceiveAsync(tempBuffs, CancellationToken.None); if (result.MessageType == WebSocketMessageType.Close) { throw new WebSocketException(WebSocketError.ConnectionClosedPrematurely, result.CloseStatusDescription); } //读取字节数小于字节数组长度,则说明数据已读取完毕。 if (result.Count < byteLen) { for (int i = 0; i < result.Count; i++) { data.Add(tempBuffs[i]); } //读取结束 var dataArray = data.ToArray(); dataStr = Encoding.UTF8.GetString(dataArray); break; } else { data.AddRange(tempBuffs.ToList()); } } } catch (Exception ex) { return ex.Message; } finally { //ArrayPool<byte>.Shared.Return(buffer); tempBuffs = null; data = null; } return dataStr; }); var sendStr = Encoding.UTF8.GetBytes("客户端发送数据"); await webSocket.SendAsync(sendStr, WebSocketMessageType.Text, true, CancellationToken.None); var dataRes = await Task.Run(task); result.ErrorCode = "0"; result.Data = dataRes; result.Message = "success"; } else { result.ErrorCode = "-1"; result.Data = "服务连接失败!"; result.Message = "failed"; } return Json(result); } catch (Exception ex) { _logger.LogError(ex, "##服务连接异常"); ViewData["Msg"] = ex.Message; result.ErrorCode = "-1"; result.Message = ex.Message; return Json(result); } }
前端调用
html
<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> <textarea id="txtDes" cols="80" rows="10"></textarea> <br /> <button id="send" onclick="send();">发送</button> <button onclick="quit();">停止</button> <button onclick="testSocket()">test</button>
js
/////////////////////////////////////////////////////// //var ws; //var msgContainer = document.getElementById('message'); //window.onload = function () { // ws = new WebSocket("ws://localhost:5196/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() { // var dataStr = $("#txtDes").val(); // ws.send(dataStr); // var htmlValue = "客户端: " + dataStr + " " + getNowTime(); // var msg = document.createElement('div'); // msg.style.color = '#ffff00'; // msg.innerHTML = htmlValue; // msgContainer.appendChild(msg); // $("#txtDes").val(""); // msgContainer.scrollTop = msgContainer.scrollHeight; //} ////获取当前时间 //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; //} //function testSocket(){ // $.ajax({ // url: "/Home/Test", // type: "post", // dataType: "json", // contentType: "application/json", // //data: JSON.stringify({ Idx: 1, ProductCode: "code1", ProductName: "name1", StockQty: 10, MakeQty: 4 }), // success: function (result, status) { // alert(result.message + "/" + result.data); // } // }); //} ///////////////////////////////////////////////////////
WebSocket中间件版本
using WebApp.Utils; namespace WebApp.Middlewares { /// <summary> /// webSocket /// </summary> public class WebSocketMiddleware { private readonly RequestDelegate _next; private readonly ILogger<ExceptionHandlingMiddleware> _logger; /// <summary> /// 构造 /// </summary> /// <param name="next"></param> /// <param name="actionPathName">目标路径</param> public WebSocketMiddleware(RequestDelegate next, ILogger<ExceptionHandlingMiddleware> logger) { _next = next; _logger = logger; } /// <summary> /// 中间件调用 /// </summary> /// <param name="httpContext"></param> /// <returns></returns> public async Task Invoke(HttpContext httpContext) { try { var socket = await httpContext.WebSockets.AcceptWebSocketAsync(); await new WebSocketHelper().WebSocketReceive(socket); } catch (Exception ex) { //调用日志处理对象的实例记录日志 _logger.LogError(ex, "##异常来源:{0}", httpContext.Request.Path); } await _next(httpContext); } } // Extension method used to add the middleware to the HTTP request pipeline. public static class WebSocketMiddlewareExtensions { public static IApplicationBuilder UseWebSocketMiddleware(this IApplicationBuilder builder) { return builder.UseMiddleware<WebSocketMiddleware>(); } } }
中间件,Program.cs中 app.UseWebSocketMiddleware();