Документация Steamworks
Steam Datagram Relay
Steam Datagram Relay (SDR) — это закрытая виртуальная игровая сеть Valve. С помощью API вы можете перенести игровой трафик на сетевые магистрали Valve, предназначенные для игрового контента, а также получить доступ к нашей сети ретрансляторов. Ретрансляция трафика защищает ваши сервера и игроков от DoS-атак, поскольку всегда скрывает IP-адреса. Весь входящий трафик аутентифицирован, зашифрован и ограничен. Кроме того, если вы столкнулись с большим наплывом игроков, мы можем подобрать более быстрый маршрут через нашу сеть, что действительно уменьшает время пинга у игроков.

Эта сеть ретрансляции может использоваться как для однорангового трафика, так и для выделенных серверов.

Общие требования и советы для переноса существующего сетевого кода

В этом разделе дана общая информация по одноранговым соединениям и выделенным серверам.

Во-первых, в любом месте, где сетевые серверы идентифицируются по публичному IP-адресу (то есть почти всегда в случае игровых серверов), необходимо использовать другой идентификатор. Есть несколько вариантов:
  • Для клиентов и игровых серверов, совершивших вход в Steam, вы будете, как правило, использовать SteamID.
  • Если ваш игровой сервер не совершает вход в Steam и вы используете процедуру проверки подлинности на основе билетов, вы можете использовать любой другой идентификатор, который посчитаете нужным. См. SteamNetworkingIdentity.
  • В некотором исходном коде распространено допущение, что сетевые хосты и игровые серверы идентифицируются при помощи IPv4-адреса. Поменять это допущение достаточно трудозатратно. Так настроены API Steamworks — ISteamMatchmaking и ISteamMatchmakingServers, а также некоторые наши игры, например Team Fortress 2. В этом случае вы можете использовать систему FakeIP в Steamworks. FakeIP — это IP-адрес, который выглядит как стандартный IPv4-адрес, но входит в зарезервированное адресное пространство, которое не используется в интернете. Если вашему серверу назначен FakeIP, до него всё ещё можно будет доступиться по IPv4-адресу, и практически всё будет «просто работать». Системы ISteamNetworkingSockets и ISteamMatchmakingServers распознают эти особенные IP-адреса и сделают всё, что нужно. Они не участвуют в маршрутиризации и не могут использоваться для всех целей в интернете (так, вы не можете послать на них пинг). Подробнее см. ISteamNetworkingSockets::BeginAsyncRequestFakeIP.

Во-вторых, вам нужно модифицировать весь низкоуровневый код сокетов и использовать один из API Steamworks для соединения.
  • В идеале вы можете использовать один из устанавливающих соединение API ISteamNetworkingSockets, который возвращает HSteamNetConnection.
    (Обратите внимание, что этот API также поддерживает обычный транспорт UDP, что очень удобно для тестирования. Также есть версия с открытым исходным кодом).
  • Некоторый исходный код написан в стиле, который ближе к UDP, когда пакеты могут быть отправлены любому удаленному хосту в любое время, и не все послания отправляются по установленному соединению. В таких ситуациях могут быть полезными две функции Steamworks.
    • Используйте ISteamNetworkingMessages для коммуникации с хостами, идентифицируемые типом SteamNetworkingIdentity, например SteamID.
    • Используйте ISteamNetworkingFakeUDPPort для коммуникации с хостами, идентифицируемыми FakeIP.

Использование SDR в других магазинах и на других платформах

Сетевой API и защита от DDoS-атак для кроссплатформенных игр бесполезны, если они работают только на одной платформе. В большинстве случаев игроки на других платформах и в других магазинах имеют доступ к сети ретрансляции, если ваша игра соответствует некоторым базовым условиям:
  • У вас есть версия вашей игры в Steam.
  • Вы согласны обновлять свою игру раз в определённый приемлемый временной интервал (например, раз в несколько месяцев), если у нас возникнет необходимость предоставить пользователям обновление с исправлениями ошибок или обновление для системы безопасности.
  • Вы понимаете, что, к сожалению, мы не можем обещать, что этот сервис будет всегда доступен для игроков вне Steam. На тот маловероятный случай, если нам надо будет переходить на использование более ранней версии этого сервиса, мы будем сотрудничать с вами и сделаем всё возможное, чтобы избежать перебоев у ваших игроков (в том числе мы сообщим вам заранее, чтобы вы могли составить план действий). В SDK есть встроенные механизмы, с помощью которых мы можем сообщить клиентам о необходимости вернуться к прямому UDP-соединению или попытаться выполнить перфорацию NAT. Однако имейте в виду такую возможность.
  • У вас есть какой-то подбор игр (в SDR это называется «Игровой координатор»), который может выдавать учётные данные для проверки подлинности. Для этого у нас есть отдельный SDK. См. ниже.

Свяжитесь с нами, чтобы получить соответствующие SDK и обсудить особые условия. Мы всё ещё обсуждаем, как распространять код, и на данный момент у нас может не быть возможности поддерживать кроссплатформенную работу для всех партнёров и всех игр.

Ниже вы найдёте более подробную информацию о внедрении SDR в другие магазины и платформы.

Если вы не можете обеспечить выполнение описанных выше критериев, вы можете воспользоваться общедоступной версией API для собственных целей. Помните, что открытый исходный код не поддерживает доступ к сети ретрансляции.

Игры P2P

В случае с одноранговым трафиком в Steam, всё, что вам понадобится, чтобы воспользоваться преимуществами SDR, — это использование API, например ISteamNetworkingSockets::CreateListenSocketP2P и ISteamNetworkingSockets::ConnectP2P. Обо всём остальном позаботится Steam. Для других платформ и магазинов — ознакомьтесь с дополнительными техническими требованиями ниже.

Выделенные серверы в известных дата-центрах

Одноранговые API хорошо работают, даже если одна из сторон — выделенный сервер! Но есть одна важная вещь: если ваш выделенный сервер находится далеко от дата-центра, где запущена ретрансляция, тогда лучший ретранслируемый маршрут может быть медленнее базового IP-маршрута и как минимум у некоторых пользователей задержка будет хуже, чем уже имеющаяся.

Для оптимального результата работы с выделенными серверами сервер должен быть запущен в известном дата-центре, который является частью сети SDR. Мы следим за тем, что рядом запущены ретрансляторы и ретранслируемый маршрут не будет медленнее базового IP-маршрута. Серверы, запущенные в этих известных дата-центрах, устанавливают соединение с использованием специального API. В SDK этот вариант называется «Выделенный сервер». Обратите внимание, что это не обязательно означает, что именно Valve обеспечивает работу серверов или узлов ретрансляции, — это может быть сторонний дата-центр, с которым у нас установлены связи (он должен быть известен системе Steam Datagram Relay).

Если вы управляете игровыми серверами в большом хостинг-провайдере и заинтересованы в использовании SDR (Steam Datagram Relay), свяжитесь с нами. Мы попробуем договориться с вашей хостинговой компанией о запуске узлов ретрансляции в дата-центре. Это лучший вариант развития событий, но даже если так не получится, мы можем попробовать добавить дата-центр в нашу сеть и просто использовать ближайшие ретрансляторы Valve.

Если вы компания, предоставляющая выделенные серверы, и хотите присоединиться к нашей сети, чтобы ваши пользователи могли воспользоваться преимуществами SDR, свяжитесь с нами! Мы ещё не размещали узлы ретрансляции в сторонних хостинговых компаниях, однако мы заинтересованы в этом.

Простое подключение к выделенному серверу без игрового координатора

Если у вас нет собственного централизованного сервиса подбора игр или входа в аккаунт (иногда мы называем его «игровой координатор»), который распределяет игроков по серверам, или вы хотите максимально упросить процесс, вы можете подключиться к выделенному серверу в известном дата-центре, воспользовавшись ISteamNetworkingSockets::CreateListenSocketP2P и ISteamNetworkingSockets::ConnectP2P. В этом случае соединение начинается со стороны клиента как базовое P2P-соединение. Сообщения протокола Rendezvous отправляются через Steam, поэтому если пользователь или сервер потеряют соединение со Steam, соединение не удастся. Кроме того, Steam не имеет никаких ограничений на попытки соединения, за исключением проверки, что пользователь вошёл в свой аккаунт Steam и владеет игрой.

Подключение к серверу посредством билетов

Если у вас нет собственного сервиса игрового координатора, мы рекомендуем использовать соединение посредством билетов. Обычно это требует больших усилий, чем с простым P2P-соединением, но у такого подхода есть два важных преимущества:
  • Вы выдаёте билеты только тем игрокам, которым разрешено совершать попытку соединения, так что нежелательные соединения даже не достигают вашего сервера.
  • Когда у игрока есть билет, он может подключиться к серверу, даже в случае потери связи со Steam или сбоев в работе компьютера игрока. Переподключение к игровому серверу в этих распространённых случаях может быть очень важным для игр, в которых предусмотрено наказание в случае, если игрок покидает игру.

Соединение с выделенным сервером через SDR посредством билетов работает следующим образом:
  • Когда ваш игровой сервер входит в игровой координатор, он отправляет свой SteamDatagramHostedAddress, который является непрозрачным BLOB-объектом, содержащим физические данные маршрутизации (см. ISteamNetworkingSockets::GetHostedDedicatedServerAddress). Также обратите внимание, что у нас есть инструменты, которые вы можете использовать для помощи с аутентифицированным входом в игровой координатор.
  • Сервер начинает принимать ретранслированный трафик, используя ISteamNetworkingSockets::CreateHostedDedicatedServerListenSocket.
  • На определённом этапе клиент захочет воспользоваться подбором игр или подключиться к серверу.
  • Клиент может использовать методы в интерфейсе ISteamNetworkingUtils для получения времени пинга для дата-центров и проверки подключения. В идеале клиент должен отправлять эту информацию игровому координатору, чтобы он мог правильно распределять игроков по дата-центрам.
  • Когда игровой координатор готов авторизовать клиент для соединения с сервером, он создаёт SteamDatagramRelayAuthTicket и подписывает его вашим секретным ключом. Этот билет авторизует определённый клиент для общения с конкретным игровым сервером на ограниченный период времени. Также он содержит зашифрованную информацию о маршрутизации. Игровой координатор отравляет билет клиенту.
  • Клиент кэширует билет в локальный кэш (узнать больше можно в разделе ISteamNetworkingSockets::ReceivedRelayAuthTicket, включая информацию о том, чем оправдана сложность кэширования).
  • Клиент использует ISteamNetworkingSockets::ConnectToHostedDedicatedServer для подключения к серверу. Ознакомьтесь с ISteamNetworkingSockets для получения подробной информации об отправке и получении сообщений.

На данный момент аутентификация посредством билетов недоступна в сочетании с системой FakeIP.

SDK игрового координатора

«Игровой координатор» — это термин, которым мы называем подбор игр и другие ваши серверные службы. Существует отдельный небольшой SDK, который вы можете связать с игровым координатором и использовать для:
  • выпуска билетов, которые будут предоставлять клиентам доступ к игровым серверам, размещённым вне SDR (Steam Datagram Relay);
  • парсинга строк PingLocation_t и подсчёта времени пинга между этими объектами;
  • выпуска сертификата удостоверения для игроков на других платформах и в других магазинах;
  • использования других дополнительных функций.

SDK доступен здесь

Аутентификация с помощью SDK игрового координатора

SDR использует два механизма аутентификации:

  • Билеты размещённых серверов выдаются вашим игровым координатором и авторизуют конкретного пользователя общаться с определённым выделенным сервером на какое-то время. Билеты ретрансляции используются только в сценарии с выделенным сервером. См. SteamDatagramRelayAuthTicket.
  • Сертификаты используются традиционным способом для аутентификации и обмениваются ключами по протоколу Диффи-Хеллмана для установления зашифрованного канала. Сертификаты являются объектами сквозного шифрования и могут быть использованы в любой форме общения SteamNetworkingSockets, включая прямое UDP-подключение или P2P. См. SteamDatagram_CreateCert в SDK игрового координатора и ISteamNetworkingSockets::GetCertificateRequest.

Мы используем проприетарную инфраструктуру открытых ключей для аутентификации пользователей и серверов. Игрокам выдаются индивидуальные, краткосрочные сертификаты, привязанные к их персональной информации. Этим занимается Steam. Для игровых серверов мы обычно используем долгосрочные сертификаты, которые авторизуют целый дата-центр для определённого AppID. Выпускать эти сертификаты будете вы.

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

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

Надёжно храните закрытые ключи сертификатов и центра сертификации! Утечка ключей может привести к перебоям из-за необходимости изъять или заменить их.

Работа серверов в известных дата-центрах


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

Инициализация игрового координатора

  • Вашему сервису подбора игр (далее «игровой координатор») надо будет подключиться к SDK игрового координатора. В заголовочном файле steamdatagram_gamecoordinator.h об этом можно узнать подробнее. SDK игрового координатора использует API на языке C, так что использовать его с другими языками программирования должно быть относительно просто.
  • Скачайте настройки сети во время инициализации и проверяйте наличие обновлений примерно раз в час (для этого ознакомьтесь с SteamDatagram_GameCoordinator_GetNetworkConfigURL и SteamDatagram_GameCoordinator_SetNetworkConfig). Настройки сети — сравнительно маленький файл JSON, который на момент написания этой документации занимает 26 Кбайт (9 Кбайт после сжатия). Адрес обычно легкодоступен, но в случае сбоя вы можете использовать скачанную недавно версию настроек.
  • Вам понадобится файл пары ключей, аутентифицированный для вашей игры. Пришлите нам открытый ключ и инициализируйте SDK игрового координатора своим закрытым ключом (больше информации здесь — SteamDatagram_SetPrivateKey_Ed25519).

Вход клиента в систему

  • Клиент осуществит вызов ISteamNetworkingSockets::GetCertificateRequest, чтобы получить фрагмент данных и отправить его вместе с сообщением о запросе на вход вашему игровому координатору.
  • Когда игровой координатор получит запрос на вход, сгенерируйте сертификат для клиента с помощью SteamDatagram_CreateCert.
  • Отправьте сертификат клиенту в ответ на запрос на вход. Клиенту следует установить сертификат с помощью ISteamNetworkingSockets::SetCertificate.
  • Мы крайне рекомендуем предоставлять клиентам настройки сети в это же время. Клиент должен применить их с помощью SteamDatagram_SetNetworkConfig.

Сертификаты имеют срок действия, мы рекомендуем устанавливать его в 48 часов. Если клиент будет подключён более чем 48 часов, вам потребуется периодически обновлять сертификат. Допустимо применять новый сертификат в любое время, поэтому, если вы хотите выпускать сертификаты чаще, например, в начале каждого матча, вы можете это делать.

Каждый клиент должен быть уникальным. По возможности используйте идентификаторы с указанием платформы (для клиентов Steam это требование обязательно). Если это невозможно, вы можете использовать идентификацию обычной строкой, которая имеет значение для вашего подбора игр. См. SteamNetworkingIdentity.

Игры P2P

Соединениям P2P требуется служба передачи сигнала — канал, имеющий низкую пропускную способность и не чувствительный к задержкам, доставляющий пакеты «с максимальными усилиями» и способный периодически передавать связующие сообщения для проложения маршрута. Для этого потребуется, чтобы у клиентов было постоянное подключение к вашей службе подбора игр — тогда вы сможете отсылать им сообщения, например, по протоколу WebSocket или через TCP-соединение. Если клиенты общаются с вашим игровым координатором только в формате «запрос-ответ» (например, по протоколу http), то ничего не сработает. Доставка «с максимальными усилиями» подразумевает, что библиотека позволяет соединению терять сообщения или доставлять одно и то же сообщение несколько раз.

  • Для открытия соединения используйте ISteamNetworkingSockets::ConnectP2PCustomSignaling. Вам нужно будет добавить подкласс ISteamNetworkingConnectionSignaling, и при вызове SendSignal клиент должен отправить сообщение на внутренний сервер, который постарается передать сообщение другой стороне. Для первоначального подключения характерен обмен 4–10 сообщениями. В дальнейшем обмен сообщениями по установленному подключению будет нужен только в случае, если между сторонами изменится маршрутизация.
  • Получив сигнал, клиент осуществит вызов ISteamNetworkingSockets::ReceivedP2PCustomSignal. Библиотека SDK расшифрует сообщение. Если речь ведётся о существующем подключении, сигнал обработается на месте. Если это сигнал от нового подключения, будет осуществлён вызов ISteamNetworkingSignalingRecvContext::OnConnectRequest.

Более подробная информация — в файле steamnetworkingcustomsignaling.h.

Работа серверов в известных дата-центрах

В этом разделе описаны некоторые технические детали, необходимые для работы выделенных серверов в известных дата-центрах.

Переменные среды

Выделенный сервер получает настройки из переменных среды. Обратите внимание, что в дата-центрах Valve эти значения будут настроены для вас автоматически.
  • SDR_LISTEN_PORT: UDP-порт, на который ваш сервер будет получать трафик с ретрансляторов. Выделенный сервер использует только один сокет (однако, если вы используете «виртуальные порты», у вас может быть и более одного логического «прослушивающего сокета» — см. ISteamNetworkingSockets::CreateHostedDedicatedServerListenSocket). В своих дата-центрах мы обычно используем диапазон 30xxx.
  • SDR_IP: у вашего сервера должен быть публичный IP-адрес, который может получать «незапрошенный» трафик от ретрансляторов. Если у сервера есть только один интерфейс с публичным IP-адресом, он будет использован автоматически. В противном случае вы должны будете указать игровому серверу, какой IP-адрес следует использовать. Сокет SDR будет привязан к INADDR_ANY, но эта информация должна быть указана в SteamDatagramHostedAddress сервера. Обратите внимание, что это обычно требуется настроить в средах разработки, когда ваш сервер работает за корпоративным брандмауэром (см. ниже). Также вы можете указать определённый порт, если общедоступный порт отличается от SDR_LISTEN_PORT.
  • SDR_POPID: трёх- или четырёхзначный буквенно-цифровой код (SteamNetworkingPOPID) для дата-центра. Находится в разработке. В среде разработки оставьте это поле незаполненным.
  • SDR_PRIVATE_KEY: закрытый ключ из вашего сертификата. Это PEM-блок OpenSSH, который начинается с «-----BEGIN OPENSSH PRIVATE KEY-----».
  • SDR_CERT: ваш подписанный сертификат. Это проприетарный блок типа PEM, который начинается с «-----BEGIN STEAMDATAGRAM CERT-----».
  • SDR_NETWORK_CONFIG: полный путь к недавней локальной копии файла настроек SDR-сети для вашего приложения. Если эта переменная не задана, то для получения настроек сети сервер получит копию по HTTP во время начальной загрузки. Для лучшей производительности вы можете регулярно (например, каждый час) скачивать последнюю конфигурацию и сохранять её локально, чтобы задержки сети не провоцировали перебои. Так функционируют серверы Valve.

Запуск в среде разработки

Поскольку ISteamNetworkingSockets поддерживает простое UDP-соединение, для начала лучше всего сделать так, чтобы ваш код работал в этом интерфейсе через UDP, и не беспокоиться о ретрансляции.

Мы рекомендуем, чтобы ваш серверный код использовал наличие переменной среды SDR_LISTEN_PORT, чтобы определить, должен ли сервер ожидать SDR. Вы можете использовать ISteamNetworkingSockets::GetHostedDedicatedServerPort для получения значения.

Во время разработки оставьте SDR_POPID пустым. Когда SDR_LISTEN_PORT и SDR_POPID не заполнены, POPID получает специальный трёхзначный код разработки «dev».

Обычно в среде разработки аутентификация для серверов отключена (клиенты и ретрансляторы разрешают соединение с серверами разработки без подписанного сертификата, если у них есть подписанный билет). Вам потребуется другой механизм аутентификации для игрового координатора. Ваш игровой координатор должен быть осмотрительным при выдаче билетов серверам с обозначением «dev»!

У вашего сервера должна быть возможность получения незапрошенного публичного трафика. Это означает, что если у него нет общедоступного IP-адреса, вам понадобится настроить переадресацию портов в брандмауэре. Кроме того, вам, скорее всего, нужно будет настроить SDR_IP с соответствующим общедоступным IP-адресом (и портом, если он отличается от SDR_LISTEN_PORT).