我有一个在Nodejs和Socket.io上运行的应用程序。
图像中看到的事件2,3是空事件,Socket.io服务器以随机间隔不断发出这些事件。更烦人的是,空事件之间的时间延迟是疯狂的,如图中所见在2到3之间有19秒的时间延迟。因此,Socket.io客户机发出的消息:删除事件,本应立即发出消息:删除,但延迟了19秒!!
更糟糕的是,在发出这些空事件的同时,所有其他源自socket client的socket事件都没有发出,它们被困在边缘,直到空事件消失为止。
我怀疑这些空事件是套接字ping
和pong
事件。有人知道为什么会这样吗?我们怎样才能防止这种情况呢?或者甚至可以为客户端socket.emit设置一个优先级,以便不管这些空事件如何,客户端发出的socket事件优先并立即被激发?
编辑#1
尽管添加了{transports:['websocket']}
,延迟仍然远远超过17秒,如图所示
编辑#2-socket.emit代码
客户端是由很多jQuery+vanilla JS+Angular 1.7组成的。客户端套接字是工厂包装
app.factory('socket',['$rootScope', function ($rootScope) {
var socket = io.connect('',{
path: '/socket.io',
transports: ['websocket']
});
return {
on: function (eventName, callback) {
socket.on(eventName, function () {
var args = arguments;
$rootScope.$apply(function () {
callback.apply(socket, args);
});
});
},
emit: function (eventName, data, callback) {
socket.emit(eventName, data, function () {
var args = arguments;
$rootScope.$apply(function () {
if (callback) {
callback.apply(socket, args);
}
});
})
},
disconnect: function(close){
socket.disconnect(close);
},
removeAllListeners: function (eventName, callback) {
socket.removeAllListeners(eventName, function() {
var args = arguments;
$rootScope.$apply(function () {
callback.apply(socket, args);
});
});
}
};
}])
控制器上的“socket.emit”代码如下
$scope.deleteMessage = function (message) {
socket.emit('message:delete', {
id: message
});
};
我使用express+Nodejs,下面是初始化服务器套接字的代码
Server = require('socket.io'),
io = new Server({
path: `/socket.io`,
transports: ['websocket']
});
服务器端套接字代码监听客户端发出,如下所示
io.on("connection", async function (socket) {
socket.on("message:delete", function (payload) {
if (props.connectedUsers[socket.userId].info.isAdmin) {
console.log("Received Message Deletion by",
props.connectedUsers[socket.userId].info.name);
if (payload.id == "SYS_MOTD") return;
await Message.remove({
_id: new db.Types.ObjectId(payload.id)
}).exec(function (err, message) {
if (!err) {
console.log("Emit message:deleted");
io.sockets.emit("message:deleted", {
id: payload.id
});
}
});
}
});
});
根据socket.io文档,我认为这是正常的:
默认情况下,首先建立长轮询连接,然后升级到“更好”的传输(如WebSocket)。
你可以做的是设置连接只使用websocket,它应该停止长轮询,你会立即收到消息:
socket = io.connect({transports: ['websocket']});
更新
不需要将路径
设置为/socket.io
,它是默认值。
在客户端,您还可以使用:
const socket = io([URL], {
transports: ['websocket']
});
我注意到您正在使用async/await
和callback
,我将在您的服务器端代码上使用async/await
或callback
,例如:
try {
await Message.remove({
_id: new db.Types.ObjectId(payload.id)
})
console.log("Emit message:deleted");
io.sockets.emit("message:deleted", {
id: payload.id
});
} catch(ex) {
console.log(ex.message);
}