问题
I have a javascript GameClient that uses SocketIO to send messages to a nodeJs server. Multiple users can open the GameClient separately and send messages to the server.
GameClient
GameClient ---> NodeJS Server
GameClient
The server can send messages to specific clients using io.to(socketid).emit()
. The code looks something like this:
CLIENT
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)
SERVER (simplified for clarity, just keeping track of one user here)
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")
PROBLEM
When the client browser tab becomes inactive for any reason at all, the client disconnects and reconnects and gets a new socket connection ID. This actually happens a lot in Chrome and Safari.
The server only knows the old connection id, so now it can't send direct messages any more. How do I keep the socket connection id synchronised on the client and server?
Since the server also gets a reconnected event, how does it know which user reconnected?
回答1:
The answer to your question is quite simple: you need a way to identify who is who. And that is not socket.id
because this only identifies sockets, not users, as you've already noticed.
So you need some authentication mechanism. Once a user authenticates you can reuse his true id (whether it is simply a name or an integer in a database is irrelevant). And then on the server side you keep a collection of pairs (true_id, socket_id)
. And whenever a message comes to that user, you broadcast it to all matched socket.io objects.
Edit: So here's the flow:
- Client authenticates with the server, the server sends him his own
true_id
, which the client stores somewhere. The client may also store somesession_id
or maybe some other mechanism that will allow him fast reauthentication in case of disconnection (note: do not store credentials, its a security issue). - The server keeps track of
(true_id, socket_id)
pairs in the form of a double way, mutlivalue map (it's an implementation detail what kind of data structure should be used here, maybe two{}
objects is enough). If a connection dies then(true_id, socket_id)
entry is removed. Note that for a giventrue_id
there still may be some othersocket_id
alive. And so it doesn't mean that the user disconnected. It only means that this particular channel is dead. - Users don't care about
socket_id
, they only care abouttrue_id
. What you emit is{target_id: true_id, ...}
instead of{target_id: socket_id, ...}
on the client side, when you want to send a direct message. - When the server receives such message with
true_id
inside, it retrieves all(true_id, socket_id)
pairs and passes the message to all of these sockets (note: maybe you don't even needsocket_id
, you can simply storesocket
objects here). Although this is a business logic: do you allow multiple connections per user? I would. There are many edge cases here (like for example a client thinks that he disconnected, but the server thinks he is still connected, etc) and making this 100% correct is unfortunately impossible (due to the nature of networking). But with a bit of effort it is possible to make it work 99% of the time. - If a connection dies then it is your client's responsibility to automatically reconnect and reauthenticate. New
socket_id
for oldtrue_id
is generated on the server side.
Let me emphasize this again: clients don't care about socket_id
at all. Because that doesn't identify them. This only identifies a channel. And only the server cares about this information.
来源:https://stackoverflow.com/questions/58208626/how-synchronise-socketio-connection-ids-on-client-and-server