Java WebSocket案例

wen java案例 2

本文目录导读:

Java WebSocket案例

  1. 目录导读
  2. WebSocket核心原理与Java生态选型
  3. 项目环境搭建与依赖配置
  4. 服务端核心代码实现(@ServerEndpoint)
  5. 客户端连接与消息收发完整案例
  6. 连接管理与心跳检测机制
  7. 常见问题排查与性能优化建议
  8. 面试高频问答环节

Java WebSocket实战案例:从零搭建实时消息推送系统(附完整代码)

目录导读

  1. WebSocket核心原理与Java生态选型
  2. 项目环境搭建与依赖配置
  3. 服务端核心代码实现(@ServerEndpoint)
  4. 客户端连接与消息收发完整案例
  5. 连接管理与心跳检测机制
  6. 常见问题排查与性能优化建议
  7. 面试高频问答环节

WebSocket核心原理与Java生态选型

WebSocket是一种在单个TCP连接上进行全双工通信的协议,它解决了HTTP协议只能由客户端发起请求的局限性,在Java生态中,主流的实现方案包括JSR 356标准API(javax.websocket)、Spring WebSocket模块以及Netty高性能框架。

为什么选择JSR 356?
对于大多数企业级应用,无需引入额外框架,原生API足够轻量,本文案例基于Servlet 3.1+容器(如Tomcat 9+)实现,兼容性最好。


项目环境搭建与依赖配置

Maven依赖(pom.xml核心部分):

<dependency>
    <groupId>javax.websocket</groupId>
    <artifactId>javax.websocket-api</artifactId>
    <version>1.1</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>

关键点: provided作用域确保容器(Tomcat)提供实现类,避免冲突。


服务端核心代码实现(@ServerEndpoint)

这是一个完整可运行的WebSocket服务端案例,包含连接管理、消息群发、异常处理:

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
@ServerEndpoint("/chat")
public class ChatEndpoint {
    // 线程安全的连接集合
    private static final CopyOnWriteArraySet<ChatEndpoint> CONNECTIONS = new CopyOnWriteArraySet<>();
    private Session session;
    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        CONNECTIONS.add(this);
        broadcast("用户上线,当前在线人数:" + CONNECTIONS.size());
    }
    @OnMessage
    public void onMessage(String message, Session session) {
        broadcast("用户消息:" + message);
    }
    @OnClose
    public void onClose() {
        CONNECTIONS.remove(this);
        broadcast("用户下线,当前在线人数:" + CONNECTIONS.size());
    }
    @OnError
    public void onError(Throwable error) {
        error.printStackTrace();
    }
    private static void broadcast(String msg) {
        for (ChatEndpoint client : CONNECTIONS) {
            try {
                client.session.getBasicRemote().sendText(msg);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

设计要诀: 使用CopyOnWriteArraySet保证高并发下的读写安全,广播方法遍历所有会话发送消息。


客户端连接与消息收发完整案例

HTML5 JavaScript客户端(原生实现):

let ws = new WebSocket("ws://your-server.com/websocket/chat");
ws.onopen = function() {
    console.log("连接已建立");
    ws.send("你好,服务器!");
};
ws.onmessage = function(event) {
    console.log("收到消息:" + event.data);
    // 实时更新UI
    document.getElementById("messages").innerHTML += `<p>${event.data}</p>`;
};
ws.onclose = function() {
    console.log("连接关闭");
};
// 发送消息函数
function sendMsg() {
    const input = document.getElementById("input");
    ws.send(input.value);
    input.value = "";
}

测试步骤: 启动Tomcat后,打开两个浏览器标签页访问同页面,即可看到双向实时通信效果。


连接管理与心跳检测机制

为什么需要心跳? 长连接中,代理服务器(如Nginx)会主动断开空闲连接,导致僵尸连接占用资源。

服务端心跳方案(配合定时任务):

// 定期发送ping包,服务器端只需在容器层处理
// 客户端需实现:
ws.onclose = function() {
    // 自动重连,指数退避算法
    setTimeout(() => { connect(); }, 3000);
};

最佳实践: 建议设置session.setMaxIdleTimeout(30000),并配合客户端30秒自动重连逻辑。


常见问题排查与性能优化建议

高频问题:

  • 连接失败: 检查ws://wss://协议是否与页面HTTPS匹配
  • 消息乱码: 服务端统一使用UTF-8编码
  • 内存泄漏: 确保onClose中移除无用引用

性能优化四板斧:

  1. 使用消息压缩(如permessage-deflate)
  2. 设置合理的最大消息大小(默认8K,可调)
  3. 通过异步发送sendMessage替代sendText
  4. 多节点部署时使用Redis发布订阅实现跨节点广播

面试高频问答环节

Q1:WebSocket和HTTP长轮询有什么区别?
A:WebSocket只需一次握手建立持久连接,服务端可主动推送;长轮询每次请求都携带完整HTTP头,且推延时高于WebSocket,线连接数利用率完全不在一个量级。

Q2:如何处理在线用户列表的一致性?
A:常规做法是维护ConcurrentHashMap映射userId到Session,但集群环境下必须引入分布式存储(如Redis)记录在线状态,并通过广播通知所有节点更新。

Q3:什么是WebSocket的子协议(subprotocol)?
A:子协议是应用层协议标识,如STOMP,Java端可用@ServerEndpoint(value="/chat", subprotocols={"stomp"})声明,用于消息路由和订阅管理。

Q4:如何防御WebSocket的跨站点劫持攻击?
A:校验Origin请求头,拒绝非白名单来源;正确实现鉴权(握手阶段传递token);使用WSS加密传输。


本文从一个可运行的案例出发,完整讲解了Java WebSocket的编码规范、生命周期管理、生产级优化方向,掌握这些要点后,即可构建出支撑千万级并发的实时交互系统,建议在真实项目中,结合Spring的WebSocketHandler进行更细粒度的消息拦截,或使用Netty获得极致性能。

抱歉,评论功能暂时关闭!