夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

BlenderとUnityでTCP通信を行う

本日はBlender枠です。

以前Blenderでサーバーを立ててUnityへデータを送信しました。

この記事で使用した通信プロトコルはUDPと呼ばれるものを使用しました。

redhologerbera.hatenablog.com

今回はTCPのプロトコルを使用してUnityとBlenderで通信を行っていきます。

〇UDPとTCPの違い

UDPもTCPもどちらも通信を行うプロトコルです。

UDPはリアルタイム通信や大規模データの送信に向いており、送信元のデバイスでは送信先がデータを受け取ったことを確認せずにデータを送り続けます。

デメリットとしては通信のデータロスが発生する可能性があります。

逆にTCPは通信相手とのコネクションを確立している状態で通信を行います。

つまり通信データの確実性があります。

今回はこのTCPの仕組みでBlenderとUnityで通信を行います。

〇参考

cloudapi.kddi-web.com

〇Blenderサーバー

BlenderではSocketを使用しています。

次のコードを実行します。

import bpy
import socket
import threading

class ClientHandler(threading.Thread):
    def __init__(self, client_socket):
        threading.Thread.__init__(self)
        self.client_socket = client_socket

    def run(self):
        while True:
            request = self.client_socket.recv(1024)
            if not request:
                break
            print("[*] Received: %s" % request.decode())
        self.client_socket.close()

class ServerThread(threading.Thread):
    def __init__(self, bind_ip, bind_port):
        threading.Thread.__init__(self)
        self.bind_ip = bind_ip
        self.bind_port = bind_port

    def run(self):
        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server.bind((self.bind_ip, self.bind_port))
        server.listen(5)
        print("[*] Listening on %s:%d" % (self.bind_ip, self.bind_port))

        while True:
            client, addr = server.accept()
            print("[*] Accepted connection from: %s:%d" % (addr[0], addr[1]))
            client_handler = ClientHandler(client)
            client_handler.start()
            self.client_socket = client

# Run the server in a new thread
server_thread = ServerThread("0.0.0.0", 9999)
server_thread.start()

def send_message_to_unity(message):
    server_thread.client_socket.send(message.encode())

class SimpleOperator(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "object.send_message"
    bl_label = "Send Message"

    def execute(self, context):
        send_message_to_unity("Hello, Unity!")
        return {'FINISHED'}

class CustomPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Send Message Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

    def draw(self, context):
        layout = self.layout
        layout.operator("object.send_message")

bpy.utils.register_class(SimpleOperator)
bpy.utils.register_class(CustomPanel)

コードを実行するとオブジェクトプロパティウィンドウにSend Messageが表示されます。

このボタンを押すことでUnityにメッセージを送信します。

〇Unity

Unity側は次のコードを使用します。

このコードではHキーを押すことでBlender側にメッセージを送ります。

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

public class TCPClient : MonoBehaviour
{
    private TcpClient _client;
    private NetworkStream _stream;

    void Start()
    {
        _client = new TcpClient("localhost", 9999);
        _stream = _client.GetStream();

        // Start a new thread to listen for incoming messages
        new Thread(() =>
        {
            var responseBytes = new byte[1024];
            while (true)
            {
                var bytesRead = _stream.Read(responseBytes, 0, responseBytes.Length);
                Debug.Log("Received: " + Encoding.ASCII.GetString(responseBytes, 0, bytesRead));
            }
        }).Start();
    }

    void Update()
    {
        // Send a message when the H key is pressed
        if (Input.GetKeyDown(KeyCode.H))
        {
            var bytes = Encoding.ASCII.GetBytes("Hello, Blender!");
            _stream.Write(bytes, 0, bytes.Length);
        }
    }

    private void OnDestroy()
    {
        _stream.Close();
        _client.Close();
    }
}

〇実行

実行しそれぞれの送信ボタンを押すことでメッセージを送りあうことができます。

以上でTCPの双方向通信が行えました。

細かいコードの解説は後日行います。本日は以上です。