ReliableBroadcastProtocol は、ある程度大きなサイズのデータを複数台のステーションに送信するためのプロトコルです。到達保証があり、セッションホスト/セッションクライアントの種別に関係なく、任意のステーションがデータ送信側となることができます。
CTR のローカル通信、LAN 通信においては、ブロードキャスト送信を行いますので、複数台の相手に効率よくデータを送信することが可能です。
ReliableBroadcastProtocol を利用する場合の基本的な処理の流れは以下の通りです。
以下、各項目について解説します。
ReliableBroadcastProtocol の初期化処理のコーディング例を以下に示します。
static uint32_t s_Handle = 0; // ReliableBroadcastProtocol 用のハンドル
void initializeTransport() { // transport のセットアップ区間開始。 nn::pia::Result result = nn::pia::transport::BeginSetup(); PIA_ASSERT(result.IsSuccess()); // PiaTransport におけるのシングルトン作成などのコード ... ... nn::pia::transport::Transport* pTransport = nn::pia::transport::Transport::GetInstance(); PIA_ASSERT(PIA_IS_VALID_POINTER(pTransport)); // ReliableBroadcastProtocol の作成と初期化。BeginSetup() ~ EndSetup() 区間内で行います。 const uint16_t ReliableBroadcastProtocolPort = 0; // ReliableBroadcastProtocol が使用するポート番号。 s_Handle = pTransport->CreateProtocol<nn::pia::transport::ReliableBroadcastProtocol>(ReliableBroadcastProtocolPort); PIA_ASSERT(s_Handle != 0); // CreateProtocol()は、既に同じプロトコルIDが存在していた場合は0を返すので、そうではないことを確認 result = pTransport->GetProtocol<nn::pia::transport::ReliableBroadcastProtocol>(s_Handle)->Initialize(); PIA_ASSERT(result.IsSuccess()); // transport のセットアップ区間終了。 result = nn::pia::transport::EndSetup(); PIA_ASSERT(result.IsSuccess()); } |
送信するデータはあらかじめアプリケーションが作成しておき、サイズを確定させておく必要があります。ストリーミング送信には対応していません。
送信側は、送信データとそのサイズ、転送における振る舞いを StartSend() に渡して呼び出します。転送における振る舞いは、Configuration クラスのインスタンスで設定します。設定可能な振る舞いは以下の通りですが、詳細は API リファレンスを参照してください。
StartSend() 呼び出しにより、送信側は他のステーションに向けて受信要求を送出します。
// ReliableBroadcastProtocol のポインタを得る関数
nn::pia::transport::ReliableBroadcastProtocol* GetReliableBroadcastProtocol() { PIA_ASSERT(PIA_IS_VALID_POINTER(nn::pia::transport::Transport::GetInstance())); return nn::pia::transport::Transport::GetInstance()->GetProtocol<nn::pia::transport::ReliableBroadcastProtocol>(s_Handle); } const uint32_t SendDataSize = 8 * 1024 * 1024; // 送信データサイズ static uint32_t s_SendData[SendDataSize/sizeof(uint32_t)]; // 送信データの実体 static nn::pia::transport::ReliableBroadcastProtocol::Configuration s_SendConfig; // データ転送の動作方式 void prepareSend() { // データ送信の準備 nn::pia::transport::ReliableBroadcastProtocol* pProtocol = GetReliableBroadcastProtocol(); nn::pia::Result result = pProtocol->StartSend(s_SendData, sizeof(s_SendData), s_SendConfig); if (result.IsFailure()) { if (result == nn::pia::ResultTemporaryUnavailable()) { // セッション移行処理中のため、一時的に API を利用できない状態です。ジョイントセッション機能使用時にのみ返ります。 } else { PIA_TRACE_RESULT_ALWAYS(result); PIA_ASSERTMSG(false, "Programming error."); } } } |
送信側の StartSend() 呼び出しにより、セッション参加中のステーション(送信側以外)に受信要求が届きます。この受信要求の有無は GetRequest() で判定できます。受信要求が届いていなければ GetRequest() は NULL を返します。
StartReceive() 呼び出しにより、送信側から届いた受信要求を受諾し、データの送受信が開始されます。
const uint32_t ReceiveBufferSize = 8 * 1024 * 1024; // 受信バッファサイズ
static uint32_t s_ReceiveBuffer[ReceiveBufferSize/sizeof(uint32_t)]; // 受信バッファの実体 void startReceive() { // 受信要求が届いていたら、データ受信開始。 nn::pia::transport::ReliableBroadcastProtocol* pProtocol = GetReliableBroadcastProtocol(); const nn::pia::transport::ReliableBroadcastProtocol::TransferSetting* cpRequest = pProtocol->GetRequest(); if (cpRequest != NULL) { nn::pia::StationId srcId = cpRequest->GetSourceStationId(); PIA_ASSERT(srcId != nn::pia::StationIdInvalid); nn::pia::Result result = pProtocol->StartReceive(s_ReceiveBuffer, sizeof(s_ReceiveBuffer), srcId); if (result.IsFailure()) { if (result == nn::pia::ResultTemporaryUnavailable()) { // セッション移行処理中のため、一時的に API を利用できない状態です。ジョイントセッション機能使用時にのみ返ります。 } else { PIA_TRACE_RESULT_ALWAYS(result); PIA_ASSERTMSG(false, "Programming error."); } } } } |
受信の終了判定には GetState() が利用できます。受信側がデータを全て受信すると、GetState() は State_ReceiveSuccess を返すようになります。
一方、送信側による GetState() の返り値は Configuration::IsSendEndless() の設定に左右されます。詳細は API リファレンスを参照してください。
ReliableBroadcastProtocol の終了処理例を以下のコードで示します。
void finalizeTransport()
{ nn::pia::transport::Transport* pTransport = nn::pia::transport::Transport::GetInstance(); PIA_ASSERT(PIA_IS_VALID_POINTER(pTransport)); // ReliableBroadcastProtocol の終了処理 nn::pia::transport::ReliableBroadcastProtocol* pProtocol = pTransport->GetProtocol<nn::pia::transport::ReliableBroadcastProtocol>(s_Handle); if (PIA_IS_VALID_POINTER(pProtocol)) { pProtocol->Finalize(); pTransport->DestroyProtocol(s_Handle); s_Handle = 0; } } |
上記は基本的な操作です。以下、応用的な操作について解説します。
アプリケーションの仕様により、送信側/受信側が事前に確定している場合は、送信側が StartSend() を呼び出す前に受信側が StartReceive() を呼び出すことも可能です。StartReceive() を先に呼び出しておくと、データの取りこぼしを少しだけ減らせるので、送受信の時間を若干短縮できます。
前述の通り、受信要求は GetRequest() で取得できますが、この受信要求を拒絶することもできます。受信要求の拒絶には、RejectRequest() を使用します。
void rejectRequest()
{ nn::pia::transport::ReliableBroadcastProtocol* pProtocol = GetReliableBroadcastProtocol(); nn::pia::Result result = pProtocol->RejectRequest(); PIA_ASSERT(result.IsSuccess()); } |
送受信を途中でキャンセルするには、Cancel() を呼び出します。
void cancel()
{ nn::pia::transport::ReliableBroadcastProtocol* pProtocol = GetReliableBroadcastProtocol(); enum nn::pia::transport::ReliableBroadcastProtocol::State state = pProtocol->GetState(); if(state == nn::pia::transport::ReliableBroadcastProtocol::State_Sending || state == nn::pia::transport::ReliableBroadcastProtocol::State_Receiving) { // 送受信を中断します。 nn::pia::Result result = pProtocol->Cancel(); PIA_ASSERT(result.IsSuccess()); } } |
送受信の進捗状況は GetProgress() で確認できますが、GetProgress() が返す値の意味は受信側と送信側で異なることに注意してください。
受信側が呼び出した GetProgress() は単に受信したデータサイズを返しますが、送信側が呼び出した GetProgress() は、送信対象のステーションに対して送信したデータサイズの平均値が返されます。
void printProgress()
{ nn::pia::transport::ReliableBroadcastProtocol* pProtocol = GetReliableBroadcastProtocol(); const nn::pia::transport::ReliableBroadcastProtocol::TransferSetting* cpSetting = pProtocol->GetCurrentTransferSetting(); if (cpSetting != NULL) { // 受信側の進捗をプリントします。 uint32_t total = cpSetting->m_DataSize; uint32_t current = pProtocol->GetProgress(); float rate = static_cast<float>(current) / static_cast<float>(total); PIA_BASIC_REPORT("%7dB / %7dB (%5.1f%%)", current, total, rate * 100.0f); } } |
送受信結果の情報を破棄し、State_Wait 状態に戻るときには Reset() を呼び出します。ただし、送受信実行中に Reset() を呼び出すことはできません。詳細は API リファレンスを参照してください。
void reset()
{ nn::pia::transport::ReliableBroadcastProtocol* pProtocol = GetReliableBroadcastProtocol(); PIA_ASSERT(pProtocol->IsRunning() == false); nn::pia::Result result = pProtocol->Reset(); PIA_ASSERT(result.IsSuccess()); } |