检测网络初始化状态

使用此主题了解如何检索 Microsoft 游戏开发工具包(GDK)游戏中的网络连接和初始化信息。 它们通常在核心操作系统组件和网络服务运行之前启动。 因此,在游戏启动后过快地尝试调用大多数网络和安全 API(包括 WinSockWinHTTPBCryptWinCryptschannelIPHLPAPI)将导致不确定的行为。 这些行为可能包括意外失败、未初始化的返回值、任意数据包丢失以及潜在的内存损坏和崩溃。

为了避免此不确定的行为,Microsoft 游戏开发工具包(GDK)游戏应使用 XNetworkingGetConnectivityHintXNetworkingRegisterConnectivityHintChanged 函数。 XNetworkingConnectivityHint::networkInitialized 字段尤其指示网络是否已初始化。 游戏应等到 networkInitialized 字段为 true,才能调用网络和安全 API。

许多中间件库还在内部使用网络和安全 API,即使是非网络中间件也可能使用网络堆栈来进行遥测或调试。 要了解每种情况下该如何操作,请向中间件提供商咨询。 如果中间件本身并不等待网络初始化,可能需要延迟加载中间件,直到网络完成初始化。 Microsoft Game Development Kit (GDK) 中的多个库(例如 XSAPIAzure PlayFab Party)都需要等到网络初始化完成后才能使用。

暂停和继续

此外,游戏挂起/恢复周期会将 networkInitialized 字段重置回 false。 在挂起时,游戏应该清理指向所有网络和安全组件的所有句柄,并且停止所有网络操作。 有关该 API 暂停时的要求的更多信息,请参阅每个网络 API 的概述页。 恢复后,游戏应再次等到 networkInitialized 字段变为 true,然后再尝试重新建立连接,并使用任何网络或安全 API。 建议恢复网络初始化路径与游戏的初始启动路径相同,即在恢复时或在游戏启动时,等待网络初始化完成,然后再启动您的网络代码。 不知道暂停/恢复的中间件库(如 XSAPI、GameChat2 和 Azure PlayFab Party)必须在暂停时进行清理,并在等待网络初始化后在恢复时重新初始化。

测试网络初始化

在恢复和游戏启动期间进行网络初始化通常都需要几秒钟时间,具体取决于主机类型和用户的网络环境。 在开发过程中,网络初始化几乎是瞬时完成的。 这可能会隐藏游戏各个部分中导致无法正确等待网络初始化的问题。 要测试网络初始化方案,可以使用 xbconfig NetworkInitDelayInSeconds=30 在网络初始化过程中添加任意延迟。 使用此设置时,请确保在两次测试之间使用 xbapp terminate /full 充分重新启动您的游戏。 完成测试后,将 NetworkInitDelayInSeconds 设置回 0

网络初始化代码示例

下列代码示例说明如何以实时安全的方式进行轮询,以了解网络是否已初始化。


bool IsNetworkInitialized()
{
    XNetworkingConnectivityHint connectivityHint;
    if (SUCCEEDED(XNetworkingGetConnectivityHint(&connectivityHint)))
    {
        return connectivityHint.networkInitialized;
    }
    return false;
}

以下代码示例说明在网络初始化完成之前,如何阻止游戏。

static
void
NetworkConnectivityHintChangedCallback(
    _In_ void* context,
    _In_ const XNetworkingConnectivityHint* connectivityHint
    )
{
    HANDLE networkInitializedEvent = static_cast<HANDLE>(context);
    if (connectivityHint->networkInitialized)
    {
        (void)SetEvent(networkInitializedEvent);
    }
}

HRESULT EnsureNetworkInitialized()
{
    HRESULT hr = S_OK;
    XNetworkingConnectivityHint connectivityHint;
    XTaskQueueHandle queue;

    hr = XTaskQueueCreate(XTaskQueueDispatchMode::Immediate, XTaskQueueDispatchMode::Immediate, &queue);
    if (SUCCEEDED(hr))
    {
        // Use the new XNetworking APIs to check if the network is initialized.
        hr = XNetworkingGetConnectivityHint(&connectivityHint);
        if (SUCCEEDED(hr))
        {
            if (!connectivityHint.networkInitialized)
            {
                // The network isn't initialized. Wait until the network becomes initialized.
                HANDLE networkInitializedEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
                if (networkInitializedEvent != nullptr)
                {
                    XTaskQueueRegistrationToken token;
                    hr = XNetworkingRegisterConnectivityHintChanged(queue, networkInitializedEvent, NetworkConnectivityHintChangedCallback, &token);
                    if (SUCCEEDED(hr))
                    {
                        DWORD result = WaitForSingleObjectEx(networkInitializedEvent, INFINITE, FALSE);
                        if (result != WAIT_OBJECT_0)
                        {
                            hr = HRESULT_FROM_WIN32(GetLastError());
                        }

                        XNetworkingUnregisterConnectivityHintChanged(token, true);
                    }

                    CloseHandle(networkInitializedEvent);
                }
                else
                {
                    hr = HRESULT_FROM_WIN32(GetLastError());
                }
            }
        }

        XTaskQueueCloseHandle(queue);
    }

    return hr;
}

网络信息

可以使用 XNetworkingGetConnectivityHint API 来检索 Microsoft 游戏开发工具包(GDK)游戏中的网络信息。

XNetworkingGetConnectivityHint API 返回设备范围的有关网络连接级别、数据限制、有线和无线连接类型以及网络是否初始化等信息。 它是一种可立即返回最新信息的实时安全 API。 您可以使用 XNetworkingRegisterConnectivityHintChangedXNetworkingUnregisterConnectivityHintChanged 函数来侦听更改。

以下代码示例演示如何使用 XNetworkingGetConnectivityHint 函数查询有关当前网络状态的信息。


XNetworkingConnectivityHint connectivityHint;
if (SUCCEEDED(XNetworkingGetConnectivityHint(&connectivityHint)))
{
    printf(L"network initialized %u\n", connectivityHint.networkInitialized);
    printf(L"network connectivity level hint %u\n", connectivityHint.connectivityLevel);
    printf(L"network connectivity cost hint %u\n", connectivityHint.connectivityCost);
    printf(L"network approaching data limit %u\n", connectivityHint.approachingDataLimit);
    printf(L"network over data limit %u\n", connectivityHint.overDataLimit);
    printf(L"device is roaming %u\n", connectivityHint.roaming);
    switch (connectivityHint.ianaInterfaceType) {
    case IF_TYPE_ETHERNET_CSMACD:
        printf(L"network type is wired\n");
            break;
    case IF_TYPE_IEEE80211:
        printf(L"network type is wireless\n");
        break;
    case IF_TYPE_WWANPP:
    case IF_TYPE_WWANPP2:
        printf(L"network type is broadband\n");
        break;
    default:
        printf(L"network type is unusually esoteric %u\n", connectivityHint.connectivityLevel);
        break;
    }
}

网络连接最佳做法

返回的 XNetworkingConnectivityHint 结构中的字段(而不是 XNetworkingConnectivityHint::networkInitialized 字段)是提示内容。 它们是设备对网络当前状态的尽可能猜测。 这是基于在设备上观察到的网络流量的启发。

XNetworkingConnectivityLevelHint 的状态表示常规的网络级别近似值,用于简化游戏的连接逻辑。 游戏可预期 XNetworkingConnectivityLevelHint::None 反映网络媒体断开连接,以及在稳定状态下(网络环境在几分钟内没有变化的情况下)普遍缺乏连接性的情况。 其他状态不表示是否存在到特定游戏终结点的连接。

因此,建议在等到网络初始化完成后,无论 XNetworkingConnectivityHint::connectivityLevelHint 字段的状态如何,都使用 WinSock 和/或 WinHTTP 尝试建立到终结点的连接。 如果这些 API 后来失败了,我们建议您将 XNetworkingGetConnectivityHint API 用于其他 UI 和诊断报告目的。 然后,您应等到网络连接级别发生变化之后,再重试。

检索高级网络信息

大多数 Microsoft 游戏开发工具包(GDK)游戏都应将 XNetworkingGetConnectivityHint API 与 WinSock API 结合使用,来检索网络状态和基本网络信息(例如 IP 地址)。 如果您需要更多信息,GDK 中提供了低级别 IP 帮助程序 API

一般情况下,在 Microsoft 游戏开发工具包(GDK)中使用 IP Helper API 的方式与在 Win32 程序中使用此 API 的方式相同。

  1. 在您的源文件中,#include <iphlpapi.h> 位于 #include <winsock2.h> 的后面。

  2. 代替直接链接 Ws2_32.libIphlpapi.lib,链接 XGamePlatform.lib

只有 WINAPI\_PARTITION\_GAMES API 系列下的 API 才能用于 Microsoft 游戏开发工具包(GDK)游戏。

在 Xbox 主机上,由于基础平台抽象,使用 IP Helper API时某些信息不准确。 这包括但不限于以下各项:

  • MAC 地址将始终为 AA-AA-AA-AA-AA-AA
  • 无论基本网络连接类型是什么,所有接口都将始终报告有线接口。 只能通过 XNetworkingGetConnectivityHint 检索真实接口类型。

不支持的网络连接 API

Microsoft 游戏开发工具包(GDK)游戏不支持以下网络连接 API,而是应改用 XNetworkingGetConnectivityHint API 来确定网络连接。

另请参阅

XNetworkingGetConnectivityHint

XNetworkingRegisterConnectivityHintChanged

XNetworkingUnregisterConnectivityHintChanged

Windows 套接字 2 (Winsock)

Windows HTTP 服务 (WinHTTP)

IP 帮助程序 API