PlayFab Party 和直接对等连接

本页介绍了如何使用示例游戏代码在 Playfab Party 中启用和使用直接对等连接。 它还包括帮助你评估何时在游戏中使用直接对等连接的注意事项。

何时使用直接对等连接

Playfab Party 支持各种通信拓扑。 从概念上讲,所有聊天或数据消息都是从一个对等设备或用户直接发送给其他人。 然而,Party 将自动利用透明云中继服务,通过建立直接对等连接来避免常见的环境和安全问题。 可以通过利用其后台服务质量 (QoS) 测量来实现低延迟数据传输。 (有关详细信息,请参阅 Playfab Party QoS 度量。)你可以选择启用直接对等连接来进一步减少数据传输延迟。 由于“安全注意事项”下详述的安全问题,Microsoft 建议你使用我们的云中继服务,而不是启用直接对等连接,除非你的游戏具有严格的延迟要求。

平台支持

Windows 10、Microsoft Game Core、任天堂 Switch、PlayStation®4 和 PlayStation®5 版本的 Party 库支持直接对等连接。 不管通过客户端 API 指定的直接对等连接选项如何,库的其他版本都将始终使用云中继进行数据传输。

“PlayStation”是索尼互动娱乐公司的注册商标或商标。

安全注意事项

由于直接对等连接用于在客户端之间直接发送数据,因此客户端都需要知道如何相互连接。 这是通过在游戏会话中的客户端之间共享客户端 IP 地址来完成的。 例如,如果一个 16 个玩家的多人游戏使用直接对等连接来更新玩家位置,则 16 个游戏客户端中的每一个都需要知道其他 15 个客户端的 IP 地址,以知道向谁发送数据。

在游戏客户端之间共享 IP 地址存在安全风险。 共享 IP 地址可能允许不良行动者检测 IP 地址并使用它对游戏外部的其他玩家实施恶意攻击。 执行这些攻击的常见方法是通过拒绝服务 (DOS) 攻击,或称为分布式拒绝服务 (DDOS) 攻击的变体。 攻击的工作原理是通过尝试使用多余的网络流量使网络过载。 如果攻击者可以向其受害者发送足够的网络流量,则受害者的网络硬件(调制解调器和路由器)必须花费所有时间处理多余的流量,并且没有时间执行处理合法网络连接的正常工作。 实际上,这意味着受害者在整个攻击期间都无法使用其网络。 这通常称为“脱机启动”。

总之,成功的直接对等连接可能会降低某些设备之间的延迟。 但是,尝试建立直接对等连接还需要用户向其他人披露其 IP 地址,这可能会使恶意用户能够在游戏外部攻击其设备和 Internet 连接。 出于策略原因,在某些平台上可能也不允许直接对等连接。 请务必使用适当的直接对等连接选项来实现性能和安全目标。 如果在权衡风险后决定使用直接对等连接,请使用以下示例,以按每个网络和每台设备选择加入游戏。

LAN 方案

Party 中的直接对等连接可用于在 LAN 方案中实现极低延迟。 但是,即使在这些情况下,也需要有限的 Internet 连接来支持用户身份验证、LiveOps 数据和见解以及语音聊天辅助功能。

上游带宽注意事项

使用直接对等连接可能会增加游戏的上游带宽使用量。 当通过云中继服务传输游戏或语音消息时,Party 会向该服务发送一条消息;然后该服务会将该消息复制并转发到每个目标设备。 当通过直接对等连接传输游戏或语音消息时,Party 将通过已建立直接对等连接的每个目标设备的直接连接复制和发送该消息。 因此,游戏的上游带宽使用量将随建立了直接对等连接的设备数量成比例扩展。 在启用直接对等连接之前,请考虑你的游戏是否可以接受上游带宽增加。

如何在游戏中使用直接对等连接

在网络中启用直接对等连接

通过 PartyManager::CreateNewNetwork() 创建网络时,可以通过提供给调用的 PartyNetworkConfiguration 指定各种网络配置参数。 可以使用 PartyNetworkConfiguration::directPeerConnectivityOptions 字段指定网络中的设备是否支持直接对等连接以及如何支持。

以下示例演示了一个网络配置,它指定应在网络中的所有设备之间尝试直接对等连接,而不管平台类型或登录提供程序如何。

PartyNetworkConfiguration configuration = {};
configuration.directPeerConnectivityOptions = PartyDirectPeerConnectivityOptions::AnyPlatformType | PartyDirectPeerConnectivityOptions::AnyEntityLoginProvider;
// Initialize the rest of the network configuration parameters appropriately for your game before using.

在成功将初始用户验证到网络中时,如果网络配置允许,设备可能会尝试与已参与网络的其他设备建立直接对等连接。 如果尝试成功,设备之间的终结点消息和聊天数据将使用这些直接连接传输。 对于由于设备之间的环境不兼容而失败的尝试,这些设备之间的所有通信都将通过透明云中继服务器进行传输。 如果网络配置不允许设备尝试直接对等连接,则它们永远不会交换 IP 地址信息,并且将始终通过透明云中继服务器传输终结点消息和聊天数据。

注意

建立直接对等连接是尽力而为的,由于环境因素、每设备连接选项或平台策略,可能无法实现。 有关评估是否已建立到特定设备的直接对等连接的详细信息,请参阅评估连接类型和延迟

限制每台设备的直接对等连接

除了网络配置中的直接对等连接选项外,设备可以使用 PartyManager::SetOption() 设置 PartyOption::LocalDeviceDirectPeerConnectivityOptionsMask,从而针对其进行身份验证的所有网络进一步限制直接对等连接。 使用按位 AND 运算计算所有标志。 也就是说,仅在以下三处启用特定标志时,该特定标志才会对给定网络的设备对有效: 网络配置以及两个设备各自的本地掩码选项。 即使网络配置允许相关形式的直接对等连接,任一设备也可以通过不在其本地设备掩码选项中启用标志,独立选择退出 IP 地址披露和它们之间的直接连接尝试。 在支持直接对等连接的库版本中,PartyOption::LocalDeviceDirectPeerConnectivityOptionsMask 值默认允许网络启用的所有直接对等连接。 因此,只有当你有特定于设备的要求时才需要对其进行配置,以便阻止涉及本地设备的部分或全部直接对等连接。

以下示例说明了如何限制本地设备的直接对等连接,以便它只尝试建立至同一平台设备的直接对等连接。

PartyDirectPeerConnectivityOptions localDeviceMask = PartyDirectPeerConnectivityOptions::SamePlatformType | PartyDirectPeerConnectivityOptions::AnyEntityLoginProvider;
PartyError error = PartyManager::GetSingleton().SetOption(nullptr, PartyOption::LocalDeviceDirectPeerConnectivityOptionsMask, &localDeviceMask);
if (PARTY_FAILED(error))
{
    printf("Failed to set local device direct peer connectivity options mask! error = 0x%08x\n", error);
}

评估连接类型和延迟

可以通过调用 PartyNetwork::GetDeviceConnectionType() 来确定本地设备是否建立了对特定远程设备的直接对等连接。

建议不要主动强制对任何给定设备对进行直接对等连接(例如,如果 PartyNetwork::GetDeviceConnectionType() 报告除 以外的值,请不要调用 PartyDeviceConnectionType::DirectPeerConnectionPartyNetwork::LeaveNetwork()),因为使用的特定基础传输方法不会改变通信的整体逻辑能力。 如果游戏设计对于最大消息延迟有严格要求(其鼓励直接对等连接),那么最好根据 PartyEndpointStatistic::AverageDeviceRoundTripLatencyInMilliseconds 统计数据所报告的该延迟的当前具体观察结果采取措施,而不是根据传输机制进行抽象假设。 否则,你可能会不断阻碍用户尝试与同一组好友玩游戏,由于无法控制的环境因素,他们总是需要使用附近的透明云中继服务器。

下面的示例说明了如何检查从 localEndpointnetwork 中的 remoteEndpoint 的往返延迟。

// A helper for inspecting the connection type and average round trip latency between a local endpoint and a remote
// endpoint in a network.
void PrintConnectionTypeAndLatency(
    PartyNetwork* network,
    PartyLocalEndpoint* localEndpoint,
    PartyEndpoint* remoteEndpoint
    )
{
    // Retrieve the device associated with the remote endpoint.
    PartyDevice* remoteDevice;
    PartyError error = remoteEndpoint->GetDevice(&remoteDevice);
    if (PARTY_FAILED(error))
    {
        printf("Failed to get the remote device! error = 0x%08x\n", error);
        return;
    }

    // Get the device connection type.
    PartyDeviceConnectionType connectionType;
    PartyError error = network->GetDeviceConnectionType(remoteDevice, &connectionType);
    if (PARTY_FAILED(error))
    {
        printf("Failed to get device connection type! error = 0x%08x\n", error);
        return;
    }

    // Retrieve the latency statistic.
    PartyEndpointStatistic latencyStatistic = PartyEndpointStatistic::AverageDeviceRoundTripLatencyInMilliseconds;
    uint64_t latencyStatisticValue;
    error = localEndpoint->GetEndpointStatistics(
        1,                       // targetEndpointCount
        &remoteEndpoint,         // targetEndpoints
        1,                       // statisticCount
        &latencyStatistic,       // statisticTypes
        &latencyStatisticValue); // statisticValues
    if (PARTY_FAILED(error))
    {
        printf("Failed to get latency statistic! error = 0x%08x\n", error);
        return;
    }

    // Print the results.
    printf("Local endpoint 0x%p and remote endpoint 0x%p in network 0x%p have average round trip latency %llu ms and device connection type %i\n",
        localEndpoint,
        remoteEndpoint,
        network,
        latencyStatisticValue,
        static_cast<int32_t>(connectionType));
}

连接类型中的更改

更改环境条件可能会中断直接对等连接,使其无法用于 PlayFab Party。 如果发生这种情况,设备会尝试回退到通过云中继服务器进行通信。 如果仍可中继通信,则 PartyNetwork::GetDeviceConnectionType() 函数将开始报告 PartyDeviceConnectionType::RelayServer,并且设备将使用新的连接类型继续保留在 Party 网络中。 否则,连接中断的设备将离开网络。

警告

在直接对等连接中断时仍在直接对等连接上传输或接收的聊天和游戏消息可能从不会到达,即使它们是使用 PartySendMessageOptions::GuaranteedDelivery 发送也是如此,即使它们不再计入通过 PartyLocalEndpoint::GetEndpointStatistics() 返回的 PartyEndpointStatistic::CurrentQueuedSendMessagesPartyEndpointStatistic::CurrentActiveSendMessages 值也是如此。 此外,即使使用 PartySendMessageOptions::SequentialDelivery 发送,在连接类型转换期间传输的消息也可能无法按顺序到达。 在使用直接对等连接和这些 PartySendMessageOptions 时,游戏应为数据丢失和顺序错误可能性做好准备。

PartyDeviceConnectionType::RelayServer 的连接类型从不会更改为其他类型,无论该值是在设备最初加入网络时分配的,还是在之前中断的直接对等连接之后分配的。

计费指示器

使用直接对等连接的网络与使用云中继服务的网络应用相同的计费指示器。 但是,只有通过云中继服务的游戏或语音数据才会计入网络出口Party 语音计量器。