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示例代码)

  1. 建立NET7的MVC视图模型控制器项目
  2. 创建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; }
        }
    }

  3. 一个房间用同一个Websocket
    using 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;
                } 
            }
        }
    }
    

  4. 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();
            }
        }
    }
    

  5. 创建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;
                }
            }
        }
    }
    

  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页面代码
<!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>

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java WebSocket是一种用于实现双向通信的网络协议,可以帮助我们实现简易聊天室。下面是一个基于Java WebSocket实现的简易聊天室的示例代码: 首先,我们需要定义一个WebSocket处理程序: ```java @ServerEndpoint("/chat") public class ChatEndpoint { private static Set<Session> sessions = Collections.synchronizedSet(new HashSet<Session>()); @OnOpen public void onOpen(Session session) { sessions.add(session); } @OnMessage public void onMessage(String message, Session session) throws IOException { for (Session s : sessions) { // 过滤自己 if (!s.equals(session)) { s.getBasicRemote().sendText(message); } } } @OnClose public void onClose(Session session) { sessions.remove(session); } } ``` 在这个处理程序中,我们使用`@ServerEndpoint("/chat")`注解指定了WebSocket的端点,即`/chat`。在`onOpen`方法中,我们将新的会话添加到会话集合中。在`onMessage`方法中,我们将接收到的消息广播给所有其他会话。在`onClose`方法中,我们将关闭的会话从会话集合中移除。 接下来,我们需要在`web.xml`文件中配置WebSocket: ```xml <web-app> <display-name>WebSocket Chat</display-name> <servlet> <servlet-name>chat</servlet-name> <servlet-class>org.glassfish.tyrus.servlet.TyrusServlet</servlet-class> <init-param> <param-name>org.glassfish.tyrus.servlet.websocketClassnames</param-name> <param-value>com.example.ChatEndpoint</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>chat</servlet-name> <url-pattern>/chat/*</url-pattern> </servlet-mapping> </web-app> ``` 在这个配置中,我们使用了`org.glassfish.tyrus.servlet.TyrusServlet`作为WebSocket的Servlet。我们将`com.example.ChatEndpoint`指定为WebSocket处理程序的类名,并将其加载到`servlet`中。 现在,我们就可以在HTML页面中使用WebSocket来连接我们的聊天室了: ```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>WebSocket Chat</title> </head> <body> <input type="text" id="message"> <button onclick="send()">Send</button> <div id="output"></div> <script> var socket = new WebSocket('ws://localhost:8080/chat'); socket.onmessage = function (event) { var output = document.getElementById('output'); output.innerHTML += event.data + '<br>'; }; function send() { var message = document.getElementById('message').value; socket.send(message); } </script> </body> </html> ``` 在这个HTML页面中,我们创建了一个WebSocket连接到`ws://localhost:8080/chat`。当收到消息时,我们将其添加到页面上的`<div>`元素中。当点击发送按钮时,我们将输入框中的文本发送到WebSocket连接中。 这样,我们就完成了一个简易的Java WebSocket聊天室的实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值