はかせのラボ

私の頭の中を書いていく雑記ブログです

Unity UDP通信を受信する

あいさつ

どうも、はかせです。

何気なくアクセス解析を見てたらですね
以前上げたTCP通信の記事がトップになってました。
f:id:hakase0274:20191108210217p:plain

ということで今日はUDPやっていきますよ。
(別にこのためにやってたわけじゃないけど)

ちなみに今回は受信だけです。

実装内容

今回はスマホとPCでUDP通信を行い
加速度センサーの値と姿勢センサーの値を取得します。

スマホからのデータ送信には
「ZIG SIM」というアプリを使います。

ZIG SIM
ZIG SIM
開発元:1-10
無料
posted withアプリーチ

このアプリはスマホの各種センサの値を色んな通信方法やデータ形式で送信できるアプリです。
今回はUDP通信でJSONを送ります。
JSONの扱いはMiniJSONJsonNodeを使っています。

コード

UdpClientを使いデータを取得した後
JsonNodeを使ってJSONにパースします。

using System;
using System.Text;
using System.Net;
using System.Net.Sockets;

public class UdpReceiver : IDisposable
{
    UdpClient mUdp;
    //ソケット通信に何か問題が発生したときのコールバック
    public Action<SocketException> SocketExceptionCallBack;
    //UdpClientがDisposeされているときのコールバック
    public Action<ObjectDisposedException> ObjectDisposedExceptionCallBack;

    /*以下アプリ依存のコールバック*/
    //加速度センサーのコールバック
    public Action<double, double, double> AccelCallBack;
    //姿勢センサーのコールバック
    public Action<double, double, double, double> QuaternionCallBack;

    /// <summary>
    /// Udp通信を開始する
    /// </summary>
    /// <param name="localIpString">IPアドレス</param>
    /// <param name="localPort">ポート番号</param>
    public void Start(string localIpString,int localPort) 
    {
        IPAddress localAddress = IPAddress.Parse(localIpString);
        IPEndPoint localEP = new IPEndPoint(localAddress, localPort);
        mUdp = new UdpClient(localEP);
        mUdp.BeginReceive(UDPReceive, mUdp);
    }

    public void Dispose()
    {
        mUdp.Dispose();
    }

    /// <summary>
    /// 受信処理
    /// </summary>
    /// <param name="res"></param>
    void UDPReceive(IAsyncResult res)
    {
        UdpClient getUdp = (UdpClient)res.AsyncState;
        IPEndPoint ipEnd = null;

        try
        { 
            //バイトデータを取得
            byte[] getByte = getUdp.EndReceive(res, ref ipEnd);
            //アスキーコードで文字列に変換
            string text = Encoding.ASCII.GetString(getByte);
            //JSONをパース 今回はMiniJSON+JsonNodeを使ってる
            JsonNode jsonNode = JsonNode.Parse(text);
            //加速度センサーの値を取得
            double ax = jsonNode["sensordata"]["accel"]["x"].Get<double>();
            double ay = jsonNode["sensordata"]["accel"]["y"].Get<double>();
            double az = jsonNode["sensordata"]["accel"]["z"].Get<double>();
            //姿勢センサーの値を取得
            double qutX = jsonNode["sensordata"]["quaternion"]["x"].Get<double>();
            double qutY = jsonNode["sensordata"]["quaternion"]["y"].Get<double>();
            double qutZ = jsonNode["sensordata"]["quaternion"]["z"].Get<double>();
            double qutW = jsonNode["sensordata"]["quaternion"]["w"].Get<double>();
            //コールバックに流す
            AccelCallBack(ax, ay, az);
            QuaternionCallBack(qutX, qutY, qutZ, qutW);
        }
        catch (SocketException ex)
        {
            SocketExceptionCallBack(ex);
            return;
        }
        catch (ObjectDisposedException ex) 
        {
            ObjectDisposedExceptionCallBack(ex);
            return;
        }
        //もう一回受信
        getUdp.BeginReceive(UDPReceive, getUdp); 
    }
}

Startを呼び出すことでUdpClientを作成し、
受信を開始します。

StartにはIPアドレスとポート番号を渡します。
IPアドレスはcmdからipconfigで調べられます。
ポート番号はなんでもいいですが、
不安な人はnetstatで使おうとしているポートが空いてるか
調べるといいです。

Startを呼び出した後はデータを受信したタイミングで
・受信停止
・バイトデータ取得
・バイトデータをアスキーコードでエンコード
エンコード文字列をJSONにパース
JSONからデータを取得し各コールバックを起動
・再度受信を開始

という処理を行います。

実行環境

通信を扱うものなのでちょっとだけ
意識しなきゃいけないことがあります。
スマホとPCを同一LANにつなぐ
・Unity側はビルドした実行ファイルを使う

一つ目はまぁそらそうだって話なんですが、
二つ目は意外とハマりそうです。(ハマりました)

詳しい原理やら理屈やらは知りませんが、
エディタ実行でやるとUDPのパケットが叩き潰されます。
(マジUnityファッ○)

なのでビルドしましょう。
Build and RunならCtrl+Bでできますから(Windows)

結果

www.youtube.com

手元を映すカメラがなかったので
イマイチ連動しているかはわかりにくいかもですが
動きがそれっぽいのでなんとなく察してください。

あとがき

今回はUnityでUDP通信でした。
ハマりどころはありますが、
そこさえ回避できればそんな難しくはないです。

あと今回やるうえで初めて知った「ZIG SIM」
ぶっちゃけめちゃめちゃ強いアプリだと思います。
これとUnityがあればなんちゃってIoTが簡単に作れますね。

今回の記事が良ければスターやコメント等よろしくお願いします。
それでは今回はこの辺でノシ