socketio
socket.io说明
Socket.io是一个WebSocket库,包括了客户端的js和服务器端的nodejs,它的目标是构建可以在不同浏览器和移动设备上使用的实时应用。
它会自动根据浏览器从WebSocket、AJAX长轮询、Iframe流等等各种方式中选择最佳的方式来实现网络实时应用,非常方便和人性化,而且支持的浏览器最低达IE5.5
socket.io特点
实时分析:将数据推送到客户端,这些客户端会被表示为实时计数器,图表或日志客户。
实时通信和聊天:只需几行代码便可写成一个Socket.IO的”Hello,World”聊天应用。
二进制流传输:从1.0版本开始,Socket.IO支持任何形式的二进制文件传输,例如:图片,视频,音频等。
文档合并:允许多个用户同时编辑一个文档,并且能够看到每个用户做出的修改。
socketio 使用
服务端
- 配置jiangHuConfig, 启用socket
// config.default.js
jiangHuConfig: {
enableSocket: true
}
- 配置socketIO配置信息
// config.default.js jianghuConfig同级
socketIO: {
path: `/${appId}/socket.io`,
serveClient: true,
connectTimeout: 45000,
// 多work模式下需要 启用 redis adapter
// redis: {
// host: "127.0.0.1",
// port: "6379",
// // password: '',
// db: 0,
// },
},
- 发送socket消息
const { socketIO } = this.app;
socketIO.to(toSocketId).emit(resourcePath, socketBody);
客户端
- 初始化socket 客户端
function init() {
const requestBody = {
packageId,
packageType: "socketRequest",
deviceId: socket.deviceId,
status: null,
timestamp: new Date().toISOString(),
appData: {
appId: window.appInfo.appId,
pageId: "socket",
actionId: "connect",
authToken: socket.authToken,
actionData: {
socketId,
},
},
};
try {
socket.client = io("/", {
path: `/${window.appInfo.appId}/socket.io`,
auth: requestBody,
closeOnBeforeunload: true,
transports: ["websocket"],
forceNew: true,
timeout: 5000,
secure: false, // 是否支持SSL/TLS
});
} catch (e) {
console.error(e);
}
}
- 注册客户端监听事件
socket.client.on("resource", async (message) => {
console.log("==== [socket channel.resource]", JSON.stringify(message));
const { appId, pageId, actionId } = message.appData;
socket.packageId = message.packageId;
// 认证成功
if (pageId === "socket" && actionId === "connect") {
// 每次掉线都会重新走一遍认证过程,code=100的逻辑要注意别搞混
// 设置在线标识
socket.online = true;
socket.loadFinish = true;
console.log("socket.hasDisconnectOrError :: " + socket.hasDisconnectOrError)
socket.onReConnect(socket.hasDisconnectOrError)
} else {
socket.receiveSocketMsg(message.appData, message.packageId);
if (socket.packageListeners[message.packageId]) {
const { callback } = socket.packageListeners[message.packageId];
callback(message);
}
}
});
socket.client.on("connect", (message) => {
console.log("==== [socket channel.onConnect]", message);
});
socket.client.on("connect_timeout", (message) => {
console.log("==== [socket channel.connect_timeout]", message);
});
socket.client.on("connect_error", (message) => {
console.log("==== [socket channel.onError]", message);
socket.hasDisconnectOrError = true;
socket.online = false;
});
socket.client.on("disconnect", (message) => {
console.log("==== [socket channel.disconnect]", message);
socket.online = false;
socket.hasDisconnectOrError = true;
});
socket.client.on("reconnect", (message) => {
socket.hasDisconnectOrError = true;
console.log("==== [socket channel.onReconnect]", message);
});
socket.client.on("reconnect_attempt", (message) => {
console.log("==== [socket channel.onReconnectAttempt]", message);
});
socket.client.on("reconnect_failed", (message) => {
console.log("==== [socket channel.onReconnectFailed]", message);
});
socket.client.on("reconnect_error", (message) => {
console.log("==== [socket channel.onReconnectError]", message);
});
socket.client.on("ping", (message) => {
// 心跳请求
// callback_onIMPing
console.log("==== [socket channel.onPing]", message);
});
socket.client.on("pong", (message) => {
// 心跳响应
// callback_onIMPong
console.log("==== [socket channel.onPong]", message);
});
- 添加socket客户端断开重连逻辑
// 每5s检查一下连接状态,若连接已断开,则尝试重新连接
setInterval(() => {
if (!socket.connected) {
this.init()
}
}, 5000)
- 发送socket消息
const packageId = `${Date.now()}_${_.random(1000000, 9999999)}`;
const requestBody = {
packageId,
packageType: "socketForward",
deviceId: socket.deviceId,
status: null,
timestamp: new Date().toISOString(),
appData: {
appId: window.appInfo.appId,
pageId: "socket",
actionId,
authToken: socket.authToken,
actionData,
},
};
socket.client.emit("resource", requestBody);