Сокеты на примере игр

Вы задумывались, что когда вы играете в Доту, Кс или Apex, то вы видите у себя на компьютере то же, что и другие игроки в режиме реального времени? Расположение на карте, когда кто-то стреляет или использует способности - все эти данные синхронизированы между всеми игроками одновременно.

Как это работает?

Всю информацию об игре знает сервер, это центральное хранилище текущего состояния игры. С ним связаны все компьютеры игроков и он передает и получает обновление об этом состоянии по сокетам.

Сокеты на примере игр

Что же такое сокеты? Давайте по порядку.

Есть два основных взаимодействия сервера с компьютером игрока - или же клиента:

Первое - “запрос-ответ” (request-response), то что используется на всех сайтах: клиент сам спрашивает сервер о наличии новых данных.

Сокеты на примере игр

Дешевое взаимодействие по мощности, но медленное по синхронизации, поэтому часто используется большими сайтами и практически никогда играми, представьте что пинг в кске всегда бы был не менее 300мс, не удобно, правда?

И второе - сокетное (socket) взаимодействие его ключевое отличие от первого в том, что не клиент спрашивает есть ли обновления у сервера, а сервер сам напрямую сразу шлет все обновления на клиент.

Сокеты на примере игр

Из минусов - это взаимодействие требует много ресурсов, и например поддержать даже 100 клиентов таким образом крайне сложная задача, поэтому во всех играх, где критично важна минимальная задержка - вы не встретите количество игроков на одном сервере больше 100, как например PUBG/APEX/FORTNITE и другие.

23
18 комментариев

Комментарий недоступен

8
Ответить

Автостопом по галактикам

А вообще идея в том, чтобы в 1 минуту дать какую-то новую информацию, тем кому интересно смогут найти либо более глубокое описание (его полно в интернете), либо не углубляться. Я скорее решаю одну из больших болей - начитанность и эрудированность, те просто знание терминов, технологий и подходов - это уже чуть ли не 50% решения проблем, имхо)

1
Ответить

Могу дополнить примером работы с сокетами.

Первоначально, надо приконнектиться, это выглядит так:

socket.Connect("192.168.0.1");

После чего, есть две основных элемента:

1. Передача данных сокет-серверу, как правило это называет словом "emit", с названиям метода/ивента и его параметрами.

socket.Emit("PlayerConnect", playerId);

И тогда эта информация передается с клиента на сервер (и её могут получить все клиенты, которые работают с этим сокетом).

2. Получение данных от сервера, путем подписывания на события, обычно ключевое слово "subscribe", с названием ивента/события и что должно произойти(как правило, это ссылка на функцию/метод).

socket.Subscribe("HealthChanged", UpdateHealthUI);

Как-то так.

4
Ответить

Да, а еще со стороны сервера есть различные способы взаимодействия с соединениями/топиками/каналами/событиями

Можно либо всем слать сообщение, иначе назаывается броадкастить (broadcast), например глобальное событие: "Появился новый босс в подземелье Х, игроки попытайте свою удачу"

А есть возможность точечно игроку (конкретному подписчику события), например игрок запросил уникальную и приватную информацию, и только он получит ее от сервера)

4
Ответить

А еще соединение может обвалиться и придется переподключаться. Например, можем повесить коннект при срабатывании socket.close

1
Ответить

Чотко
ликбез незнакомым зайдет

3
Ответить

Смешались в кучу кони, люди...

Есть модель сетевого взаимодействия OSI, разбитая для удобства на уровни абстракции от железа. "Сайтики" в браузере работают на протоколе TCP транспортного уровня и различных версий HTTP прикладного уорвня поверх него по принципу запрос-ответ (request-response). Каждый раз, когда веб-клиент (например, браузер) хочет узнать новые данные, устанавливается (новое) TCP соединение с сервером, происходит диалог, и соединение закрывается. Это очень долго для интерактивных применений.

Плюсы TCP в том, что он гарантирует доставку байтов в обе стороны, за это приходится платить высоким общим временем "доставки последнего байта сообщения" (end-to-end latency). Особенность HTTP в том, что в оригинале это протокол передачи текста, а передавать бинарные данные по нему сложно/дорого, поэтому изобрели разные костыли, чтоб немножко сломать абстракцию, но улучшить производительность.

Там, где требуется низкая задержка (latency), придумали костыли (например, не закрывать TCP соединение после окончания запроса, так работает WebSockets) или вообще отказались от "дорогого" TCP.

В интерактивных приложениях, например играх, часто используют UDP как альтернативу TCP на траспортном уровне. Он не гарантирует доставку байтов до адресата, но при этом серверу не надо держать по сокету на клиент. Получается экономичнее и быстрее. Минус — обеспечивать целостность полученных данных надо самим приложениям, не надеясь на транспортный уровень.

В качестве прикладного протокола передачи обычно используют какой-нибудь бинарный протокол типа Protobuff, CBOR, BSON и кучу других вариантов, или пишут что-то своё на коленке. Плюсы: они все быстрее в обработке, чем текстовые типа HTTP.

Теперь про количество соединений. Современные ОС абстрагируют от нас все, что ниже прикладного уровня. В замен приложения получают абстрактный _сокет_ — дырку, из которой можно читать и куда можно писать. Таких сокетов на всю ОС ограниченное количество, что зависит от реализации, но можно говорить о _десятках тысяч_ доступных сокетов.

Вопрос не в том, чтоб открыть и держать все эти сокеты доступными, а в том, что получать и передавать данные ото всех клиентов сразу не получится, потому что сетевая карта имеет ограниченную пропускную способность. То есть если наши клиенты постоянно хотят обмениваться данными с сервером, чем выше количество клиентов (больше даннвх требует обработки), тем дольше будет физическое время ожидания отправки и получения байтов из сети со стороны сервера. Это называется congestion. И связано с тем, что сокеты пишут и читают из специальной очереди на сетевой карте (или не одной, но принципа не меняет). И чем больше мы хотим писать и читать, тем длинее очереди, и, значит, увеличивается задержка.

То есть, если у нас есть например Веселая Ферма, клиенты которой просто есть и редко (речь про секунды и минуты) хотят получить данные или передать, то с помощью специальных техник один сервер с одной сетевой картой может обрабатывать _сотни тысяч_ клиентов игры. Конечно, если они ВСЕ СРАЗУ захотят писать серверу, мы в лучшем случае будем долго это все обрабатывать (часы). В худшем - все развалится. Это хорошо видно на запусках популярных игр. Из последнего — Диабло 4 с очередями на вход.

Другое дело приложения с высоким трафиком данных. Кроме того, что это трафик нужно получить и отправить с приемлемой задержкой (не всем нравится ждать реакции на выстрел больше 200 мс), так ещё и обработать все это надо. Поэтому в шутерах, гоночках и всем сложнее пасьянса есть как технические, так и геймдизайнерские ограничения на количество игроков на сессию/сервер/... И действительно ограничения тут обычно порядка 100 клиентов на одну сессию.

Как-то так.

2
Ответить