websocket广播与单播共用同一连接管理机制,核心在于线程安全的会话容器(如concurrenthashmap)、连接状态校验(isopen())、用户-会话绑定及统一消息格式;需避免内存泄漏、状态误判与id混淆。

WebSocket 的广播与单播不是两个独立功能,而是同一套连接管理机制下不同消息分发逻辑的体现——核心在于怎么存会话、怎么查用户、怎么发消息。
会话容器必须线程安全且及时清理
所有推送能力都依赖一个可读写、线程安全的活跃连接容器。推荐用 ConcurrentHashMap
- 禁止使用 HashMap 或 HashSet,多线程并发操作会抛 ConcurrentModificationException
- 连接关闭时必须显式从容器中移除 session,否则内存泄漏 + 广播失败(isOpen() 返回 false,但对象仍被引用)
- 建议在
afterConnectionClosed()回调中执行清理,同时校验 session 是否已失效
广播:遍历在线会话并逐个校验状态
广播本质是“向所有当前可用连接发送相同内容”,但不能无脑遍历发送。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 发送前必须调用
session.isOpen(),否则可能触发 IllegalStateException: Session is invalid - 避免在循环中调用
session.getRemoteAddress(),部分服务器(如 Jetty 9.4+)断连后该方法会抛 NullPointerException - 高并发场景下,建议用
CompletableFuture.runAsync()异步广播,防止阻塞主线程影响新连接接入
单点推送:靠用户标识做多终端路由
单点不等于“只推一个 session”,而是“推给某用户当前所有活跃终端”。关键步骤是绑定用户 ID 与 session。
- 连接建立时,从 token、URL 参数或握手请求头中提取 userId,并存入 session 属性:
session.getAttributes().put("uid", uid) - 维护 ConcurrentHashMap
> 实现用户 → 多 session 映射,读多写少场景更高效 - 用户登出或 token 失效时,必须主动遍历该用户所有 session 并调用
session.close(),不能依赖心跳超时清理 - 切勿把 userId 当作 session ID 使用——WebSocket 协议本身不携带身份信息,全靠应用层绑定和维护
实际编码中两个常见陷阱
一是消息格式未统一,导致前端解析失败;二是未区分连接上下文,把服务端 session ID 错当用户 ID 传给前端做单播依据。
- 建议消息体采用标准 JSON 结构,包含 type(broadcast/unicast)、from、to(单播时必填)、content 字段
- 单播时 to 字段应为业务用户 ID,而非 WebSocket session ID;服务端收到后根据 to 查用户映射表,再批量发给对应 session
- 测试阶段务必模拟多设备登录、网络中断重连、token 过期等边界情况,验证 session 清理与消息可达性










