はかせのラボ

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

Unity TCP通信を受信する

あいさつ

どうも、はかせです。
今やってるAWSTCP通信しかサポートしてないそうなので、
Unityを使ってTCP通信を受信してみます。
(UDPが出来たら楽だったんだけどなぁ)

サーバー、クライアント双方がUnityならば
わざわざこんなことする必要がないので
今回はCLIの入力をUnityに送ってみます。

サーバーサイド(Unity)

using UnityEngine;
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class TestTCPServer : MonoBehaviour
{
    //自分自身を指すIPアドレス
    public string mIpAddress = "127.0.0.1";
    //ポート番号は適当 ただしクライアントと合わせること
    public int mPortNumber = 2001;

    private TcpListener mListener;
    private TcpClient mClient;

    // ソケット接続準備、待機
    public void Start()
    {
        var ip = IPAddress.Parse(mIpAddress);
        mListener = new TcpListener(ip, mPortNumber);
        mListener.Start();
        //コールバック設定 第二引数はコールバック関数に渡される
        mListener.BeginAcceptSocket(DoAcceptTcpClientCallback, mListener);
    }

    // クライアントからの接続処理
    private void DoAcceptTcpClientCallback(IAsyncResult ar)
    {
        //渡されたものを取り出す
        var listener = (TcpListener)ar.AsyncState;
        mClient = listener.EndAcceptTcpClient(ar);
        print("Connect: " + mClient.Client.RemoteEndPoint);

        // 接続した人とのネットワークストリームを取得
        var stream = mClient.GetStream();
        var reader = new StreamReader(stream, Encoding.UTF8);

        // 接続が切れるまで送受信を繰り返す
        while (mClient.Connected)
        {
            while (!reader.EndOfStream)
            {
                // 一行分の文字列を受け取る
                print(reader.ReadLine());
            }

            // クライアントの接続が切れたら
            if (mClient.Client.Poll(1000, SelectMode.SelectRead) && (mClient.Client.Available == 0))
            {
                print("Disconnect: " + mClient.Client.RemoteEndPoint);
                mClient.Close();
                break;
            }
        }
    }

    // 終了処理
    protected virtual void OnApplicationQuit()
    {
        if (mListener != null) mListener.Stop();
        if (mClient != null) mClient.Close();
    }
}

クライアントサイド(CLI)

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

class Program
{
    static void Main(string[] args)
    {
        //サーバーに送信するデータを入力してもらう
        Console.WriteLine("文字列を入力し、Enterキーを押してください。");
        var sendMsg = Console.ReadLine();
        //何も入力されなかった時は終了
        if (sendMsg == null || sendMsg.Length == 0) return;

        //サーバーのIPアドレス(または、ホスト名)とポート番号
        var ipOrHost = "127.0.0.1";
        //string ipOrHost = "localhost";
        var port = 2001;

        //TcpClientを作成し、サーバーと接続する
        var tcp = new TcpClient(ipOrHost, port);
        Console.WriteLine("サーバー({0}:{1})と接続しました({2}:{3})。",
            ((IPEndPoint)tcp.Client.RemoteEndPoint).Address,
            ((IPEndPoint)tcp.Client.RemoteEndPoint).Port,
            ((IPEndPoint)tcp.Client.LocalEndPoint).Address,
            ((IPEndPoint)tcp.Client.LocalEndPoint).Port);

        //NetworkStreamを取得する
        var ns = tcp.GetStream();

        //読み取り、書き込みのタイムアウトを10秒にする
        //デフォルトはInfiniteで、タイムアウトしない
        //(.NET Framework 2.0以上が必要)
        ns.ReadTimeout = 10000;
        ns.WriteTimeout = 10000;

        //サーバーにデータを送信する
        //文字列をByte型配列に変換
        var sendBytes = Encoding.UTF8.GetBytes(sendMsg + '\n');
        //データを送信する
        ns.Write(sendBytes, 0, sendBytes.Length);
        Console.WriteLine(sendMsg);

        //閉じる
        ns.Close();
        tcp.Close();
        Console.WriteLine("切断しました。");
        Console.ReadLine();
    }
}

実行結果

クライアントサイド
f:id:hakase0274:20190811234140p:plain
サーバーサイド
f:id:hakase0274:20190811234151p:plain

あとがき

今回はUnityにTCP通信を使ってデータを送ってみました。
UnityWebRequestやってた辺りでUnity内で通信やろうとすると
叩き落される的な話をしてましたが、
受信だけならば特に干渉されないっぽいですね。
(もしくは私が離れてた約1年の間に色々許されるようになったのか)

ちなみに今回Unity(サーバーサイド)から送信してないのは
変に叩き落されるんじゃないかっていう恐怖と
今作ろうとしてるものでUnityから送信する必要がないからですね。

まぁ必要になったとしてもC#のTcpClient使ってるだけなんで
そんな手間でもないですし必要になったらつければいいかなーと。
(C#は適当にそれっぽいの探してちょちょいと書き直すだけでできる楽ちん言語だからな)

それでは今回はこの辺でノシ

参考

Unityで受信
blog.applibot.co.jp

TCP送る
dobon.net