2026/1/10 12:41:16
网站建设
项目流程
腾讯网站建设公司,wordpress更改ico,石家庄网站建设找汉狮,做网页的素材#x1f4e1; 前言#xff1a;为什么选 Netty-SocketIO#xff1f;
Spring 官方提供了 spring-boot-starter-websocket#xff0c;为什么不用#xff1f;
虽然官方的支持 STOMP 协议#xff0c;上手简单#xff0c;但在面对高并发、长连接维持、心跳检测、断线自动重连等… 前言为什么选 Netty-SocketIOSpring 官方提供了spring-boot-starter-websocket为什么不用虽然官方的支持 STOMP 协议上手简单但在面对高并发、长连接维持、心跳检测、断线自动重连等复杂场景时基于Netty封装的netty-socketio表现得更加稳健和高性能。它完美适配了前端的socket.io-client库让前后端联调变得异常简单。️ 一、 架构设计用户如何找到彼此IM 系统的核心在于**“路由”**当 UserA 发消息给 UserB 时服务器怎么知道 UserB 的长连接是哪一个我们需要维护一张用户 ID – Socket Session的映射表。IM 消息流转图 (Mermaid):IM 核心服务1. 发送消息 {to: UserB}2. 查找 SessionMap3. 获取 UserB 的连接4. 异步持久化5. 推送事件 push_event6. 收到消息用户 A (Vue 前端)Netty ServerMap: UserId - UUIDSocketIOClient (UserB)MySQL / MongoDB用户 B (Vue 前端)渲染聊天气泡️ 二、 后端实战搭建 Netty-SocketIO 服务1. 引入依赖dependencygroupIdcom.corundumstudio.socketio/groupIdartifactIdnetty-socketio/artifactIdversion1.7.22/version/dependency2. 配置启动类 (SocketIOConfig.java)我们不使用 Tomcat 的端口而是另起一个 Netty 端口如 9092。ConfigurationpublicclassSocketIOConfig{BeanpublicSocketIOServersocketIOServer(){com.corundumstudio.socketio.Configurationconfignewcom.corundumstudio.socketio.Configuration();config.setHostname(localhost);config.setPort(9092);// 关键设置最大帧长度防止发大图报错config.setMaxFramePayloadLength(1024*1024);config.setMaxHttpContentLength(1024*1024);// 握手协议参数SocketConfigsocketConfignewSocketConfig();socketConfig.setReuseAddress(true);config.setSocketConfig(socketConfig);returnnewSocketIOServer(config);}// Spring Boot 启动时同时启动 Netty 服务BeanpublicSpringAnnotationScannerspringAnnotationScanner(SocketIOServersocketServer){returnnewSpringAnnotationScanner(socketServer);}}3. 核心业务逻辑 (MessageEventHandler.java)这里实现了上线注册、单聊、群聊逻辑。ComponentpublicclassMessageEventHandler{// 线程安全的 Map存储 UserId - SocketClient 的映射publicstaticfinalConcurrentHashMapString,UUIDUSER_CLIENT_MAPnewConcurrentHashMap();AutowiredprivateSocketIOServerserver;// --- 1. 客户端连接 (握手) ---OnConnectpublicvoidonConnect(SocketIOClientclient){// 前端连接时带上参数http://localhost:9092?userId1001StringuserIdclient.getHandshakeData().getSingleUrlParam(userId);if(userId!null){USER_CLIENT_MAP.put(userId,client.getSessionId());System.out.println(用户上线: userId);}}// --- 2. 客户端断开 ---OnDisconnectpublicvoidonDisconnect(SocketIOClientclient){StringuserIdclient.getHandshakeData().getSingleUrlParam(userId);if(userId!null){USER_CLIENT_MAP.remove(userId);System.out.println(用户下线: userId);}}// --- 3. 处理单聊消息 ---OnEvent(send_msg)publicvoidonEvent(SocketIOClientclient,ChatMessageRequestdata){StringtoUserIddata.getToUserId();UUIDtargetSessionIdUSER_CLIENT_MAP.get(toUserId);// 如果用户在线直接推送if(targetSessionId!nullserver.getClient(targetSessionId)!null){server.getClient(targetSessionId).sendEvent(receive_msg,data);}else{// 用户不在线存入数据库标记为“未读消息”saveOfflineMessage(data);}}// --- 4. 处理群聊 (加入房间) ---OnEvent(join_group)publicvoidonJoinGroup(SocketIOClientclient,StringgroupId){client.joinRoom(groupId);// SocketIO 自带房间管理}OnEvent(send_group_msg)publicvoidonGroupMsg(SocketIOClientclient,ChatMessageRequestdata){// 直接向房间内广播server.getRoomOperations(data.getGroupId()).sendEvent(receive_group_msg,data);}} 三、 前端 Vue3 实战Socket.io-client前端使用socket.io-client库代码极其简洁。安装npminstallsocket.io-client连接与收发import{io}fromsocket.io-client;// 1. 建立连接 (带上自己的 ID)constsocketio(http://localhost:9092,{query:{userId:1001},transports:[websocket]// 强制使用 WebSocket不用轮询});// 2. 监听连接成功socket.on(connect,(){console.log(连接成功SessionID:,socket.id);});// 3. 接收消息 (监听 receive_msg 事件)socket.on(receive_msg,(data){console.log(收到新消息:,data);// 这里将 data push 到聊天记录数组中页面会自动渲染messages.value.push(data);});// 4. 发送消息constsendMessage(){socket.emit(send_msg,{fromUserId:1001,toUserId:1002,content:你好今晚吃什么,type:text});}; 四、 进阶挑战分布式集群下的 Session 共享如果你的用户量达到 10 万一台服务器扛不住你需要部署两台 Netty 服务。问题来了UserA 连上了 Server1UserB 连上了 Server2。UserA 发消息给 UserBServer1 的内存 Map 里找不到 UserB 的 Session怎么办解决方案Redis Pub/Sub (发布订阅)Server1 发现 UserB 不在本地。Server1 将消息 Publish 到 Redis 的频道IM_CHANNEL。Server2 订阅了该频道收到消息后发现 UserB 在自己这儿。Server2 将消息推送给 UserB。Redisson 提供了很好的支持或者直接使用 Socket.IO 官方的Redis Adapter。 总结通过 Spring Boot Netty-SocketIO我们只用了几百行代码就实现了一个高实时性的 IM 系统核心。这不仅是一个聊天工具它还是即时通知、在线客服、游戏对战等场景的基石。Next Step:现在的消息只存在内存里重启就丢了。试着引入MongoDB来存储聊天记录写入速度快结构灵活并实现“历史消息回溯”功能你的 IM 系统就具备商业价值了