Socket.IO 是一个功能丰富的实时通信库,相比原生 WebSocket 提供了:
鸿蒙端目前没有现成的 Socket.IO 客户端库,因此需要手动实现 Socket.IO 协议。
已实现 SocketIOProtocol 类,支持:
0 - CONNECT(连接/握手)1 - DISCONNECT(断开连接)2 - EVENT(事件)3 - ACK(确认)4 - ERROR(错误)5 - BINARY_EVENT(二进制事件)✅ 已实现6 - BINARY_ACK(二进制确认)✅ 已实现42["event", data] - 42 是 EVENT 类型,后面是 JSON 数组42/namespace["event", data] ✅ 已实现0{"sid":"...","pingInterval":25000,"pingTimeout":20000}2["ping"]3["pong"]51-["event", {"_placeholder":true,"num":0}] ✅ 已实现Socket.IO 的自动降级连接机制:
// 1. 先尝试 WebSocket
try {
transport = new WebSocketTransport();
await transport.connect(wsUrl, token);
// WebSocket 连接成功
} catch (e) {
// WebSocket 失败,降级到 HTTP 长轮询
transport = new PollingTransport();
await transport.connect(serverUrl, token, namespace);
// HTTP 长轮询连接成功
}
sid 参数保持会话// 连接默认命名空间 "/"
await socketService.connect(serverUrl, token);
// 连接自定义命名空间 "/chat"
await socketService.connect(serverUrl, token, "/chat");
// 获取当前命名空间
const namespace = socketService.getNamespace();
/namespace/socket.io/?EIO=4&transport=websocket42/namespace["event", data]// 加入房间
socketService.joinRoom("room_name");
// 离开房间
socketService.leaveRoom("room_name");
join 事件到服务器leave 事件到服务器// 发送二进制数据
const binaryData = new Uint8Array([1, 2, 3, 4]);
socketService.emitBinary("binary_event", binaryData, (response) => {
// ACK 回调
console.log("收到 ACK:", response);
});
51-["event", {"_placeholder":true,"num":0}]// 发送带 ACK 的事件
socketService.emit("event", data, (response) => {
console.log("收到 ACK:", response);
});
42["event", data, ackId]43[data]// 1. 获取 Repository
const repository = SocketIORepositoryFactory.getInstance();
// 2. 连接服务器(默认命名空间)
await repository.connect(serverUrl, token);
// 3. 连接命名空间
await repository.connect(serverUrl, token, "/chat");
// 4. 观察连接状态
repository.connectionState.observe((isConnected) => {
console.log('连接状态:', isConnected);
});
// 5. 发送事件
await repository.sendVehicleControl('lock', vehicleId);
// 6. 发送二进制数据
const binaryData = new Uint8Array([1, 2, 3]);
socketService.emitBinary("binary_event", binaryData);
// 7. 加入房间
socketService.joinRoom("room_1");
// 8. 观察事件
repository.vehicleAlarm.observe((alarm) => {
if (alarm) {
console.log('收到报警:', alarm.data);
}
});
| 功能 | Android 端 | 鸿蒙端 | 状态 |
|---|---|---|---|
| Socket.IO 协议 | ✅ socket.io-client:2.1.2 | ✅ 手动实现 | ✅ 兼容 |
| 握手机制 | ✅ 自动 | ✅ 手动实现 | ✅ 兼容 |
| 心跳机制 | ✅ 自动 | ✅ 手动实现 | ✅ 兼容 |
| 事件系统 | ✅ 支持 | ✅ 支持 | ✅ 兼容 |
| 自动重连 | ✅ 支持 | ✅ 支持 | ✅ 兼容 |
| 命名空间 | ✅ 支持 | ✅ 已实现 | ✅ 兼容 |
| 房间 | ✅ 支持 | ✅ 已实现 | ✅ 兼容 |
| 二进制数据 | ✅ 支持 | ✅ 已实现 | ✅ 兼容 |
| 自动降级连接 | ✅ 支持 | ✅ 已实现 | ✅ 兼容 |
| ACK 回调 | ✅ 支持 | ✅ 已实现 | ✅ 兼容 |
1. 尝试 WebSocket 连接
↓
2. WebSocket 连接失败?
↓ 是
3. 自动降级到 HTTP 长轮询
↓
4. HTTP 长轮询连接成功
↓
5. 正常通信(业务代码无感知)
客户端 服务器
| |
|--- GET (长轮询) ------->|
| | (等待消息,最长 60 秒)
|<-- 消息1, 消息2 -------|
| |
|--- GET (长轮询) ------->|
| |
|--- POST (发送消息) ---->|
|<-- OK -----------------|
| |
| 特性 | WebSocket | HTTP 长轮询 |
|---|---|---|
| 延迟 | 低(实时) | 中等(取决于轮询间隔) |
| 带宽 | 低(无 HTTP 头) | 高(每次请求都有 HTTP 头) |
| 兼容性 | 中等(可能被阻止) | 高(几乎都支持) |
| 连接数 | 1 个长连接 | 多个短连接 |
在 SocketIOServiceImpl 中已添加详细日志:
如果遇到连接问题,检查:
sid、pingInterval、pingTimeout如果需要支持更多 Socket.IO 功能,可以考虑:
连接状态恢复(Socket.IO 4.6.0+)
// 恢复连接状态和丢失的数据包
socketService.reconnect();
多路复用(多个命名空间共享连接)
// 在同一个连接上使用多个命名空间
const chatSocket = socketService.of("/chat");
const notificationSocket = socketService.of("/notification");
压缩支持
// 启用消息压缩
socketService.enableCompression();
当前实现已经支持 Socket.IO 的所有核心功能:
与 Android 端使用 socket.io-client:2.1.2 的兼容性完全一致,可以正常通信。
自动降级连接机制确保了在各种网络环境下都能成功连接,提高了应用的兼容性和可靠性。