Как лучше организовать обмен данными по сокетам между пользователями?
Добрый день. Я не буду описывать реальную ситуацию, т.к. она довольно непроста, попробую рассказать суть, которой хочется добиться и собственно услышать ваши мнения по этому вопросу.
Итак, представьте ситуацию: есть игра, в которой игроки подключаются к комнате и ждут ее начала. Когда игра начинается (неважно, как она начинается, просто началась), каждый игрок об этом узнает посредством broadcast-а. Тут все хорошо. Далее у каждого игрока запускается таймер с интервалом в 1 секунду (грубо говоря продолжительность текущей игры). Каждую секунду каждый игрок генерирует число (в нашем общем случае пусть это будет какое-то random значение) и ему необходимо это число разослать всем участникам этой комнаты, а им в свою очередь надо получить это число в эту же секунду. Серверная часть написана на Node.js и Socket.io.
Например:
1) есть игрок1 и игрок2
2) началась игра
3) 1ая секунда игры: игрок1 отправил на сервер число 15, а игрок 2 - число 18
4) в эту же 1ую секунду игрок1 должен увидеть, что игрок2 отправил число 18, а игрок2 должен увидеть, что игрок1 отправил число 15
Проблема в том, что я не уверен, как правильно это реализовать, т.к. не знаю, успеют ли данные доходить до игроков за эту 1ую секунду, ведь им надо отправить свое число, а всем остальным получить это число за ту же секунду. Я вижу 2 варианта:
1) Игрок1 отправляет свое число на сервер. Складываем это число в массив, примерно такой: usersPoints[userId][second] = points. В эту же секунду игрок2 запрашивает данные из массива и уже смотрит, сколько очков у игрока1. Проблема: я не уверен, что данные от игрок1 успеют положиться в массива раньше, чем игрок2 их запросит.
2) Игрок1 отправляет свое число на сервер. Сервер броадкастит в комнату это число. Проблема: я не уверен, что число от игрока1 дойдет до сервера именно в ту секунду, когда оно нужно игроку2. Ну, возьмем к примеру медленный интернет. Получается, что по таймеру у игрока1 сработает событие "отправить число на сервер". Игрок2 в эту же секунду будет ждать число от игрок1, но т.к. у игрок1 медленный интернет, а таймер игрока2 его ждать не будет, то игрок2 может просто не дождаться этого числа.
Я тестировал 1ый вариант и результат был ожидаемый (мной), число то доходило (до всех остальных), то нет. Пробовал отправлять очки не каждую секунду, а каждые 990мс, а запрашивать каждую секунду, но тогда со временем (уже минуты через 2) они уже становятся не совсем актуальными.
Если вам не совсем понятно, зачем игрокам отправлять и получать числа, то давайте попробую объяснить в целом. Когда игра стартует каждую секунду каждый игрок своими действиями генерирует количество очков. Остальные игроки должны видеть его очки в эту секунду (а он видеть очки других игроков), чтобы сравнивать их со своими.
Я в отчаянии. Вроде и проблема совсем обычная, обмен актуальными данными в текущую секунду, а какой выбрать подход - не знаю. Отсюда и вопрос: каким наилучшим образом организовать обмен актуальными данными между игроками в течение одной секунды?
Я исходил из таких размышлений: когда запрашиваем, то приходят стабильно очки всех игроков в момент запроса за конкретную секунду, указанную в запросе.
Если, вместо запроса, рассылкой будет заниматься сервер, то я переживаю, что от разных пользователей очки могут приходить в разное время . Т.е. чтобы сервер что-то разослал, сперва надо ему отдать это что-то, а вот отдадут ли ему очки в эту секунду я не знаю. Ну, то есть я то знаю, что отдадут, но может ли скорость интернет соединения повлиять на скорость обмена очками?
Ну к примеру Вася играет с Петей. У Васи медленный интернет. Он в 1ую секунду игры пытается сказать серверу, что у него за 1ую секунду 30 очков, но т.к. интернет плохой, то запрос отправить получится только через 2 секунды. Получается, что Петя мало того, что не получит очки Васи за первую секунду, так ему еще и придут избыточные данные broadcast-ом от Васи за 1ую секунду, которые уже ему не нужны
В любом случае, будет уходить запрос каждую секунду на сервер в этот момент и создавать там сообщение, не важно успели придти очки от других людей или нет, а то что они не успели придти, это маловероятно, т.к. скорость интернета для передачи нескольких байт должна нууу очень маленькая быть, тут другой момент, надо чтобы ответ от сервера, был очень быстрый, т.е. 50 миллисекунд, тогда можно хоть 10 раз в секунду, проверять данные.
Проектируйте игру таким образом, чтобы требования по частоте обмена трафиком между игроками не превышали разумный пинг.
Множество проектов загнулись, когда игра была критична к пингу, а из-за популярности и наплыва игроков, играть стало невозможно (тот же tetrisarena, где требовалось до нескольких раз в секунду обмен всего лишь между двумя участниками, начало загибаться, когда общий онлайн на сервере превысил несколько тысяч человек), видимо не успели развести игроков на несколько разных серверов, и на проект забили.
В то же время, средний пинг на который следует рассчиывать - до 20 мс. в идеале до 10 мс. Вот и посчитайте что и сколько раз можно передать за такой промежуток, умножьте на количество игроков и сравните с аплинком к вашему серверу, сколько игроков он потянет.