Как синхронизировать идентификаторы соединений socketIO на клиенте и сервере? - PullRequest
2 голосов
/ 02 октября 2019

У меня есть JavaScript GameClient, который использует SocketIO для отправки сообщений на сервер nodeJs. Несколько пользователей могут открывать GameClient отдельно и отправлять сообщения на сервер.

GameClient
GameClient  ---> NodeJS Server
GameClient

Сервер может отправлять сообщения определенным клиентам, используя io.to(socketid).emit(). Код выглядит примерно так:

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 (упрощено для ясности, просто отслеживая одного пользователя здесь)

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")

ПРОБЛЕМА

Когда вкладка браузера клиента вообще по какой-либо причине становится неактивной, клиент отключается и повторно подключается и получает новый идентификатор подключения к сокету. На самом деле это часто случается в Chrome и Safari.

Сервер знает только старый идентификатор соединения, поэтому теперь он больше не может отправлять прямые сообщения. Как сохранить синхронизацию идентификатора соединения сокета на клиенте и сервере?

Поскольку сервер также получает событие повторного подключения, как он узнает, какой пользователь повторно подключился?

1 Ответ

2 голосов
/ 02 октября 2019

Ответ на ваш вопрос довольно прост: вам нужен способ определить, кто есть кто. И это не socket.id, потому что это идентифицирует только сокеты, а не пользователей, как вы уже заметили.

Так что вам нужен механизм аутентификации. Как только пользователь аутентифицируется, вы можете повторно использовать его истинный идентификатор (неважно, является ли это просто именем или целым числом в базе данных). А затем на стороне сервера вы храните коллекцию пар (true_id, socket_id). И всякий раз, когда сообщение приходит этому пользователю, вы отправляете его всем совпадающим объектам socket.io.

Edit: Итак, вот поток:

  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)соединяет и передает сообщение в всех этих сокетов (примечание: может быть, вам даже не нужен socket_id, вы можете просто хранить socket объекты здесь). Хотя это бизнес-логика: вы разрешаете несколько подключений на пользователя? Я мог бы. Здесь есть много крайних случаев (например, клиент думает, что он отключен, но сервер думает, что он все еще подключен и т. Д.), И сделать это на 100% правильным, к сожалению, невозможно (из-за особенностей сети). Но, приложив немного усилий, можно заставить его работать в 99% случаев.
  5. Если соединение разорвано, то ваш клиент обязан автоматически переподключиться и повторно аутентифицироваться. Новое socket_id для старого true_id генерируется на стороне сервера.

Позвольте мне еще раз подчеркнуть это: клиентам наплевать на socket_id. Потому что это не идентифицирует их. Это только идентифицирует канал. И только сервер заботится об этой информации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...