NET7下用WebSocket做简易聊天室
NET7下用WebSocket做简易聊天室
步骤:
- 建立NET7的MVC视图模型控制器项目
- 创建websocket之间通信的JSON字符串对应的实体类
- 一个房间用同一个Websocket
- websocket集合类,N个房间
- 创建websocket中间件代码
- Program.cs中的核心代码,使用Websocket
- 聊天室HTML页面代码
GIT源码地址:https://niunan.coding.net/public/WebSocketDemo/WebSocketDemo/git/files (里面还有以前做的.NET FRAMEWORK的websocket示例代码)

- 建立NET7的MVC视图模型控制器项目
- 创建websocket之间通信的JSON字符串对应的实体类
namespace NetCore.WebSocketDemo.Models { /// <summary> /// websocket之间通信的JSON字符串转的实体类 /// </summary> public class Message { /// <summary> /// websocket对应的ID /// </summary> public string SendClientId { set; get; } /// <summary> /// 加入房间join 发送消息send_to_room 离开房间levea /// </summary> public string action { set; get; } /// <summary> /// 房间号 /// </summary> public string roomNo { set; get; } /// <summary> /// 昵称 /// </summary> public string nick { set; get; } /// <summary> /// 发送的消息内容 /// </summary> public string msg { set; get; } } }
- 一个房间用同一个Websocket
12345678910111213141516171819202122232425262728293031using
System.Net.Sockets;
using
System.Net.WebSockets;
using
System.Text;
namespace
NetCore.WebSocketDemo.Models
{
/// <summary>
/// 一个房间里的都用这个websocket
/// </summary>
public
class
WebsocketClient
{
public
string
Id {
set
;
get
; }
public
string
RoomNo {
set
;
get
; }
public
WebSocket WebSocket {
set
;
get
; }
public
async Task SendMessageAsync(
string
text)
{
var
recvBytes = Encoding.UTF8.GetBytes(text);
var
sendBuffer =
new
ArraySegment<
byte
>(recvBytes);
try
{
await WebSocket.SendAsync(sendBuffer, WebSocketMessageType.Text,
true
, CancellationToken.None);
}
catch
(Exception ex)
{
throw
ex;
}
}
}
}
- websocket集合类,N个房间
namespace NetCore.WebSocketDemo.Models { /// <summary> /// websocket集合类,N个房间 /// </summary> public class WebsocketClientCollection { private static List<WebsocketClient> _clients = new List<WebsocketClient>(); public static void Add(WebsocketClient client) { _clients.Add(client); } public static void Remove(WebsocketClient client) { _clients.Remove(client); } public static WebsocketClient Get(string clientId) { var client = _clients.FirstOrDefault(c => c.Id == clientId); return client; } public static List<WebsocketClient> GetAll() { return _clients; } public static List<WebsocketClient> GetClientsByRoomNo(string roomNo) { var client = _clients.Where(c => c.RoomNo == roomNo); return client.ToList(); } } }
- 创建websocket中间件代码
using Newtonsoft.Json; using System.Net.WebSockets; using System.Text; namespace NetCore.WebSocketDemo.Models { /// <summary> /// programe里用 app.UseWebsocketHandlerMiddleware(); /// </summary> public static class WebsocketHandlerMiddlewareExtensions { public static IApplicationBuilder UseWebsocketHandlerMiddleware( this IApplicationBuilder builder) { return builder.UseMiddleware<WebsocketHandlerMiddleware>(); } } /// <summary> /// websocket中间件 /// </summary> public class WebsocketHandlerMiddleware { private readonly RequestDelegate _next; public WebsocketHandlerMiddleware( RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { if (context.Request.Path == "/ws") { //仅当网页执行new WebSocket("ws://localhost:5000/ws")时,后台会执行此逻辑 if (context.WebSockets.IsWebSocketRequest) { //后台成功接收到连接请求并建立连接后,前台的webSocket.onopen = function (event){}才执行 WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync(); string clientId = Guid.NewGuid().ToString(); ; var wsClient = new WebsocketClient { Id = clientId, WebSocket = webSocket }; try { await Handle(wsClient); } catch (Exception ex) { await context.Response.WriteAsync("closed"); } } else { context.Response.StatusCode = 404; } } else { await _next(context); } } private async Task Handle(WebsocketClient websocketClient) { WebsocketClientCollection.Add(websocketClient); WebSocketReceiveResult clientData = null; do { var buffer = new byte[1024 * 1]; //客户端与服务器成功建立连接后,服务器会循环异步接收客户端发送的消息,收到消息后就会执行Handle(WebsocketClient websocketClient)中的do{}while;直到客户端断开连接 //不同的客户端向服务器发送消息后台执行do{}while;时,websocketClient实参是不同的,它与客户端一一对应 //同一个客户端向服务器多次发送消息后台执行do{}while;时,websocketClient实参是相同的 clientData = await websocketClient.WebSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); if (clientData.MessageType == WebSocketMessageType.Text && !clientData.CloseStatus.HasValue) { var msgString = Encoding.UTF8.GetString(buffer); var message = JsonConvert.DeserializeObject<Message>(msgString); message.SendClientId = websocketClient.Id; HandleMessage(message); } } while (!clientData.CloseStatus.HasValue); //关掉使用WebSocket连接的网页/调用webSocket.close()后,与之对应的后台会跳出循环 WebsocketClientCollection.Remove(websocketClient); } private void HandleMessage(Message message) { var client = WebsocketClientCollection.Get(message.SendClientId); switch (message.action) { case "join": client.RoomNo = message.roomNo; client.SendMessageAsync($"{message.nick} join room {client.RoomNo} success ."); break; case "send_to_room": if (string.IsNullOrEmpty(client.RoomNo)) { break; } var clients = WebsocketClientCollection.GetClientsByRoomNo(client.RoomNo); clients.ForEach(c => { c.SendMessageAsync(message.nick + " : " + message.msg); }); break; case "leave": #region 通过把连接的RoomNo置空模拟关闭连接 var roomNo = client.RoomNo; client.RoomNo = ""; #endregion #region 后台关闭连接 //client.WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None); //WebsocketClientCollection.Remove(client); #endregion client.SendMessageAsync($"{message.nick} leave room {roomNo} success ."); break; default: break; } } } }
- Program.cs中的核心代码,使用Websocket
var app = builder.Build(); #region 配置中间件,使用websocket app.UseWebSockets(new WebSocketOptions { KeepAliveInterval = TimeSpan.FromSeconds(60), ReceiveBufferSize = 1 * 1024 }); app.UseWebsocketHandlerMiddleware(); #endregion
- 聊天室HTML页面代码
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>简易websocket聊天室应用</title> </head> <body> <div style="margin-bottom:5px;"> 房间号: <input type="text" id="txtRoomNo" value="99999" /> <button id="btnJoin">加入房间</button> <button id="btnLeave">离开房间</button> <button id="btnDisConnect">断开链接</button> </div> <div style="margin-bottom:5px;"> 我的昵称: <input type="text" id="txtNickName" value="niunan" /> </div> <div style="height:300px;width:600px"> <textarea style="height:100%;width:100%" id="msgList"></textarea> <div style="text-align: right"> <input type="text" id="txtMsg" value="" placeholder="请输入您要发送的文本消息" /> <button id="btnSend">发送</button> </div> </div> <script src="lib/jquery/dist/jquery.min.js"></script> <script> var webSocket = new WebSocket("ws://localhost:5160/ws"); //前台向后台发送连接请求,后台成功接收并建立连接后才会触发此事件 webSocket.onopen = function (event) { console.log("Connection opened..."); $("#msgList").val("WebSocket connection opened"); }; //后台向前台发送消息,前台成功接收后会触发此事件 webSocket.onmessage = function (event) { console.log("Received message: " + event.data); if (event.data) { var content = $('#msgList').val(); content = content + '\r\n' + event.data; $('#msgList').val(content); } }; //后台关闭连接后/前台关闭连接后都会触发此事件 webSocket.onclose = function (event) { console.log("Connection closed..."); var content = $('#msgList').val(); content = content + '\r\nWebSocket connection closed'; $('#msgList').val(content); }; $('#btnJoin').on('click', function () { var roomNo = $('#txtRoomNo').val(); var nick = $('#txtNickName').val(); if (!roomNo) { alert("请输入RoomNo"); return; } var msg = { action: 'join', roomNo: roomNo, nick: nick }; if (CheckWebSocketConnected(webSocket)) { webSocket.send(JSON.stringify(msg)); } }); $('#btnSend').on('click', function () { var message = $('#txtMsg').val(); var nick = $('#txtNickName').val(); if (!message) { alert("请输入发生的内容"); return; } if (CheckWebSocketConnected(webSocket)) { webSocket.send(JSON.stringify({ action: 'send_to_room', msg: message, nick: nick })); } }); $('#btnLeave').on('click', function () { var nick = $('#txtNickName').val(); var msg = { action: 'leave', roomNo: '', nick: nick }; if (CheckWebSocketConnected(webSocket)) { webSocket.send(JSON.stringify(msg)); } }); $("#btnDisConnect").on("click", function () { if (CheckWebSocketConnected(webSocket)) { //部分浏览器调用close()方法关闭WebSocket时不支持传参 //webSocket.close(001, "closeReason"); webSocket.close(); } }); //判断当前websocket的状态 /* CONNECTING:值为0,表示正在连接。 OPEN:值为1,表示连接成功,可以通信。 CLOSING:值为2,表示连接正在关闭。 CLOSED:值为3,表示连接已经关闭,或者打开连接失败。 */ function CheckWebSocketConnected(ws) { var b = false; switch (ws.readyState) { case WebSocket.CONNECTING: // 也可以用0 // do something break; case WebSocket.OPEN: // 也可以用1 // do something b = true; break; case WebSocket.CLOSING: // 也可以用2 // do something break; case WebSocket.CLOSED: // 也可以用3 // do something break; default: // this never happens break; } return b; } </script> </body> </html>
撸码:复制、粘贴,拿起键盘就是“干”!!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2016-10-20 apache做转发
2016-10-20 绑定DDL控件方法