# p2p\_rudp\_sample

## p2p\_rudp サンプル

### 概要

Room モジュールを使用してユーザー同士が P2P 接続し、RUDP (Reliable UDP) を使用して P2P 通信を行うサンプルです。 Room モジュールの特徴については[こちらのページ](/diarkis-modules/room.md)を参照してください。

### ローカル環境でサーバーを起動する

サンプルで使用するサーバーを起動するためのチュートリアルを実施して、ローカル環境で Diarkis サーバーを起動します。

[1. Diarkis サーバーをローカル環境で起動する](/getting-started/tutorial/setup-local-server.md)

### サンプルの引数

サンプルの起動時には以下の３つのパラメータを指定してください。

`p2p_rudp_sample.exe serverAddr UID clientKey`

| 引数         | 説明                            |
| ---------- | ----------------------------- |
| serverAddr | Diarkis サーバのエンドポイントを指定してください  |
| UID        | 接続するユーザーの ID を任意の文字列で指定してください |
| clientKey  | クライアントキーを任意の文字列で指定してください      |

#### 起動例：

`p2p_rudp_sample.exe 192.168.1.123:7000 1111 AAAA`

### 起動方法

本サンプルは起動すると Room に接続し、Room のメンバー数が 2 人になるまで待機します。 サンプルプログラムを 2 つ起動することで 2 人のユーザーが Room に参加し P2P 接続の処理が開始します。

### サンプルコード説明

#### Room の P2P を使用する全体的な流れ

1. Diarkis ランタイムおよび Diarkis Module を初期化し、Diarkis サーバーへ接続します。\
   詳細については [Diarkis モジュール利用の全体的な流れ](https://help.diarkis.io/diarkis-client/samples/cpp/pages/r3yF3oFZnxAPw2prL13v#diarkis-モジュール利用の全体的な流れ) を参照してください。
2. セットアップ\
   Room と P2P モジュールを初期化します。

   ```
   diarkis = Diarkis::DiarkisAllocShared<DiarkisInterface>(uid);
   ...
   // Diarkis Module の Room のセットアップ
   diarkis->SetupRoom();
   // Diarkis Module の P2P のセットアップ
   diarkis->SetupP2P();
   ...
   ```
3. Room へ接続\
   `DiarkisRoomBase::SendCreateOrJoinByCustomID` を使用して Room に接続します。Room に接続することが目的のため `DiarkisRoomBase::SendJoinRandomRoom` 等、他の接続用の API を使用しても問題ありません。

   ```
   auto roomBase = diarkis->GetRoomBase();
   roomBase->SendCreateOrJoinByCustomID("sample_room", 4, 200, uid.c_str(), false);
   ...
   ```
4. P2P 接続を開始\
   Room に接続後、`DiarkisRoomBase::SendStartP2PSync` を実行することで P2P 接続を開始します。この API は Room に接続しているメンバーの中で誰か 1 人が実行すれば他のユーザー含めて全員の P2P 接続処理が開始します。本サンプルでは Room のオーナーとなっているユーザーが代表してこの API を実行しています。

   ```
   // Start P2P
   if (uid == ownerUid)
   {
       roomBase->SendStartP2PSync();
   }
   ```
5. P2P 接続完了待ち\
   本サンプルでは全ユーザーの P2P 接続が完了するまで待機します。 `DiarkisP2PBase::GetConnectedUsers` で P2P 接続が完了しているユーザー数をチェックすることができるため、この人数が想定している人数になるまで待機しています。 `DiarkisP2PBase::GetConnectedUsers` は接続しているピアの数となるため参加人数 - 1 でチェックしています。

   ```
   Diarkis::StdVector<Diarkis::StdString> peerUids = p2pBase->GetConnectedUsers();
   while (peerUids.size() < numClients - 1)
   {
       std::this_thread::sleep_for(std::chrono::milliseconds(30));
       peerUids = p2pBase->GetConnectedUsers();
   }
   ...
   ```
6. P2P で RUDP メッセージを送信\
   P2P での接続完了後、`DiarkisP2PBase::SendBroadcast` を使用して P2P 接続している全ユーザーに対してメッセージを送信しています。 この時 Reliablity に `Reliability::RELIABLE_ORDERED` や `Reliability::RELIABLE_UNORDERED` を指定すると RUDP としてメッセージを送信します。 `Reliability::RELIABLE_ORDERED` では到達保証・順番保証となり `Reliability::RELIABLE_UNORDERED` では到達保証のみとなります。\
   また、RUDP では MTU を超える大きなサイズのパケットも送信することができます。簡単に大量のデータを送ることが出来てしまいますので、ネットワーク負荷を考慮してご使用ください。

   ```
   if (num % 10 == 0)
   {
       reliability = Reliability::RELIABLE_ORDERED;
   }

   // RUDP で大きいサイズ (2000 byte) のメッセージを送信
   if (num % 100 == 0)
   {
       reliability = Reliability::RELIABLE_UNORDERED;
       sendSize = PayloadSize;
   }

   p2pBase->SendBroadcast(buff.data(), sendSize, reliability);
   ...
   ```
7. P2P でメッセージを受信\
   P2P でメッセージを受信すると `DiarkisP2PBase::OnP2PMessage` が発火します。 `DiarkisP2PBase::OnP2PMessage` の引数の `DiarkisMessageEventArgs` では送信元 UID やペイロードなど様々な情報を取得することができます。 ユーザーは `DiarkisP2PBase` を継承し `DiarkisP2PBase::OnP2PMessage` をオーバーライドすることで受信したデータに対してアプリ固有の処理を実装することができます。

   ```
   void DiarkisP2PBase::OnP2PMessage(const DiarkisMessageEventArgs& args)
   {
       ...
   ```
8. 切断処理 `DiarkisP2PBase::Disconnect` を使用して P2P 接続を切断します。このとき、Room に接続したままであれば Room 経由で通信を行うことが可能です。

   ```
   p2pBase->Disconnect();
   ```
9. 終了処理\
   詳細については [Diarkis モジュール利用の全体的な流れ](https://help.diarkis.io/diarkis-client/samples/cpp/pages/r3yF3oFZnxAPw2prL13v#diarkis-モジュール利用の全体的な流れ) を参照してください。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://help.diarkis.io/diarkis-client/samples/cpp/p2p-rudp-sample.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
