5.1 KiB
5.1 KiB
WebSocket
目录
WebSocket协议
WebSocket 简介
// WebSocket:全双工通信协议
// - 客户端和服务器可以同时发送数据
// - 基于 TCP
// - 低延迟
// - 适合实时通信
WebSocket 握手
// WebSocket 握手过程
// 1. 客户端发送 HTTP 请求,包含 Upgrade 头
GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
// 2. 服务器响应,同意升级
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
WebSocket与HTTP对比
对比表
| 特性 | HTTP | WebSocket |
|---|---|---|
| 通信方式 | 请求-响应 | 全双工 |
| 连接 | 短连接 | 长连接 |
| 开销 | 每次请求都有头部 | 连接建立后开销小 |
| 实时性 | 低 | 高 |
| 适用场景 | 一般请求 | 实时通信 |
使用场景
// WebSocket 适用场景:
// 1. 实时聊天
// 2. 实时推送
// 3. 游戏
// 4. 股票行情
// HTTP 适用场景:
// 1. 一般 API 请求
// 2. 文件下载
// 3. 网页浏览
WebSocket实现
使用 OkHttp WebSocket
// 创建 WebSocket
Request request = new Request.Builder()
.url("ws://echo.websocket.org")
.build();
WebSocket webSocket = client.newWebSocket(request, new WebSocketListener() {
@Override
public void onOpen(WebSocket webSocket, Response response) {
// 连接打开
webSocket.send("Hello");
}
@Override
public void onMessage(WebSocket webSocket, String text) {
// 接收文本消息
}
@Override
public void onMessage(WebSocket webSocket, ByteString bytes) {
// 接收二进制消息
}
@Override
public void onClosing(WebSocket webSocket, int code, String reason) {
// 正在关闭
webSocket.close(1000, null);
}
@Override
public void onClosed(WebSocket webSocket, int code, String reason) {
// 已关闭
}
@Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
// 连接失败
}
});
// 发送消息
webSocket.send("Hello");
webSocket.send(ByteString.of("Hello".getBytes()));
// 关闭连接
webSocket.close(1000, "Normal closure");
心跳机制
心跳实现
// 心跳:保持连接活跃
private Handler heartbeatHandler = new Handler();
private Runnable heartbeatRunnable = new Runnable() {
@Override
public void run() {
if (webSocket != null) {
webSocket.send("ping");
heartbeatHandler.postDelayed(this, 30000); // 30秒发送一次
}
}
};
// 启动心跳
heartbeatHandler.post(heartbeatRunnable);
// 停止心跳
heartbeatHandler.removeCallbacks(heartbeatRunnable);
重连机制
重连实现
// 重连机制
private void reconnect() {
if (isConnecting || isConnected) {
return;
}
isConnecting = true;
new Handler().postDelayed(() -> {
connect();
}, reconnectDelay);
reconnectDelay = Math.min(reconnectDelay * 2, MAX_RECONNECT_DELAY);
}
// 连接失败时重连
@Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
isConnected = false;
isConnecting = false;
reconnect();
}
WebSocket最佳实践
1. 管理连接状态
// 管理连接状态
private boolean isConnected = false;
private boolean isConnecting = false;
// 检查连接状态
if (!isConnected) {
connect();
}
2. 处理消息队列
// 消息队列:连接断开时缓存消息
private Queue<String> messageQueue = new LinkedList<>();
// 发送消息
public void sendMessage(String message) {
if (isConnected) {
webSocket.send(message);
} else {
messageQueue.offer(message);
}
}
// 连接成功后发送缓存消息
@Override
public void onOpen(WebSocket webSocket, Response response) {
isConnected = true;
while (!messageQueue.isEmpty()) {
webSocket.send(messageQueue.poll());
}
}
3. 及时关闭连接
@Override
protected void onDestroy() {
super.onDestroy();
if (webSocket != null) {
webSocket.close(1000, "Activity destroyed");
}
}
面试常见问题
Q1: WebSocket 和 HTTP 的区别?
答案:
- HTTP:请求-响应模式,短连接
- WebSocket:全双工通信,长连接,实时性更好
Q2: WebSocket 的使用场景?
答案:
- 实时聊天
- 实时推送
- 游戏
- 股票行情
Q3: WebSocket 的心跳机制?
答案:
- 定期发送心跳消息
- 保持连接活跃
- 检测连接是否断开
Q4: WebSocket 的重连机制?
答案:
- 连接断开时自动重连
- 使用指数退避策略
- 限制最大重连延迟
最后更新:2024年