4. インターネットP2P 通信
インターネット P2P 通信における初期化・セッションの管理・終了処理について解説します。
4.1. 初期化・終了処理
インターネット P2P 通信を開始するためには、ConnectivityManager::StartNATSession() を使用して P2P 通信で使用するポートの自動選択や NAT トラバーサル機能の初期化を行った後、 P2P 通信を管理する NetZ クラスオブジェクトを生成します( Code 4.1 )。
NAT トラバーサル機能については 21. もご覧ください。
NetZ クラスオブジェクト作成後は必要に応じて P2P 通信の設定を行います。以下の設定が必須となります。
- Network::SetP2PDataPacketSessionSignatureKey() を使用してマッチメイクセッション参加者全員に共有されている P2P 通信用の鍵を設定する
void InitializeNetZ(const qVector<qByte>& sessionKey)
{
if (pNetZ)
{
return;
}
CallContext oContext;
ConnectivityManager::GetInstance()->StartNATSession(&oContext);
oContext.Wait();
if(!oContext.GetOutcome())
{
return;
}
NetZ pNetZ = qNew NetZ();
// 必要に応じて P2P 通信用の設定を行う
Station::SetLocalPlayerName(NEX_T("PLAYER NAME"), 0);
Network::GetInstance()->SetP2PDataPacketSessionSignatureKey(sessionKey);
}
StartNATSession()では、NAT種別判定サーバーのアドレス名を解決します。名前解決前にルータのWAN側のケーブルを抜いたときなどには、アドレス解決処理のタイムアウトを待つのに 最大30秒かかるため、非同期で呼び出しを推奨します。 また、名前解決はキャンセルできないため、StartNATSession()後、アドレス解決が完了していない状態でNEXを終了させようとすると、最大30秒かかります。
P2P 通信を終了するときは、NetZ::Terminate() でセッションを終了した後、NetZ クラスオブジェクトを破棄します。 その後、ConnectivityManager::StopNATSession() でポートの開放処理を行います。 セッションを終了する前にNetZ クラスオブジェクトを破棄しようとすると、 内部で NetZ::Terminate() が完了するまでブロックします( Code 4.2 )。
void FinalizeNetZ(NetZ pNetZ)
{
if (!pNetZ)
{
return;
}
// Terminateしないと NetZ オブジェクトの Delete 時にTerminate するまでブロックする。
CallContext oContext;
pNetZ->Terminate(&oContext);
oContext.Wait();
qDelete pNetZ;
ConnectivityManager::GetInstance()->StopNATSession();
}
4.2. P2P セッションを作成する
マッチメイクセッションのホストは P2P セッションを作成する必要があります。 P2P セッションを作成するには、Session::CreateSession() を使用します。 この関数の引数には、セッションの名前を渡すことができます(オプション)。 第 2 引数はデフォルトの true を指定してください。
static qBool CreateSession(const qChar *szSessionName=NULL,
qBool bNetworked=true);
4.3. P2P セッションに参加する
マッチメイクセッションのホストの URL をMatchMakingClient::GetSessionURLs() で取得し、 Session::JoinSession() で P2P セッションに参加します。 P2P セッションへの参加に失敗した場合はマッチメイクセッションから退出してください。
// P2P セッション に参加する
qBool JoinMachmakeSession(
NetZ* pNetZ,
MatchmakeExtensionClient *pMatchMakingClient,
GatheringID sessionGid)
{
qList<StationURL> lstURLs;
ProtocolCallContext oContext;
// ホストのURLを取得
if (!pMatchMakingClient->GetSessionURLs(&oContext, sessionGid, &lstURLs))
{
return false;
}
oContext.Wait();
// 1つ以上のURLが格納されていることを確認
if(!oContext.GetOutcome() || lstURLs.empty())
{
return false;
}
if(!pNetZ->JoinSession(&oContext, lstURLs))
{
return false;
}
oContext.Wait();
return oContext.GetOutcome();
}
注意
MatchMakingClient::GetSessionURLs() で取得されるリスト中のURLはすべて必要です。加工せずにそのまま、 Session::JoinSession()に渡すようにしてください。
4.4. ホストマイグレーション拡張機能を利用する
現在の P2P 通信のホストが P2P セッションを去ると、NetZ は自動的にホストを別の参加者へ移します。 また、マッチメイクセッションには P2P 通信のホスト情報が記録されており、ホストがマッチメイクセッションを抜けるとその情報がクリアされます。 ホスト情報は P2P セッションへの参加時に必要となるため、適切に更新される必要があります。 ホストマイグレーション拡張機能を利用すると、 P2P セッションのホストが移行したときに、 その旨をゲームサーバーに通知して、マッチメイクセッションの P2P 通信のホスト情報を更新します。 ホストマイグレーション拡張機能を使用している場合、セッションホストが移行されると、該当するマッチメイクセッションについて、 適切な MatchMakingClient::UpdateSessionHost() の呼び出しが行われます。ホストマイグレーション拡張機能の利用手順は以下の通りです。
- #use <NetZ/src/Core/HostMigration/HostMigrationExt.ddl> をDDL に書く。
- NetZオブジェクト生成後にHostMigrationExtension::Register() を実行
- 生成したMatchmakeExtensionClientと、ホストマイグレーションが発生したときに呼ばれるコールバック関数(通常、MatchmakingClient::StaticUpdateSessionHost() もしくは MatchmakingClient::StaticUpdateSessionHostWithOwner())を使って HostMigrationCallback を生成。
- HostMigrationCallback::Register() で参加したギャザリング ID を登録
マッチメイクセッション登録からホストマイグレーションまでの一連の流れは Figure 4.1 を参照してください。 正常状態で P2P セッションを終了した場合は、すみやかにマッチメイクセッションから退出してください
ホスト以外のクライアントが P2P セッションから孤立した場合は、自分以外の最低一つのクライアントからの承認でホストマイグレーションは発生します。 ただし、セッション内に 2人しかプレーヤーがおらず、タイムアウトなどが発生しお互いのステーションを異常状態で見失った場合は、 そのクライアント自身がホストに昇格すべきかが分からないため、MatchMakingClient::UpdateSessionHost() の呼び出しが発生しません。 この状態を孤立といい、 HostMigrationCallback::SessionHostIsOrphan() で判定できます。 孤立していると判定された場合は参加しているマッチメイクセッションから退出してください。 セッション内に 2人しかプレーヤーがいない状態でひとつの端末が正常に抜けた( NetZ::SetTerminateImmediately() を指定しないで NetZ::Terminate() で抜けた)場合には、孤立状態と判断されません。ホストが抜けた場合は、ホストマイグレーションが発生します。
孤立状態に陥った場合でもホストマイグレーションは発生しているため、 ゲームを継続することは可能ですが、外部から参加可能なホストが存在するマッチメイクセッションが存在しないために他のクライアントが P2P セッションへ参加できません。 他のクライアントが参加できるようにするには、新しくマッチメイクセッションを登録してください。 また、HostMigrationCallback のオブジェクトを破棄し、新しいHostMigrationCallbackオブジェクトを生成して新しいIDを登録する必要があります。
補足
ホスト移行時に新しいホストをゲームサーバーに通知しなかった場合、 MatchMakingClient::GetSessionURLs () で取得される URL は移行前のホストの URL になります。 したがってホストが退出した後であっても、他のクライアントが P2P セッションへ参加できるようにするためには、 ホストマイグレーション拡張機能を利用する必要があります。
補足
同一の ROM でインターネット通信モードとローカル通信モードを使用し、 かつインターネット通信モードでホストマイグレーション拡張機能を使用する場合は、 ローカル通信モードにて HostMigrationExtension::Disable() を呼び出すことで、 HostMigrationExtension::Register()の呼び出しを省略することができます。

Figure 4.1 マッチメイクセッション登録からホストマイグレーションまでの流れ