PC内でUDPソケット通信（Unityとフォームアプリ）

#目次
・はじめに
・Windows10（フォームアプリケーション＿.NET Framework＿C#）の作成
・Unityアプリ（C#）の作成
・結果
#はじめに
　別のアプリで処理したデータをUnityに送りたい。UnityはBLEとかサポートしてないので、Windowsで使用する場合は別にアプリを作成する必要があるのだが、数値の引き渡しをどうすべきか？メモリマップトファイルとか使っていたが、Socket通信というのが簡単らしい（もう古いらしい？との情報も…）のでやってみる。
　TCPとUDPの二つの方式のうち、UDPとする。データの品質にはこだわらないからだ。テストのため、
　WindowsフォームアプリからデータをUnityに送信する　－＞　Unityは受け取ったデータを送り返す　－＞　WindowsフォームアプリはUnityからデータを受け取る。
　という形式で作ってみる。
　作ってみた結果は以下のとおり、
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">WindowsフォームアプリとUnity間でソケット通信<br>PC内のアプリ間でUDPの通信ができるようになった。 <a href="https://t.co/A3ivxNi6rO">pic.twitter.com/A3ivxNi6rO</a></p>&mdash; いっちー (@get_itchy_feet) <a href="https://twitter.com/get_itchy_feet/status/1248948897172475905?ref_src=twsrc%5Etfw">April 11, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
#Windows10（フォームアプリケーション＿.NET Framework＿C#）の作成
　まずは【Microsoft Visual Studio Community 2019】から新しいプロジェクト【Windowsフォームアプリケーション_.NET Framework】を作成する。使用する言語は【C#】となる。
　画面も簡単に作る。ラベル二つにボタンが一つ、それにタイマー。それぞれ以下の通り。
　　・ラベル：labelDataFromUnity　受信した数値を表示。
　　・ラベル：labelDataToUnity　送信する数値を表示。
　　・ボタン：buttonDataFromUnity　送信ボタン。ボタンをクリックすると数値を送信する。
　　・タイマー：timer1　ラベルの文字の更新に使用する。intervalが100ms、enabledをtrueに。
　Unityに送る数値は二つ。最初の数値はクリックするごとに一つずつ増える。もう一つは何も変わらない。複数送れるか試すため、二つになっている。
　また、タイマーを用い100msごとにラベルの文字を更新する。
<img width=60% src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184089/4cc24de0-a775-27b4-8dd8-0d387e04bafe.png>
　コードの書き方もいろんなところを参考にコピペして作り上げた。主に参考にしたのは以下のサイト
https://dobon.net/vb/dotnet/internet/udpclient.html
https://garafu.blogspot.com/2015/08/udpclient.html

　以下のようにコードを書いてみる。Tryとかは適当に入れてあるので不十分だが気にしない。

```C#:FormsAppSoketUdpQiita
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace FormsAppSoketUdpQiita
{
    public partial class Form1 : Form
    {
        //Formアプリ側
        static string localIpString = "127.0.0.10";
        static int localPort = 8887;
        static IPAddress localAddress = IPAddress.Parse(localIpString);
        static IPEndPoint localEP = new IPEndPoint(localAddress, localPort);
        static UdpClient udp = new UdpClient(localEP);
        //Unity側
        static int unityPort = 8888;
        static IPEndPoint unityEP = new IPEndPoint(localAddress, unityPort);
        //受信用Thread
        static bool isReceiving;
        static string RxDatatext, TxDatatext;
        Thread thread;
        public Form1()
        {
            InitializeComponent();
            udp.Client.ReceiveTimeout = 1000;
            udp.Connect(unityEP);
            isReceiving = true;
            thread = new Thread(new ThreadStart(ThreadMethod));
            thread.Start();
            TxDatatext = "labelDataFromUnity";
            RxDatatext = "labelDataToUnity";
        }

        private void buttonDataToUnity_Click(object sender, EventArgs e)
        {
            if (TxData[0] < 100) TxData[0]++;
            else TxData[0] = 0;
            TxDatatext = TxData[0].ToString() + "," + TxData[1].ToString();
            udp.Send(TxData, 2);
        }
        private static void ThreadMethod()
        {
            while (isReceiving)
            {
                try
                {
                    IPEndPoint remoteEP = null;
                    byte[] data = udp.Receive(ref remoteEP);
                    RxDatatext = data[0].ToString() + " , " + data[1].ToString();
                }
                catch (System.Exception e)
                {
                }
            }
        }
        public static byte[] TxData = {0 ,0};

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (thread != null) thread.Abort();
            if (udp != null) udp.Close();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            labelDataToUnity.Text = TxDatatext;
            labelDataFromUnity.Text = RxDatatext;
        }
    }
}
```
#Unityの作成
　Unity側もやってみる。Textを二つ貼り付けそれぞれ受信したデータと送信するデータが表示される。
　（※受信＝送信データなので、値は変わらない）
　textDataToFomApp：送信データ
　textDataFromFomApp：受信データ
　画面はこんな感じで。
<img width=60% src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184089/361b7793-e05e-b806-58dc-ae683ec7b246.png>
　UDP通信用に以下のコードを作った。

```C#:LocalUdpReceive
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using UnityEngine.UI;

public class LocalUdpReceive : MonoBehaviour
{
    static string localIpString = "127.0.0.10";
    static int localPort = 8887;
    static IPAddress localAddress = IPAddress.Parse(localIpString);
    IPEndPoint localEP = new IPEndPoint(localAddress, localPort);

    static int unityPort = 8888;
    IPEndPoint unityEP = new IPEndPoint(localAddress, unityPort);
    static bool isReceiving;
    static UdpClient udpUnity;
    Thread thread;

    public Text textDataToFomApp;
    public Text textDataFromFomApp;
    static string Rtext,Ttext;

    void Start()
    {
        udpUnity = new UdpClient(unityEP);
        udpUnity.Client.ReceiveTimeout = 20;
        udpUnity.Connect(localEP);
        isReceiving = true;
        thread = new Thread(new ThreadStart(ThreadMethod));
        thread.Start();
        Debug.Log("start");
        Ttext = "DataToFomApp";
        Rtext = "DataFromFomApp";
    }
    static public byte[] unityData;
    void Update()
    {
        textDataFromFomApp.text = Rtext;
        udpUnity.Send(unityData,2);
        textDataToFomApp.text = Ttext;
    }

    void OnApplicationQuit()
    {
        isReceiving = false;
        if (thread != null) thread.Abort();
        if (udpUnity != null) udpUnity.Close();
    }

    private static void ThreadMethod()
    {
        while (isReceiving)
        {
            try
            {
                IPEndPoint remoteEP = null;
                byte[] data = udpUnity.Receive(ref remoteEP);
                Rtext = data[0].ToString() + " , " +data[1].ToString();
                unityData = data;
                Ttext = unityData[0].ToString() + " , " + unityData[1].ToString();
                Debug.Log(Rtext);
            }
            catch (System.Exception e)
            {
                Debug.Log(e.ToString());
            }
        }
    }
}
```
#結果
　うまく通信できた。メモリマップトファイルよりかなり楽だ。
　ただ、一つ注意がIPアドレスだった。なんでもいいかと思いきやどうもPC内での通信では【127.xx.xx.xx】である必要があるみたいだ。
　このあたりをちゃんと読まねばなぁ。
https://qiita.com/mogulla3/items/efb4c9328d82d24d98e6