サーバー用の高度な NAT テクニック
サーバー用の高度な NAT テクニック
Microsoft® DirectPlay® は、ユニバーサル プラグ アンド プレイ (UPnP) をサポートしないネットワークアドレス変換 (NAT) デバイスの対象であるホストに対しては、100 パーセントの接続性を提供しない。しかし、アプリケーションでより複雑な手法を使うことで、このような状況でのサポートを向上できる可能性がある。ここで説明するテクニックには、より多くの開発作業と、外部サーバー リソースが必要になる。
NAT リゾルバ
NAT デバイスは、内部のコンピュータが外部のコンピュータにパケットを送信するときに、明示しないポート マッピングを作成する。NAT デバイスによっては、元の外部ターゲットが送信した応答を単に転送する代わりに、このポート マッピングを使った内部のコンピュータへの送信を、外部のコンピュータに対して許可するものがある。このような NAT は、"loose NAT" と呼ばれることがある。DirectPlay は、IDirectPlay8NATResolver インターフェイスとアドレス コンポーネントを使ってこの動作を活用し、これらのデバイスの対象でホスティングを実行できる。
最初に、インターネットからアクセス可能な IDirectPlay8NATResolver サーバーを実装しなければならない。次に、ゲーム アプリケーションは、IDirectPlay8Server::Host に渡すデバイス アドレスに、DPNA_KEY_NAT_RESOLVER コンポーネントを追加できる。このコンポーネント データは、インターネット プロトコル (IP) アドレスと、使用する NAT リゾルバのポートをコロンで区切った文字列である。たとえば、次のコードは、アドレス 123.123.123.123 のポート 5678 にあるサーバーを使うことを指定する。
WCHAR * wszNATResolver = L"123.123.123.123:5678";
DWORD dwNATResolverSize = (wcslen(wszNATResolver) + 1) * sizeof(WCHAR);
hr = pDP8DeviceAddress->AddComponent(DPNA_KEY_NAT_RESOLVER,
wszNATResolver,
dwNATResolverSize,
DPNA_DATATYPE_STRING);
また、次の例のように、数値の IP アドレスの代わりにホスト名を指定することもできる。
WCHAR * wszNATResolver = L"resolver.mydomain.com:5678";
DWORD dwNATResolverSize = (wcslen(wszNATResolver) + 1) * sizeof(WCHAR);
hr = pDP8DeviceAddress->AddComponent(DPNA_KEY_NAT_RESOLVER,
wszNATResolver,
dwNATResolverSize,
DPNA_DATATYPE_STRING);
信頼性を高めるために、複数の解決サーバーを試すことを勧める。次の例に示すように、複数のアドレスをコンマで区切って指定できる。
WCHAR * wszNATResolvers = L"123.123.123.123:5678,backupresolver.mydomain.com:6789";
DWORD dwNATResolverSize = (wcslen(wszNATResolvers) + 1) * sizeof(WCHAR);
hr = pDP8DeviceAddress->AddComponent(DPNA_KEY_NAT_RESOLVER,
wszNATResolvers,
dwNATResolverSize,
DPNA_DATATYPE_STRING);
各リゾルバの速度が同時にテストされ、最初の応答が使われる。サーバーが応答しない場合でも、IDirectPlay8Server::Host 呼び出しは成功する。
これらの解決サーバーをホストとするにはリソースが必要なため、任意のプレーヤがリゾルバを使わないように設定できる。そのためには、DPNA_KEY_NAT_RESOLVER_USER_STRING アドレス コンポーネントを使う。この値は、DPN_MSGID_NAT_RESOLVER_QUERY メッセージでの確認のためにリゾルバに直接渡され、必要に応じて応答または無視する選択ができる。次のサンプル コードは、この設定方法を示している。
WCHAR * wszPassword = L"MyPassword";
DWORD dwPasswordSize = (wcslen(wszPassword) + 1) * sizeof(WCHAR);
hr = pDP8DeviceAddress->AddComponent(DPNA_KEY_NAT_RESOLVER_USER_STRING,
wszPassword,
dwPasswordSize,
DPNA_DATATYPE_STRING);
注 ユーザー文字列はネットワークを介してクリア テキストで渡される。したがって、テキストに重要情報が含まれている可能性がある場合、何らかの形式で暗号化すること。
ホストの NAT デバイスが、NAT リゾルバ クエリーのポート マッピングを生成する。NAT リゾルバがクエリーに応答することを選択した場合、DirectPlay はそのマッピングのパブリック アドレスを元のホストに送信する。次に、ホストは、IDirectPlay8Server::GetLocalHostAddresses メソッドが返すアドレスにそのアドレスを含める。
外部のクライアントは、内部ホストに接続するときにこのマッピング アドレスを使う。しかし、マッピングがアクティブでない場合、NAT デバイスによってそのマッピングの有効期限が切れ、外部クライアントはマッピングを使えなくなる。実際に有効期限が切れるまでの時間は、NAT デバイスによって異なる。通常、外部ピア クライアントは、IDirectPlay8Server::Host 呼び出しの完了後 30 秒以内に接続を開始することが予期されている。
NAT リゾルバ アドレス コンポーネントの使用例は、NATPeer サンプルで説明している。