Microsoft Game Development Kit の Windows ソケットの概要
Microsoft Game Development Kit (GDK) では、Windows Sockets 2 (Winsock) API の使用がサポートされています。
Windows Sockets 2 (Winsock) を使用すると、使用されているネットワーク プロトコルとは関係なく、高度なインターネット、イントラネット、その他のネットワーク対応アプリケーションを作成して、アプリケーション データをネットワーク経由で送信できます。
Microsoft Game Development Kit (GDK) タイトルが Winsock と対話する方法は、通常、Win32 プログラムが Winsock と対話する方法と同じです。
このトピックでは、細かな違いと Game Development Kit (GDK) タイトルでの Winsock の使用に関する、ベスト プラクティスについて説明します。
設定
このセクションでは、Winsock API を使用するときに含める必要がある .h ファイルと .lib ファイルについて説明します。
- ソース ファイルに、
#include <winhttp.h>
を追加します。 - PC タイトルの場合は、引き続き
Winhttp.lib
にリンクします。 - Xbox 本体タイトルの場合は、
Winhttp.lib
に対して直接ではなく、XGamePlatform.lib
にリンクする必要があります。
WINAPI_PARTITION_GAMES
API ファミリの下にある API のみが、Microsoft Game Development Kit (GDK) タイトルで動作します。
ネットワークの初期化
WSAStartup の最初の呼び出しを行う前に、Microsoft Game Development Kit (GDK) タイトルはネットワーク スタックの準備が完了していることを確認する必要があります。 タイトルの起動プロセス中に WSAStartup
が呼び出されるタイミングが早すぎる場合、WSAStartup
または後続の Winsock の呼び出しが失敗する可能性があります。 ネットワーク スタックの準備ができていることを確認する方法の詳細については、「ネットワークの初期化と接続」を参照してください。
一時停止と再開
RegisterAppStateChangeNotification
を使用して、一時停止および再開のイベントに登録する必要があります。 一時停止時、すべてのソケット ハンドルを閉じて、WSACleanup を呼び出す必要があります。 再開時、ネットワークの初期化を再度待ってから、WSAStartup を呼び出して新しいソケットを作成する必要があります。
Microsoft Game Development Kit (GDK) 優先ローカル ユーザー データグラム プロトコル (UDP) マルチプレイヤー ポート API
Microsoft Game Development Kit (GDK) の優先ローカル UDP マルチプレイヤー ポート API は、UDP を介したゲーム内通信を容易にするためにタイトルが Winsock を使用してバインド する必要がある、動的に選択された最適なポートを返します。 Microsoft Game Development Kit (GDK) プラットフォームは、この特定のポートが各ユーザーの特定のネットワーク環境に最も役立つと期待されるポートであることを確認します。 この特定のポートを使用すると、プラットフォームのカスタマー サポートと診断フローを最大限に利用して、標準化されたネットワーク アドレス変換 (NAT) の互換性を高め、標準化された UPnP™ 認定デバイス機能を提供し、サービス品質 (QoS) ルーターと ISP アルゴリズムに依存するリアルタイムのパケットを特定できます。
UDP ポートは、ピア ツー ピア ネットワーク トポロジに依存しているタイトルに特に適しています。 ファイアウォール パンチングを実行しないでファイアウォールを通過する受信 UDP パケットを許可する唯一のポートです。 Microsoft Game Development Kit (GDK) でピア ツー ピア ネットワーク トポロジに依存しているタイトルは、モデレイトまたはストリクト NAT タイプを持つクライアント用の NAT パンチング ソリューションと併せて、専用のパブリック IP アドレスとポート検出を提供することを期待されています。 優先ポートによって、これらのテクノロジの成功率は向上しますが、これらのテクノロジに代わるものではありません。
クライアント/サーバー ネットワーク トポロジを利用するタイトルでも、UDP ポートを使用する利点があります。 トラブルシューティング、UPnP™、およびパケットの識別は、現在も、病院、ホテル、大学の寮で共通するキャプティブ ポータルおよびその他のソース ベースのフィルタリング手法に適しています。
Microsoft Game Development Kit (GDK) タイトルでは、主要なマルチプレイヤーとチャット ネットワーク トラフィックで優先ローカル UDP マルチプレイヤー ポートを使用することを強くお勧めします。
ソケットのセキュリティ
Microsoft Game Development Kit (GDK) タイトルは、Winsock API を使用してネットワーク経由で転送されるすべてのデータに適切なセキュリティと暗号化が適用されていることを確認する必要があります。
BCrypt、WinCrypt、schannel などの標準の Windows API では、推奨される暗号化プリミティブが提供されています。 Microsoft Game Development Kit (GDK) タイトルはこれらの API を使用して、すべてのソケット フローに対してDatagram Transport Layer Security (DTLS) とその他の標準化されたセキュリティ プロトコルを実装する必要があります。
独自のセキュリティ モデルを実装しないタイトルの場合は、Microsoft Game Development Kit (GDK) ライブラリ PlayFab Party で他の機能と共に、統合された完全なソケットのセキュリティが提供されています。
ソケット メモリの考慮事項
Microsoft Game Development Kit (GDK) のタイトルでは、すべての WinSock および WinHTTP のネットワーク スタックに現在使用できるのは約 16MB のみです。この容量を超えると、システムの動作が不安定になる場合があります。 最も多くメモリを消費しているソースの 1 つは、WinSock カーネル モードの送受信メモリ プールです。そこでは、着信パケットと送信パケットは、多くの recv
亜種の 1 つを使用してワイヤーで送信またはタイトルのユーザー モード メモリに転送できるようになるまで保存されます。
特に高帯域幅の状況では、自分のユーザー モード バッファーに短い待機時間 (リモート ピアまたはサーバーがプッシュする速度と同等以上) でデータを転送する操作はタイトルで行う必要があります。 複雑度が増し、保証事項を増やしながらこれを実行する方法は複数ありますが、以下の推奨事項すべての基盤となる目標は、データが到着するとすぐに転送できるようにユーザー モード バッファーを常に保留状態にして、カーネルが増加するメモリ量を割り当てる必要をなくすことです。 正味の影響は、未処理データを保留するためのメモリを、極めて制限されたカーネル プールからはるかに大きいタイトル メモリ プール内で直接管理されているメモリに変更することです。
WinSock を消費する上位 API には、通常、ソケットのカーネル メモリ使用量を制御するメカニズムが用意されています。 WinHTTP と XCurl は両方とも、それぞれの読み取り通知メカニズムを使用してカーネル メモリ使用量を制御できます。一方、XSAPI や PlayFab Party などのその他の API は、以下の技術を使用してカーネル メモリ使用量を最小化します。
バークレー (BSD) ソケット
ブロッキング バークレー ソケット API を使用する場合、recv 呼び出しの頻度を増やす必要があります。 別の場所で処理するためにキューでデータを受信する、専用スレッドを小さいループで使用することをお勧めします。 理想的には、スレッドは、recv 呼び出しの内部で必ずブロックされます。recv 呼び出しの外部で消費される時間は、潜在的には、recv の再呼び出しを待機するとカーネル メモリ使用量が増える時間です。 多くの場合、recv を再呼び出しする前にデータを処理しようとすると、タイトルによる処理が遅れ、高い頻度でデータを受信し続ける限りカーネル メモリ使用量が増える可能性があります。 カーネル バッファー サイズ境界に合わせて 8k 以上のバッファー サイズを指定して、ジッターおよびバースト状態の送信パターンに対応することをお勧めします。
WinSock オーバーラップ I/O
WinSock のオーバーラップ I/O を使用すると、ユーザー モード受信バッファーを非同期的に保留状態に維持できます。 また、カーネルでメモリ バッファーを直接使用し、(バークレー ソケット パラダイムを使用した場合と異なり) メモリのコピーの追加を回避できます。また、バッファーが常に保留され、カーネルが受信バッファー用に全く割り当てないことを想定します。 また、オーバーラップ I/O を使用すると、SO_RCVBUF および SO_SNDBUF を、送信/受信カーネル メモリの割り当てをほぼ回避できる特別な値である 0 に設定できます。
この方法は、ほとんどすべてのシナリオで、ソケットが使用するメモリを管理する最適な方法です。
登録済み I/O
登録された I/O は複雑なネットワーク API であり、待機時間が最小になり、送受信操作に使用されるカーネル メモリが確実になくなります。 これにより、カーネルが使用する複数の受信/送信バッファーを直接設定して、着信データ用のバッファーを常に確保できます。
UDP 転送単位の最大サイズ
Microsoft Game Development Kit (GDK) には理論上の最大ペイロード サイズがありますが、実際には、特定の接続に対する最大値はネットワーク接続の種類によって異なります。 接続の種類はタイトルの実行中に変わる場合があります。 実際の最大転送単位 (MTU) を調べてタイトルの実行中に MTU の変化に対応しようと試みる代わりに、パケットごとの最大 UDP ペイロードとして 1,384 バイトを想定するようにネットワーク コードを設計してください。 この値は、転送での断片化を避けるためにすべてのネットワーク構成で使用しても安全です。 ソケットの種類が IPv4 か IPv6 かに関係なく、これをお勧めします。
多くの場合、1,384 バイトを超えるペイロードの転送には、IP レベルのパケット断片化が必要です。 IP パケット断片化は、ISP、ユーザーのホーム ルーター、デバイスでは十分にサポートされていません。 これらのネットワーク構成では、IP パケット断片化は Winsock API からのエラーを発生させません。 断片化は、タイトルにはパケット損失として認識されます。 IP レベルのパケット断片化を避けるために、1,384 バイトをパケット ペイロードに対する安全な最大値として使用してください。
タイトルで断片化を回避し、最小限のマルチプレイヤー ネットワーク要件に関する関連 Xbox 要件を満たすタイトルをサポートするには、タイトルが開くすべてのソケットに対してソケット オプション IP_DONTFRAGMENT
と IP_USER_MTU
を適用する必要があります。 これらのフラグは、 XGameRuntimeIsFeatureAvailable(XGameRuntimeFeature::XNetworking) API が を返 true
す場合にのみ、Microsoft Game Development Kit (GDK) タイトルで使用できます。
XNetworking
機能が使用できない場合、setsockopt
呼び出しは失敗します。 これら 2 つのソケット オプションを設定する方法の例を次に示します。
HRESULT
ApplyFragmentationSocketOptions(
SOCKET s
)
{
int value = 1;
int error = setsockopt(s, IPPROTO_IP, IP_DONTFRAGMENT, (char *)&value, sizeof(value));
if (error == SOCKET_ERROR)
{
return HRESULT_FROM_WIN32(WSAGetLastError());
}
value = 1384;
error = setsockopt(s, IPPROTO_IP, IP_USER_MTU, (char *)&value, sizeof(value));
if (error == SOCKET_ERROR)
{
return HRESULT_FROM_WIN32(WSAGetLastError());
}
return S_OK;
}