如何同步客户端和服务器上的socketIO连接ID?

时间:2019-10-02 20:03:35

标签: javascript node.js websocket socket.io

我有一个Javascript GameClient,它使用SocketIO将消息发送到nodeJs服务器。多个用户可以分别打开GameClient并将消息发送到服务器。

GameClient
GameClient  ---> NodeJS Server
GameClient

服务器可以使用io.to(socketid).emit()将消息发送到特定客户端。代码看起来像这样:

客户

this.socket = io({ timeout: 60000 })
this.socket.on('connect', () => Settings.getInstance().socketid = this.socket.id)
this.socket.on('reconnect', (attemptNumber:number) => console.log("reconnecting..."))

const json = JSON.Stringify({socketid:this.socket.id, name:"Old Billy Bob"})
this.socket.emit('user created', json)

服务器(为简化起见,此处只是跟踪一个用户)

user = {}

io.on('connection', (socket) => {
    console.log('new connection')
    socket.on('disconnect', () => {
        console.log('user disconnected')
    });

    socket.on('user created', (json) => {
        user = JSON.parse(json)
    });
});

// demo code, send a message to our user
io.to(user.socketid).emit("message to one user")

问题

当客户端浏览器选项卡由于任何原因完全变为非活动状态时,客户端将断开连接并重新连接,并获得新的套接字连接ID。实际上,这在Chrome和Safari中经常发生。

服务器仅知道旧的连接ID,因此现在不再能够发送直接消息。如何使套接字连接ID在客户端和服务器上保持同步?

由于服务器还获得了重新连接事件,因此它如何知道哪个用户重新连接了?

1 个答案:

答案 0 :(得分:2)

您的问题的答案非常简单:您需要一种方法来识别谁是谁。那不是socket.id,因为正如您已经注意到的那样,它仅标识套接字,而不是用户。

因此,您需要某种身份验证机制。用户通过身份验证后,就可以重用其真实ID(无论是名称还是数据库中的整数都无关紧要)。然后在服务器端保留一对(true_id, socket_id)对的集合。每当有消息发送给该用户时,您就将其广播到所有匹配的socket.io对象。

编辑:流程如下:

  1. 客户端向服务器验证身份,服务器向他发送自己的true_id,客户端将其存储在某处。客户端还可以存储一些session_id或其他机制,以便在断开连接的情况下允许他快速重新认证(注意:不存储凭据,这是一个安全问题)。
  2. 服务器以双向多值映射的形式跟踪(true_id, socket_id)对(这是实现详细信息,此处应使用哪种数据结构,也许两个{}对象就足够了) 。如果连接中断,则(true_id, socket_id)条目将被删除。请注意,对于给定的true_id,仍然可能还有其他socket_id个在世。因此,这并不意味着用户已断开连接。这仅意味着该特定通道已死。
  3. 用户不关心socket_id,他们只关心true_id。当您要发送直接消息时,您发出的是{target_id: true_id, ...}而不是客户端的{target_id: socket_id, ...}
  4. 当服务器接收到带有true_id的此类消息时,它会检索所有(true_id, socket_id)对并将消息传递给这些套接字的 all (请注意:也许您没有即使需要socket_id,也可以在此处存储socket个对象)。尽管这是一种业务逻辑:您是否允许每个用户多个连接?我会。这里有很多极端的情况(例如,客户端认为他已断开连接,而服务器认为他仍在连接等),但由于网络的性质,使此100%正确是不可能的。但是只要稍作努力,就有可能使它在99%的时间内都能正常工作。
  5. 如果连接断开,则客户有责任自动重新连接并重新认证。在服务器端生成了新的socket_id,而旧的true_id

让我再次强调一下:客户根本不在乎socket_id。因为那不能识别他们。这仅标识一个通道。而且只有服务器在乎这些信息。