6. セッション・ステーション

ステーションのひとつのグループを P2P セッションといい、以後、単にセッションと言った場合には、 P2P セッションを指します。 セッションの管理者のことを、セッションマスターといい、 P2P 通信の責任者であるホストと一致した端末となります。 セッションに参加している各端末をステーションと呼び、自端末のことをローカルステーションと呼びます。

インターネット通信時には、NetZ初期化前に P2P 通信で使用するポートの自動選択処理や NAT トラバーサル機能の初期化が必要です。 詳細は、 4. を参照してください。

6.1. セッション管理

6.1.1. セッションマスターの役割

セッションマスターは、セッション全体の情報を管理して、セッションへの参加受付や、セッション内で 同期が取られているセッションクロックの管理、セッション内で共有のDOの作成を行います。 セッションマスターであるか否かは、 Session::GetRole()で取得可能です。

最初のセッションマスターは、 Session::CreateSession()によりセッションを作成したステーションです。 このステーションがセッションを離れると、ステーションのリストで二番目のステーションを新しいセッションマスターとして選びます。

セッションマスターは、セッションの情報を管理し、変更ができます。 ローカルステーションのセッション情報は、Session::GetLocalSessionDescription()で取得できます。 セッションの情報は、 SessionDescriptionクラスで管理され、アプリケーションタイトル、セッション名、セッション ID、 ユーザー定義属性、セッションのライブラリバージョンとビルド番号などが含まれます。

6.1.2. セッションの作成

セッションは、 Session::CreateSession() を使用してセッションマスターによって作成されます。

セッションのステータスは、Session クラスを使用して制御されます。 このクラスはシングルトンなので、アクセスのグローバルポイントがあるインスタンスを 1 つのみ持ちます。 つまり、各NetZ インスタンスに 1 つの Session のみが作成されます。 Session クラスの主な機能は、セッションを作成可能および参加可能にし、セッションに関する特定の情報が設定され、検索されるようにすることです。 ステーションがセッションの一部になると、そのステーションに関する特定の情報が Station クラスを使用して検索できます。

ローカル通信のセッションを作る際、UDSネットワークのマスターが Session::CreateSession()を呼び出す必要があります。

6.1.3. セッションへの参加

すでに存在するセッションに参加するには、次の構文のいずれかを使用して Session::JoinSession()を呼び出します。

Code 6.1 セッションへの参加
qBool Session::JoinSession(CallContext* pCallContext,
                           const StationURL& refStationURL); //ローカル通信用 非同期
qBool Session::JoinSession(const StationURL& refStationURL); //ローカル通信用 同期

qBool Session::JoinSession(CallContext* pCallContext,
                           const qList< StationURL > & lstURLs); //インターネット通信用 非同期
qBool Session::JoinSession(const qList< StationURL > & lstURLs); //インターネット通信用 同期

上記、refStationURL や、 lstURLs は、 nn::pia::local::UdsNetwork::GetMasterUrl()や MatchMakingClient::GetSessionURLs()で取得できるセッションの参加に使用するステーションの URL への参照です。 URLリストには参加先のグローバルIPやローカルIP情報が含まれているので、一つのみ取り出しても正しく動作できません。 ローカル通信用のメソッドを、インターネット通信時に利用すると、Assertによる強制終了もしくは、Joinに失敗します。

pCallContext は、呼び出しの CallContext へのポインタです。 定義されている場合、呼び出しは非同期的に行われます。 定義されていない場合は同期的に行われます。 呼び出しが同期である場合、システムは呼び出しが値またはエラーを返すまで、次のタスクの実行を待機します。 非同期の場合、呼び出しが完了するのを待機する間に他のタスクを実行できます。

Session::JoinSession()が終了する前に、すべての WellKnownDO とすべての IDGenerator コアオブジェクトが検出され、 これらのオブジェクトが UserDO の前に検出されることが保証されています。 また、 Session::JoinSession()内では UserDO が検出されないことが保証されています。 Session::JoinSession() を呼び出した後で Scheduler::Dispatch() を呼び出す場合にのみ最初の UserDO が検出されます。

NetZ のスレッドモデルの詳細については、 スレッドモードの設定 を参照してください。

6.1.4. セッションの離脱

Session オブジェクトを削除する唯一の方法は NetZ インスタンスを削除することです。 そのため、セッションから離脱するには、NetZ インスタンスを削除する必要があります。

NetZ インスタンスが破棄されると、ローカルステーションに存在するセッションを含めたすべての DO が削除されます。

6.1.5. LAN中セッションの検索と参加[デバッグ用]

P2P セッションを LAN で参加できるようにするため、NetZ には LANSessionDiscovery クラスが用意されています。 LANSessionDiscovery クラスを用いると同一 LAN に存在する P2P セッションを探すことができます。 このクラスはセッションマスターとなっている端末と同一の LAN で動作している端末でのみ利用可能です。 デバッグ用途以外での利用はできず、ローカル通信利用時には設定不要です。 LANSessionDiscovery::Enable()とすると、LAN上に作られた他のセッションを Session::QuerySessions()で参照できるようになります。

Session::QuerySessions()は Session::CreateSession()するか、Session::JoinSession()する前に呼び出される必要があります。

例えば、LANの P2P セッションを検索し、セッションの記述からのさまざまな情報を出力するには、次の通りです。

Code 6.2 LANの P2P セッション検索
LANSessionDiscovery::Enable();

.....

std::list<SessionDescription> lstResult;
if (Session::QuerySessions(&lstResult,false)==0)
{
    QLOG(EventLog::Error, NEX_T("No session found."));
}
else
{
    std::list<SessionDescription>::iterator it=lstResult.begin();
    while (it!=lstResult.end())
    {
        // Display relevant information from SessionDescription
        QLOG(EventLog::Info, NEX_T("Session ID    : ") << it->GetSessionID());
    }
}

また、LANの P2P セッションを検索して、リストで一番最初のセッションに参加するコードは以下の通りです。

Code 6.3 LANの P2P セッション検索・参加
LANSessionDiscovery::Enable();

.....

std::list<SessionDescription> lstResult;
if ( Session::QuerySessions(&lstResult,false) == 0 )
{
    QLOG(EventLog::Error, NEX_T("No session found."));
}
else
{
    if (! Session::JoinSession(&lstResult.begin()) )
    {
        QLOG(EventLog::Error, NEX_T("Join Failed."));
    }
}

6.2. ステーション

ステーションは、セッションが存在する限り存在するローカルステーションと、検出時に生成されて離脱時に削除されるピア(対向)ステーションの二つに分かれます。 それぞれ、固有のStationオブジェクトが生成されます。

Stationオブジェクトには、ステーション状態、 DOHandle、セッション内で固有のグローバルステーション識別子である StationIDなどが含まれます。 Stationオブジェクトが、ローカルステーションかピアステーションかを、Station::IsLocal() と Station::IsAPeer() を使用して調べることができます。 また、別のステーションと通信ができるかをStation::IsConnected()を使用して調べることができます。

6.2.1. ステーションの状態遷移

ステーションの現在の状態は Station::GetState() で取得でき、 Station::UnknownStation::JoiningSessionStation::CreatingSessionStation::ParticipatingStation::LeavingStation::LeavingOnFault のいずれかで、 Figure 6.1 に示すように遷移します。

../_images/Fig_Station_StateChart.png

Figure 6.1 ステーションの状態遷移

6.2.2. ステーションのセッション入退出検知

以下の関数を使ってステーションの参加・離脱タイミングを知ることができます。

Table 6.1 ステーションのセッション入退出ハンドリングに使用するAPI
API 内容
Station::RegisterOperationBeginCallback() ステーションの参加、離脱の処理開始時に呼ばれるコールバックを設定します
Station::RegisterOperationEndCallback() ステーションの参加、離脱の処理処理完了時に呼ばれるコールバックを設定します

主な使用用途を以下に説明します。

サンプルコードについては AutoMatchサンプル を参照してください。

6.2.3. ステーションの消失検知

NEXは、ネットワークの障害や対向ステーションの電源OFFや無線LANのOFFなど、正常ではないステーションの消失を検知するためにキープアライブパケットによる ステーションの生存監視を行います。

生存監視の動作は以下の通りです。

  • StreamSettings::GetKeepAliveTimeout() で取得できる時間(デフォルト値は1000msec) 連続して通常のパケットの送信がなかったステーションに対して、キープアライブパケットを StreamSettings::GetKeepAliveTimeout()の間隔で送信します。
  • キープアライブパケットを受け取ったステーションは、キープアライブパケットの応答を送り返します。
  • StreamSettings::GetMaxSilenceTime() で取得できる時間(デフォルト値は10,000msec)連続して一切のパケット受信がないステーションを、もはや接続していないと判断します。

ステーションの消失を検出した場合、 Station::RegisterOperationBeginCallback()で登録したコールバックで状態変化を検出でき、 消失したステーションの Station::GetState()が Station::LeavingOnFaultとなります。

6.2.4. ステーションのプロトコル情報

NEXのプロトコルの統計情報は、Station::GetEndPointInfoInterface()で、統計操作オブジェクトを取得できます。 通信開始後、もしくは、 EndPointInfoInterface::ResetEndPointInfo() 実行後から統計情報を、 EndPointInfoInterface::GetEndPointInfo() で取得できます。取得できる情報は、 EndPointInfo構造体を参照してください。 これら統計は、BundlingPolicy クラスによるDOのメッセージバンドリング後、StreamBundling クラスの設定によるパケットバンドリング前の統計情報です。 実際に出力されるデータは、パケットバンドリングによりまとめられる可能性があります。

リライアブル通信の送信用バッファのパケット数は、 EndPointInfoInterface::GetReliableBufferPacketCount()、 EndPointInfoInterface::GetReliableBufferPacketCounts() で取得できます。

RTTについては、Station::GetRTT() と Station::GetRTTAverage() により特定のメッセージの往復遅延時間と、 ローカルステーションと別のステーション間で送信されたメッセージの平均往復遅延時間を直接取得することができます。

6.2.5. ステーションのバージョン、ユーザー定義情報

Station::SetLocalApplicationVersion()により、アプリケーションのバージョンを設定可能です。 ここで設定された値は、Station::GetApplicationVersion()で取得できます。

また、Station::SetLocalIdentificationToken() を使用してユーザー定義の文字列を特定のステーションに関連付けることができます。 識別トークンを使用する方法の 1 つは、ステーションがセッションに参加しようとする際にステーションにセッション参加の権限があるかどうかを判断するため、 パスワードまたはその他の識別タグを渡すことです。 この場合、情報は接続先のステーションに渡されるため、そのステーションが参加リクエストに関する決定を下すことができます。 識別トークンは参加するステーションオブジェクトに設定され、その後 Station::GetIdentificationToken() でアクセスできます。 識別トークンの使用方法の例については、 14. を参照してください。