ネットワーク初期化状態の検出
このトピックでは、Microsoft Game Development Kit (GDK) タイトルでネットワーク接続と初期化情報を取得する方法について説明します。 多くの場合、コア OS コンポーネントとネットワーク サービスが実行される前に起動されます。 その結果、WinSock
、WinHTTP
、BCrypt
、WinCrypt
、schannel
、IPHLPAPI
などの大部分のネットワーク API やセキュリティ API をタイトルが起動された直後に呼び出そうとすると、不確定な動作が発生します。 この動作には、予期しないエラー、初期化されていない戻り値、恣意的なパケット損失、潜在的なメモリ破損やクラッシュなどが含まれます。
この不確定な動作を回避するために、Microsoft Game Development Kit (GDK) タイトルは XNetworkingGetConnectivityHint 関数と XNetworkingRegisterConnectivityHintChanged 関数を使用する必要があります。 具体的には、XNetworkingConnectivityHint::networkInitialized
フィールドでは、ネットワークが初期化されているかどうかが示されます。 タイトルでは、networkInitialized
フィールドが true
になるまで待ってから、ネットワーク API やセキュリティ API を呼び出す必要があります。
多くのミドルウェア ライブラリでも、内部的にネットワーク API やセキュリティ API が使用されています。ネットワーク ミドルウェアでなくても、テレメトリやデバッグのためにネットワーク スタックが使用される場合があります。 各インスタンスでの処理については、ミドルウェア プロバイダーに問い合わせてください。 ミドルウェア自体でネットワークの初期化を待機していない場合は、ネットワークが初期化されるまで、ミドルウェアの読み込みを延期することが必要になる場合があります。 XSAPI、Azure PlayFab Party など、Microsoft Game Development Kit (GDK) 内の複数のライブラリでは、ネットワークが初期化されるまで待ってから、ネットワークを使用する必要があります。
一時停止と再開
さらに、タイトルの一時停止/再開サイクルによって、networkInitialized
フィールドは false
にリセットされます。 一時停止時のタイトルでは、すべてのネットワーク コンポーネントとセキュリティ コンポーネントへのすべてのハンドルをクリーンアップし、すべてのネットワーク操作を停止する必要があります。 サスペンド時の API の要件の詳細については、各ネットワーク API の概要ページを参照してください。 再開時のタイトルでは、再び networkInitialized
フィールドが true
になるまで待ってから、ネットワーク API やセキュリティ 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;
}
ネットワーク情報
Microsoft Game Development Kit (GDK) タイトルでのネットワーク情報は、XNetworkingGetConnectivityHint API を使用して取得できます。
XNetworkingGetConnectivityHint API からは、デバイス全体の情報ネットワーク接続レベル、データ制限、ワイヤードとワイヤレスの接続の種類、ネットワークが初期化されているかどうかが返されます。 これは、現在の情報がすぐに返されるリアルタイムの安全な API です。 XNetworkingRegisterConnectivityHintChanged 関数と XNetworkingUnregisterConnectivityHintChanged 関数で、変更をリッスンできます。
次のコード例では、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
に反映されると期待する場合があります。 それ以外の状態の場合、特定のタイトルのエンドポイントに対する接続があるかどうかが表されることはありません。
結果として、ネットワークの初期化を待機した後、WinSock
や WinHTTP
を使用して、XNetworkingConnectivityHint::connectivityLevelHint
フィールドの状態に関係なくエンドポイントへの接続の確立を試みることをお勧めします。 後でこれらの API が失敗した場合は、追加の UI と診断レポートのために XNetworkingGetConnectivityHint API を使用することをお勧めします。 その後、もう一度試す前に、ネットワーク接続レベルが変化するのを待つ必要があります。
高度なネットワーク情報の取得
大部分の Microsoft Game Development Kit (GDK) タイトルでは、XNetworkingGetConnectivityHint API を WinSock
API と組み合わせて使用し、ネットワークに関する状態と、IP アドレスなどの基本的なネットワーク情報を取得する必要があります。 詳細については、GDK で低レベルの IP ヘルパー API を参照してください。
通常、Win32 プログラムで使用するように、Microsoft Game Development Kit (GDK) でこの IP Helper
API を使用できます。
ソース ファイルで、
#include <winsock2.h>
の後に#include <iphlpapi.h>
を指定します。Ws2_32.lib
とIphlpapi.lib
にリンクする代わりに、XGamePlatform.lib
にリンクします。
WINAPI\_PARTITION\_GAMES
API ファミリの下にある API のみが、Microsoft Game Development Kit (GDK) タイトルで動作します。
Xbox 本体で IP Helper
API を使用すると、基になっているプラットフォーム抽象化のために、特定の情報が正確に表示されなくなります。 たとえば以下が含まれますが、これらに限りません。
- MAC アドレスは常に
AA-AA-AA-AA-AA-AA
になります。 - どのインターフェイスも、基礎となるネットワーク接続の種類に関係なく、常に有線インターフェイスを報告します。 本当のインターフェイスの種類は、XNetworkingGetConnectivityHint からのみ取得できます。
サポートされていないネットワーク接続 API
次のネットワーク接続 API は Microsoft Game Development Kit (GDK) タイトルではサポートされていないため、代わりに XNetworkingGetConnectivityHint API を使用してネットワーク接続を調べる必要があります。
関連項目
XNetworkingGetConnectivityHint
XNetworkingRegisterConnectivityHintChanged