Steamworks 文献库
Steam 数据报中继
Steam 数据报中继(SDR)是 Valve 的虚拟私有游戏网络。 通过使用我们的 API,您不仅可以在 Valve 专用于游戏内容的骨干网络上传递自己的游戏流量,还可以访问我们的中继网络。 中继流量可以保护您的服务器和玩家免受 DoS 攻击,因为 IP 地址永远不会被显示。 您收到的所有流量都经过了验证、加密并受到速率限制。 此外,我们还可以通过我们的网络针对海量玩家找到更快的路由,切切实实地改善 ping 时间

此中继网络可以用于对等流量和专用服务器。

移植现有网络代码的一般要求和一些提示

以下是一些适用于 P2P 和专用服务器连接的一般注意事项。

首先,任何由公共 IP 标识网络主机的地方(游戏服务器几乎全是如此)都需要更改为使用不同的标识符。 有几种选择:
  • 如果是登录 Steam 的客户端和游戏服务器,您通常需要使用 SteamID。
  • 如果您的游戏服务器不登录 Steam,而是使用基于票证的验证流程,您可以使用任何其他对您来说有意义的标识符。 请参见 SteamNetworkingIdentity
  • 在某些代码库中,充满了“网络主机和游戏服务器是使用 IPv4 地址识别的”这种假设,而改变这一假设需要大量工作。 事实上,Steamworks ISteamMatchmakingISteamMatchmakingServers API 就具有这种属性,我们自己的一些游戏(例如《军团要塞 2》)也具有此属性。 在这种情况下,您可以使用 Steamworks“Fake IP”(假 IP)系统。 FakeIP 是在大多数情况下“看起来”像有效 IPv4 地址的 IP,但实际上却来自网上未使用的保留地址空间。 为您的服务器分配 FakeIP 后,服务器仍然可以使用 IPv4 地址寻址,并且几乎所有一切都将如常工作。 ISteamNetworkingSocketsISteamMatchmakingServers 系统会识别这些特殊 IP 并采取适当的操作。 FakeIP 不可路由且不适用于一般互联网用途(例如,您无法 ping 它们)。 请参见 ISteamNetworkingSockets::BeginAsyncRequestFakeIP,获取更多信息。

其次,您需要修改所有低级套接字代码,以使用一个 Steamworks API 进行连接。
  • 理想情况下,您可以使用一个返回 HSteamNetConnection 的面向连接的 API ISteamNetworkingSockets 接口。
    (请注意,这些 API 还支持普通的 UDP 传输,这对于测试非常有用。 此外,还有一个开源版本。)
  • 一些代码库是以更类似于 UDP 的方式编写的,其中的数据包可以随时发送到任何远程主机上,而不是所有消息都发送到已建立的“连接”中。 在这些情况下,可能有用的 Steamworks 功能有两个。

在其他平台和商店使用 SDR 的要求

如果只在一个平台上运行,那跨平台游戏的网络 API 和 DDoS 解决方案就毫无用处了。 在大多数情况下,您在其他平台和商店的玩家都可以访问中继网络,前提是您的游戏要满足一些基本条件。
  • 在 Steam 上发布您游戏的一个版本。
  • 如果我们需要推出错误修复或安全补丁,在询问您时,您同意在合理的时间范围内(比如几个月)更新您的游戏。
  • 很遗憾,请理解我们不能保证非 Steam 玩家始终可以使用此服务。 万一我们需要降级这项服务,我们将尽一切可能与您合作,以避免对您的玩家造成干扰,也会给您时间制定计划。 SDK 内置了这样的机制:我们可以让客户端回退到直接 UDP 连接或尝试 NAT 穿越,但您也应该记住这种可能性。
  • 拥有某种匹配服务(SDR 将其称为您的“游戏协调程序”),可以发布某种身份验证凭据。 为此,我们有一个单独的 SDK。 见下文。

请联系我们并询问相关 SDK 的使用事宜以及相关细则。 我们仍在研究将代码分发给合作伙伴的最佳方式的细节,目前我们可能无法向所有合作伙伴和所有游戏提供跨平台支持。

有关在其他平台和商店实现 SDR 的更多技术信息,请参见下文。

如果您不符合上述条件,可以使用 API 的 opensource 版本来满足您的需求。 请注意,开源代码不支持访问中继网络。

P2P 游戏

对于 Steam 上对等流量而言,您只需使用 ISteamNetworkingSockets::CreateListenSocketP2PISteamNetworkingSockets::ConnectP2P 等 API,即可利用 SDR。 Steam 会处理好一切其他问题。 对于其他平台和商店,请阅读下文有关其他技术要求的更多信息。

已知数据中心的专用服务器

就算有一个“对等端”是专用服务器,对等 API 也可以良好运行。 但是有一个重要的问题:如果您的专用服务器离运行中继的数据中心较远,那么最佳中继路由可能会比默认 IP 路由慢,并且至少会有一些玩家的延迟比现状更差。

为了获得最佳的专用服务器体验,服务器应该在属于 SDR 网络一部分的已知数据中心中运行。 我们会确保中继在附近运行,并且中继的路由永远不会比默认 IP 路由慢太多。 在这些已知数据中心的服务器使用特别的 API 进行连接。 这种用法在 SDK 中称为“托管专用服务器”(Hosted Dedicated Server)。 请注意,这并不一定意味着 Valve 正在托管服务器或中继——它可能是我们与之建立关系的第三方数据中心,并且是 Steam 数据报中继系统已知的地方。

如果您通过主要托管服务提供商运行游戏服务器并且对使用 SDR 感兴趣,请与我们联系。 我们会尝试与您的托管公司合作,在数据中心运行中继。 这是理想的情况,但即使这不可能,我们也可以将数据中心添加到我们的网络配置系统中,并且只使用附近的 Valve 中继。

如果您是专用服务器托管公司,并想加入我们的网络以便您的顾客可以利用 SDR,请与我们联系! 我们尚未在任何第三方托管公司中部署中继,但是我们对此很有兴趣。

无需游戏协调程序而连接至专用服务器的简单流程

如果您没有自己的中央匹配/登录服务(有时将其称为“游戏协调程序”)来将玩家分配到不同服务器,或者只是想让事情变得尽可能简单,您可以使用 ISteamNetworkingSockets::CreateListenSocketP2P ISteamNetworkingSockets::ConnectP2P 连接至位于已知数据中心的专用服务器。 在这种情况下,会像所有普通 P2P 连接那样在客户端上启动连接。 会合消息是通过 Steam 发送的,因此,如果玩家或服务器和 Steam 的连接断开,就无法再建立连接。 此外,Steam 除了验证玩家已登录至 Steam 且拥有游戏之外,不会对尝试连接的人加以限制。

以票证为基础的服务器连接流程

如果您有自己的游戏协调程序服务,我们推荐您使用以票证为基础的连接流程。 与简单的 P2P 式的连接流程相比,它通常只需要多一点工作,且有两个重要的优势:
  • 您只向应该被允许尝试连接的玩家发出票证,因此不需要的连接尝试甚至不会到达您的服务器。
  • 玩家获得票证后,即使他们失去与 Steam 的连接、服务器失去与 Steam 的连接、玩家的计算机崩溃和重新启动等,也可以连接到服务器。 对于惩罚玩家退出行为的游戏来说,在这些常见错误发生时能够稳定地重新连接至游戏服务器尤其重要。

以票证为基础并通过 SDR 连接至专用服务器的过程如下:

目前,基于票证的身份验证无法与 FakeIP 系统结合使用。

游戏协调程序 SDK

我们用“游戏协调程序”这一术语用来指代您的后端/匹配服务器。 我们有一个分开的小型 SDK,您可以将其和您的游戏协调程序相连接,这可以用来:
  • 为客户端颁发票证,让其可以访问托管于 SDR 后方的游戏服务器。
  • 解析 PingLocation_t 字符串,并计算出这些对象之间的 ping 时间。
  • 为其他平台和商店的玩家颁发身份证书。
  • 使用其他某些高级功能。

此 SDK 可以在此处获得。

使用游戏协调程序 SDK 进行验证

SDR 使用两个验证机制:

  • 托管服务器票证由您的游戏协调程序颁发,授权特定客户端与特定专用服务器交谈一段时间。 中继票证仅用于使用专用服务器的情况。 请参见 SteamDatagramRelayAuthTicket。
  • 证书用于传统的验证方式,并进行 DH 密钥交换,以建立加密频道。 证书为端对端概念,可用于各种形式的 SteamNetworkingSockets 通信,包括直接 UDP 连接或 P2P。 请参见 SteamDatagram_CreateCert from the Game Coordinator SDK 和 ISteamNetworkingSockets::GetCertificateRequest

我们使用专有公钥基础结构(PKI)来验证客户端和服务器。 颁发给玩家的是个人短期证书,与其特定玩家身份相关。 这方面由 Steam 处理。 对于游戏服务器,我们通常使用更长期的证书,为特定 AppID 授权整个数据中心。 此类证书由您颁发。

在颁发票证和证书前,您需要生成密钥对并向我们发送您的公钥。 我们会发布由我们的 CA 主密钥签署的证书,为您的应用将您的密钥标记为受信任。 然后您可以使用我们的证书工具,离线为您希望运行服务器的每个数据中心生成证书,然后用自己的私钥签署。 您将通过安全渠道将这些证书分发给您的游戏服务器,传入环境中的服务器(见下文)。

您还需要在每次玩家连接至游戏服务器时,用自己的密钥生成票证。

务必确保您的 CA 私钥和证书私钥的安全! 如果私钥泄漏,需要吊销和替换,可能导致服务中断。

在其他平台和商店实现 SDR


您在其他平台和商店的客户将无法登录 Steam,因此您需要为这些玩家提供 Steam 为 Steam 玩家提供的一些服务。

游戏协调程序初始化

  • 您的匹配服务(称为“游戏协调程序”)将需要与游戏协调程序 SDK 连接。 头文件 steamdatagram_gamecoordinator.h 中有更多细节。 游戏协调程序 SDK 使用纯 C API,因此与其他语言集成应该相对容易。
  • 在初始化时下载网络配置,大约每小时检查一次更新。 (参见 SteamDatagram_GameCoordinator_GetNetworkConfigURL 和 SteamDatagram_GameCoordinator_SetNetworkConfig。)网络配置是一个很小的 JSON 文件,在撰写本文时约为 26K(压缩后为 9K)。 此 URL 具有很高的可用性,但是如果您希望处理失败的可能性,您可以使用最近下载的版本。
  • 您需要为您的游戏验证的密钥对。 将公钥发送给我们,并使用您的私钥初始化游戏协调程序 SDK。 (有关更多信息,请参阅 SteamDatagram_SetPrivateKey_Ed25519。)

客户端登录

  • 客户端将调用 ISteamNetworkingSockets::GetCertificateRequest 来获取一个 blob,并将其与登录请求消息一起发送给您的游戏协调程序。
  • 当游戏协调程序收到登录请求时,会使用 SteamDatagram_CreateCert 为客户端生成证书。
  • 在登录响应中将生成的证书发送回客户端。 客户端应使用 ISteamNetworkingSockets::SetCertificate 安装其证书。
  • 强烈建议您此时也将网络配置分发给客户端。 客户端将使用 SteamDatagram_SetNetworkConfig 应用网络配置。

证书是有期限的,我们建议您使用 48 小时的有效期。 如果客户端连接时间可能超过 48 小时,则您需要定期更新证书。 任何时候申请新证书都可以接受,因此如果您想更频繁地颁发证书(例如在每场比赛开始时),是可以做到的。

每个客户都必须有一个独特的身份。 如果可能,请使用平台专用的身份。 (对于 Steam 客户端来说,这是必需的。)但是,如果这不可能,您可以使用对您的匹配程序来说有意义的“通用字符串”身份。 请参阅 SteamNetworkingIdentity

P2P 游戏

P2P 连接需要“信令”服务。 这是一个低带宽、非延迟敏感、尽力交付的通道,能够转发用于协商路由的、偶尔会有的会合消息。 这要求客户端与您的匹配服务建立持久连接(例如 websocket 或 TCP 连接),以便您可以向其推送消息。 如果客户端使用请求/响应模式(如通过 http)与您的游戏协调程序交谈,那将无法正常工作。 您只需要提供“尽力”的交付,也就是说库可以容忍消息丢失和多次传递的行为。

  • 要启动连接,请使用 ISteamNetworkingSockets::ConnectP2PCustomSignaling。 您需要实现 ISteamNetworkingConnectionSignaling 的子类,当调用 SendSignal 时,客户端应将消息发送到您的后端,而您的后端应尽最大努力将消息传递给对等端。 首次创建连接时,通常会交换 4-10 条初始消息。 此后,如果路由条件发生变化,您可能会被要求为已建立的连接发送信令。
  • 当客户端收到信令时,调用 ISteamNetworkingSockets::ReceivedP2PCustomSignal。 库将解码消息。 如果涉及现有连接,将在内部处理信令。 如果信令是针对新连接的,则会调用 ISteamNetworkingSignalingRecvContext::OnConnectRequest。

请参阅 steamnetworkingcustomsignaling.h,以获得更多详细信息。

运行已知数据中心的服务器

本节记录了运行已知数据中心专用服务器所涉及的一些技术细节。

环境变量

专用服务器从环境变量中获取配置。 请注意,在 Valve 数据中心中,所有的值都会为您自动设置。
  • SDR_LISTEN_PORT:您的服务器从中继接收流量的 UDP 端口。 专用服务器只使用单一套接字 (但您可以通过使用“虚拟端口”,获得多个逻辑“侦听套接字”。 参见 ISteamNetworkingutils::CreateHostedDedicatedServerListenSocket。)我们的数据中心通常使用 30xxx 范围。
  • SDR_IP:您的服务器必须有一个公共 IP,可以从中继接收“未经请求”的流量。 如果服务器只有一个带有公共 IP 的接口,则该接口将被使用。 否则,您需要告诉游戏服务器使用什么 IP。 SDR 套接字将与 INADDR_ANY 绑定,但需要此信息来填入服务器的 SteamDatagramHostedAddress。 请特别注意,这通常需要在开发环境中设置,也就是说,您的服务器位于公司防火墙之后。 (参见下文。)如果公共端口与 SDR_LISTEN_PORT 不同,您也可以指定端口。
  • SDR_POPID:数据中心在生产环境中的字母数字代码,由 3 个或 4 个字符构成(SteamNetworkingPOPID)。 在开发环境中,此项留空。
  • SDR_PRIVATE_KEY:来自您证书的私钥, 这是一个以“-----BEGIN OPENSSH PRIVATE KEY-----”开始的 OpenSSH PEM 程序块。
  • SDR_CERT:您签名的证书。 它是具有专有格式、类似于 PEM 的数据块,以“-----BEGIN STEAMDATAGRAM CERT-----”开始。
  • SDR_NETWORK_CONFIG:您应用的 SDR 网络配置文件的近期本地副本的完整路径。如果未设置此变量,则服务器为了获取网络配置,会在启动时使用 HTTP 来获得副本。 您可以定期(如每小时)下载最新的配置并在本地保存,这样网络在不稳定时就不会造成任何中断,达到最佳性能。 Valve 服务器就是按此方法配置的。

在 dev 环境中运行

由于 ISteamNetworkingSockets 支持普通 UDP 连接,通常最好一开始就通过 UDP 让您的代码运用此接口,而不必担心中继。

我们建议您的服务器代码利用 SDR_LISTEN_PORT 环境变量是否存在来决定服务器是否应侦听 SDR。 您可以使用 ISteamNetworkingSockets::GetHostedDedicatedServerPort 来获取值。

在开发环境中,请将 SDR_POPID 留空。 当 SDR_LISTEN_PORT 与 SDR_POPID 为空时,POPID 设置为专门的 3 字符代码“dev”。

一般来说,“dev”环境下的服务器验证被禁用。 (客户端与中继只要有一个签名的票证,就会允许连接至“dev”服务器,而无需签名证书。)您需要另一个机制来验证您的游戏协调程序。 您的游戏协调程序在向任何宣称属于“dev”的服务器提供票证时都需小心谨慎!

您的服务器需要能够接收未经请求的公开流量,意味着如果其无公开 IP,那么您需要在防火墙中设置端口转发。 您可能还要用恰当的公开 IP(如果端口与 SDR_LISTEN_PORT 不同,还需要相应端口)来设置 SDR_IP。