WebSocket 与长连接
问题
WebSocket 和 HTTP 有什么区别?什么时候用 WebSocket?
答案
WebSocket vs HTTP
| 维度 | HTTP | WebSocket |
|---|---|---|
| 通信方向 | 请求-响应(单向) | 全双工(双向) |
| 连接 | 短连接(Keep-Alive 复用) | 长连接 |
| 协议 | http:// / https:// | ws:// / wss:// |
| 数据格式 | 文本(有 Header 开销) | 帧(开销小) |
| 服务端推送 | 不支持(需轮询) | 原生支持 |
WebSocket 握手过程
WebSocket 基于 HTTP 升级协议建立连接。
// 客户端请求升级
GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
// 服务端同意升级
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
握手完成后,TCP 连接保持,双方可以随时互发数据。
实时通信方案对比
| 方案 | 原理 | 延迟 | 适用场景 |
|---|---|---|---|
| 短轮询 | 客户端定时请求 | 高(轮询间隔) | 简单场景 |
| 长轮询 | 服务端 hold 住请求,有数据再返回 | 中等 | 兼容性要求高 |
| SSE | 服务端单向推送 | 低 | 单向通知、日志流 |
| WebSocket | 全双工 | 最低 | IM、实时协作、游戏 |
Java WebSocket(Spring)
Spring WebSocket 服务端
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(chatHandler(), "/ws/chat")
.setAllowedOrigins("*");
}
@Bean
public WebSocketHandler chatHandler() {
return new ChatWebSocketHandler();
}
}
public class ChatWebSocketHandler extends TextWebSocketHandler {
// 保存所有在线连接
private final Set<WebSocketSession> sessions = ConcurrentHashMap.newKeySet();
@Override
public void afterConnectionEstablished(WebSocketSession session) {
sessions.add(session);
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message)
throws Exception {
// 广播消息给所有在线用户
for (WebSocketSession s : sessions) {
if (s.isOpen()) {
s.sendMessage(message);
}
}
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
sessions.remove(session);
}
}
常见面试问题
Q1: WebSocket 如何保持连接不断开?
答案:
通过心跳机制:客户端或服务端定时发送 Ping 帧,对方回复 Pong 帧。如果超过一定时间没收到 Pong,认为连接断开,触发重连。
Q2: WebSocket 集群部署怎么处理?
答案:
WebSocket 是长连接,用户连接到某台服务器后,消息只在该服务器内可见。集群需要:
- 消息广播:通过 Redis Pub/Sub 或 MQ,一台服务器收到消息后广播给所有节点
- Session 共享:用 Redis 记录用户连接在哪台服务器
- Sticky Session:负载均衡器按用户 ID 路由到固定服务器
Q3: SSE 和 WebSocket 怎么选?
答案:
- SSE:只需要服务端向客户端推送(如通知、日志流、AI 回答流式输出),基于 HTTP 天然支持重连
- WebSocket:需要双向通信(如 IM 聊天、实时协作),开销更小