NET7下用WebSocket做简易聊天室

NET7下用WebSocket做简易聊天室

步骤:

  1. 建立NET7的MVC视图模型控制器项目
  2. 创建websocket之间通信的JSON字符串对应的实体类
  3. 一个房间用同一个Websocket
  4. websocket集合类,N个房间
  5. 创建websocket中间件代码
  6. Program.cs中的核心代码,使用Websocket
  7. 聊天室HTML页面代码

参考文章:.NET Core中WebSocket的使用详解_.net websocket-CSDN博客

GIT源码地址:公开仓库 (里面还有以前做的.NET FRAMEWORK的websocket示例代码)

NET7下用WebSocket做简易聊天室_第1张图片

  1. 建立NET7的MVC视图模型控制器项目
  2. 创建websocket之间通信的JSON字符串对应的实体类
    namespace NetCore.WebSocketDemo.Models
    {
        /// 
        /// websocket之间通信的JSON字符串转的实体类
        /// 
        public class Message
        {
            /// 
            /// websocket对应的ID
            /// 
            public string SendClientId { set; get; }
            /// 
            /// 加入房间join 发送消息send_to_room 离开房间levea
            /// 
            public string action { set; get; }
            /// 
            /// 房间号
            /// 
            public string roomNo { set; get; }
            /// 
            /// 昵称
            /// 
            public string nick { set; get; }
            /// 
            /// 发送的消息内容 
            /// 
            public string msg { set; get; }
        }
    }

  3. 一个房间用同一个Websocket
    using System.Net.Sockets;
    using System.Net.WebSockets;
    using System.Text;
    
    namespace NetCore.WebSocketDemo.Models
    {
        /// 
        /// 一个房间里的都用这个websocket
        /// 
        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(recvBytes);
    
                try
                {
                    await WebSocket.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
                }
                catch (Exception ex)
                {
                    throw ex;
                } 
            }
        }
    }
    

  4. websocket集合类,N个房间
    namespace NetCore.WebSocketDemo.Models
    {
        /// 
        /// websocket集合类,N个房间
        /// 
        public class WebsocketClientCollection
        {
            private static List _clients = new List();
    
            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 GetAll()
            {
                return _clients;
            }
    
            public static List GetClientsByRoomNo(string roomNo)
            {
                var client = _clients.Where(c => c.RoomNo == roomNo);
                return client.ToList();
            }
        }
    }
    

  5. 创建websocket中间件代码
    using Newtonsoft.Json;
    using System.Net.WebSockets;
    using System.Text;
    
    namespace NetCore.WebSocketDemo.Models
    {
        /// 
        /// programe里用 app.UseWebsocketHandlerMiddleware();
        /// 
        public static class WebsocketHandlerMiddlewareExtensions
        {
            public static IApplicationBuilder UseWebsocketHandlerMiddleware(
                this IApplicationBuilder builder)
            {
                return builder.UseMiddleware();
            }
        }
        /// 
        /// websocket中间件
        /// 
        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(buffer), CancellationToken.None);
                    if (clientData.MessageType == WebSocketMessageType.Text && !clientData.CloseStatus.HasValue)
                    {
                        var msgString = Encoding.UTF8.GetString(buffer);
                      
                        var message = JsonConvert.DeserializeObject(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;
                }
            }
        }
    }
    

  6. Program.cs中的核心代码,使用Websocket
    var app = builder.Build();
    
                #region 配置中间件,使用websocket
                app.UseWebSockets(new WebSocketOptions
                {
                    KeepAliveInterval = TimeSpan.FromSeconds(60),
                    ReceiveBufferSize = 1 * 1024
                });
                app.UseWebsocketHandlerMiddleware(); 
                #endregion

  7. 聊天室HTML页面代码



    
    简易websocket聊天室应用


    
房间号:
我的昵称:

你可能感兴趣的:(C#,C#,NET7,WEBSOCKET,聊天室)