提问者:小点点

为什么Socket.io会以随机间隔发出空事件?


我有一个在Nodejs和Socket.io上运行的应用程序。

图像中看到的事件2,3是空事件,Socket.io服务器以随机间隔不断发出这些事件。更烦人的是,空事件之间的时间延迟是疯狂的,如图中所见在2到3之间有19秒的时间延迟。因此,Socket.io客户机发出的消息:删除事件,本应立即发出消息:删除,但延迟了19秒!!

更糟糕的是,在发出这些空事件的同时,所有其他源自socket client的socket事件都没有发出,它们被困在边缘,直到空事件消失为止。

我怀疑这些空事件是套接字pingpong事件。有人知道为什么会这样吗?我们怎样才能防止这种情况呢?或者甚至可以为客户端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
          });
        }
      });
    }
  });
});

共1个答案

匿名用户

根据socket.io文档,我认为这是正常的:

默认情况下,首先建立长轮询连接,然后升级到“更好”的传输(如WebSocket)。

你可以做的是设置连接只使用websocket,它应该停止长轮询,你会立即收到消息:

socket = io.connect({transports: ['websocket']});

更新

不需要将路径设置为/socket.io,它是默认值。

在客户端,您还可以使用:

const socket = io([URL], {
  transports: ['websocket']
});

我注意到您正在使用async/awaitcallback,我将在您的服务器端代码上使用async/awaitcallback,例如:

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);
}