2015-09-04 unity > udpMonitor > UDPのrelay機能の実装 / 通信内容export機能付き

```txt:実装
Unity 5.1.2-f1 on MacOS X 10.8.5
```

二台の端末があり、ポート6000でUDP通信をしているとする。

- 192.168.10.5
  - 文字列を送信して応答を受信する
- 192.168.10.6
  - echo serverが起動している

その間に(192.168.10.3として)入って、通信をリレーする処理を実装してみた。

[v0.3 @ github](https://github.com/yasokada/unity-150831-udpMonitor/releases/tag/v0.3)

主な処理は以下のコード

```csharp:udpMonitorScript.cs
	void DoRelay() {
		UdpClient client = new UdpClient (setPort);
		client.Client.ReceiveTimeout = 300; // msec
		client.Client.Blocking = false;

		int portToReturn = 31415; // is set dummy value at first
		while (ToggleComm.isOn) {
			try {
				IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
				byte[] data = client.Receive(ref anyIP);
				string text = Encoding.ASCII.GetString(data);

				if (text.Length == 0) {
					Thread.Sleep(20);
					continue;
				}
				string fromIP = anyIP.Address.ToString();
				int fromPort = anyIP.Port;

				// send to the other
				if (fromIP.Equals(ipadr1)) {
					portToReturn = fromPort; // store the port used in the "else" clause
					client.Send(data, data.Length, ipadr2, setPort);
					DebugPrintComm("1 ", fromIP, fromPort, ipadr2, setPort);
				} else {
					client.Send(data, data.Length, ipadr1, portToReturn);
					DebugPrintComm("2 ", fromIP, fromPort, ipadr1, portToReturn);
				}
			}
			catch (Exception err) {

			}
			// without this sleep, on android, the app will freeze at Unity splash screen
			Thread.Sleep(200);
		}
		client.Close ();
	}
```

## Unityプロジェクトの使用例

192.168.10.3の端末で起動するとする。

起動直後
![Main_unity_-_150831-udpMonitor_-_PC__Mac___Linux_Standalone__Personal_.jpg](https://qiita-image-store.s3.amazonaws.com/0/32870/2b80a34a-3963-f96e-c674-63837cb610ff.jpeg)

Settingボタンを押すして、以下の設定を入力する。

![Main_unity_-_150831-udpMonitor_-_PC__Mac___Linux_Standalone__Personal_.jpg](https://qiita-image-store.s3.amazonaws.com/0/32870/c89edbd9-15df-6038-94b2-57d46b2d3ae4.jpeg)

OKボタンを押して、最初のシーンに戻る。

![Main_unity_-_150831-udpMonitor_-_PC__Mac___Linux_Standalone__Personal_.jpg](https://qiita-image-store.s3.amazonaws.com/0/32870/2b80a34a-3963-f96e-c674-63837cb610ff.jpeg)

ToggleCommにチェックを入れると、Relay機能が有効になる。

192.168.10.5の端末から 192.168.10.3(ポート6000)宛のUDP通信を行うと、以下の動作になる

- 192.168.10.3が受信した文字を 192.168.10.6へ送る (relay)
- 192.168.10.6が受信した文字を 192.168.10.3へ送り返す (echo server起動している時)
- 192.168.10.3が受信した文字を 192.168.10.5へ送る (relay)

![Main_unity_-_150831-udpMonitor_-_PC__Mac___Linux_Standalone__Personal_.jpg](https://qiita-image-store.s3.amazonaws.com/0/32870/340781e9-1913-f9b2-46a6-07a72ff8b14f.jpeg)


##苦労した点

UDPのポート番号の理解がいまいちだったため、6000から6000へ送ろうとして失敗していた。

## v0.5 (通信データexport機能追加)

[v0.5 @ github](https://github.com/yasokada/unity-150831-udpMonitor/releases/tag/v0.5)

以下のコマンドで通信データを出力する機能を追加した。

```
export,88555bd
```

88555bdというのはv0.1 commit時の[hash](https://github.com/yasokada/unity-150831-udpMonitor/releases/tag/v0.1). 普段の通信では使われることはないだろうという理由から選択した。

###使用例

IP:192.168.10.3において、以下の設定でソフトを起動しているとする (192.168.10.8から192.168.10.5の通信をモニタする)。

![Main_unity_-_150831-udpMonitor_-_Android__Personal_.jpg](https://qiita-image-store.s3.amazonaws.com/0/32870/ba22b915-6615-62b0-f145-2fa58d16abad.jpeg)

今回の例では、192.168.10.5においてecho serverを起動している。

192.168.10.8から 192.168.10.3へ以下のようにUDPで文字列を送信する。

```
$ echo "testaaa" | nc -w 2 -u 192.168.10.3 6000
testaaa
$ echo "testaaa" | nc -w 2 -u 192.168.10.3 6000
testaaa
$ echo "testaaa" | nc -w 2 -u 192.168.10.3 6000
testaaa
```

192.168.10.8(送信元)においてexpotコマンドを使うと、それまで送受信した文字列が送受信時刻、送受信方向とともに取得できる。

```
$ echo "export,88555bd" | nc -w 2 -u 192.168.10.3 6000
SOT
2015/09/13 03:34:18,tx,testaaa
2015/09/13 03:34:18,rx,testaaa
2015/09/13 03:34:23,tx,testaaa
2015/09/13 03:34:23,rx,testaaa
2015/09/13 03:34:26,tx,testaaa
2015/09/13 03:34:26,rx,testaaa
EOT
```

SOT: start of table, EOT:end of table
tx: 192.168.10.8 -> 192.168.10.5の通信
rx: 192.168.10.5 -> 192.168.10.8の通信

### 実装

以下のようなListに通信内容を保持していく。
list_comm_stringには"tx,"か"rx,"かと送受信のtextを格納する。

```
private List<System.DateTime> list_comm_time;
private List<string> list_comm_string;
```

exportData()の処理は以下。時系列グラフ udpTimeGraphでやっていることとほぼ同じ。

```udpMonitorScript.cs
...
	private void exportData(ref UdpClient client, ref IPEndPoint anyIP) 
	{
		byte[] data;
		string text;

		int idx = 0;

		text = "SOT"; // start of table
		text = text + System.Environment.NewLine;
		data = System.Text.Encoding.ASCII.GetBytes(text);
		client.Send(data, data.Length, anyIP);

		foreach (var commtime in list_comm_time) {
			text = commtime.ToString("yyyy/MM/dd HH:mm:ss");
			text = text + ",";
			text = text + list_comm_string[idx];

			// below comment out because text already includes <CR><LF>
	//		text = text + System.Environment.NewLine;

			data = System.Text.Encoding.ASCII.GetBytes (text);
			client.Send (data, data.Length, anyIP);

			idx++;
		}

		text = "EOT"; // start of table
		text = text + System.Environment.NewLine;
		data = System.Text.Encoding.ASCII.GetBytes(text);
		client.Send(data, data.Length, anyIP);

	}
...
```

###不明点

192.168.10.8と192.168.10.5が192.168.10.3経由で通信を続けている時に、別のIPから192.168.10.3に向けてexportコマンドを発行した時の動作が未調査。

とりあえずはexportコマンド発行時は他の通信を停止しているのがよいかも。



##今後

1. DONE: リレーした文字列を格納、取出しする
2. DONE: リレー時に遅延処理を入れる (通信状況が悪い場合の再現)
3. UIまわりをよくしようかどうか。優先度は低い。


### 検索用キーワード
(2019-01-18追記)

- UDPrepeater
- UDPrelay