unity-websocketを使ってUnityでWebSoketを通信を行う

初めに

UnityでWebSoketを使って通信をするのはいろいろ大変なので、どのライブラリを使おうかと調べていましたが、以下のライブラリを見つけたので動かしてみます

github.com

サーバーのコードは以下のリポジトリで公開しています

github.com

開発環境

準備

Python側で以下のライブラリを使用するためインストールを行います

pip install websockets

簡単な接続確認

まずは 接続確認から行っていきます

Unity

using UnityEngine;
using System.Collections;
using MikeSchweitzer.WebSocket;

public class WebSocketTester : MonoBehaviour
{
    public WebSocketConnection _connection;
    private string _url = "ws://localhost:8765";  // Pythonサーバーのアドレス

    private void Start()
    {
        // WebSocketの初期化と接続
        _connection = gameObject.AddComponent<WebSocketConnection>();
        _connection.DesiredConfig = new WebSocketConfig
        {
            Url = _url
        };

        _connection.Connect();

        // 接続状態の変更イベント
        _connection.StateChanged += OnStateChanged;

        // メッセージ受信イベント
        _connection.MessageReceived += OnMessageReceived;
        
        // エラーメッセージ
        _connection.ErrorMessageReceived += OnErrorMessageReceived;
    }

    private void OnStateChanged(WebSocketConnection connection, WebSocketState oldState, WebSocketState newState)
    {
        Debug.Log($"WebSocket state changed from {oldState} to {newState}");

        // 接続が確立された場合
        if (newState == WebSocketState.Connected)
        {
            // サーバーへメッセージを送信
            SendMessageToServer("Hello from Unity");
        }
    }

    private void OnMessageReceived(WebSocketConnection connection, WebSocketMessage message)
    {
        Debug.Log($"Message received from server: {message.String}");
    }

    private void OnErrorMessageReceived(WebSocketConnection connection, string errorMessage)
    {
        Debug.LogError($"WebSocket error: {errorMessage}");
    }

    private void SendMessageToServer(string message)
    {
        if (_connection != null && _connection.State == WebSocketState.Connected)
        {
            _connection.AddOutgoingMessage(message);
            Debug.Log($"Message sent to server: {message}");
        }
    }

    private void OnDestroy()
    {
        if (_connection != null)
        {
            _connection.Disconnect();
            _connection = null;
        }
    }
}

Python

import asyncio
import websockets

async def echo(websocket, path):
    async for message in websocket:
        print(f"Received message: {message}")
        await websocket.send(f"Echo: {message}")

start_server = websockets.serve(echo, "localhost", 8765)

asyncio.get_event_loop().run_until_complete(start_server)
print("WebSocket server started on ws://localhost:8765")
asyncio.get_event_loop().run_forever()

実行をすると以下のようなログが表示されます

クライアントから定期的にメッセージを送信

次にクライアントから定期的にメッセージを送るような少し複雑な?ことをします (サーバーのコードは同じものです)

using System;
using UnityEngine;
using Cysharp.Threading.Tasks;
using System.Threading;
using MikeSchweitzer.WebSocket;
using Random = UnityEngine.Random;

public class WebSoketTest : MonoBehaviour
{
    public WebSocketConnection _connection;
    private string _url = "ws://localhost:8765";  // Pythonサーバーのアドレス
    private bool _shouldReconnect = true;
    private CancellationTokenSource _cts;

    private void Start()
    {
        _cts = new CancellationTokenSource();

        // WebSocketの初期化と接続
        _connection = gameObject.AddComponent<WebSocketConnection>();
        _connection.DesiredConfig = new WebSocketConfig
        {
            Url = _url
        };

        _connection.Connect();

        // 接続状態の変更イベント
        _connection.StateChanged += OnStateChanged;

        // メッセージ受信イベント
        _connection.MessageReceived += OnMessageReceived;
        
        // エラーメッセージ
        _connection.ErrorMessageReceived += OnErrorMessageReceived;

        // 定期的なメッセージ送信を非同期タスクで実行
        SendMessagesPeriodically(_cts.Token).Forget();
    }

    private void OnStateChanged(WebSocketConnection connection, WebSocketState oldState, WebSocketState newState)
    {
        Debug.Log($"WebSocket state changed from {oldState} to {newState}");

        // 再接続の試み
        if (newState == WebSocketState.Disconnected && _shouldReconnect)
        {
            Reconnect().Forget();
        }
    }

    private void OnMessageReceived(WebSocketConnection connection, WebSocketMessage message)
    {
        Debug.Log($"Message received from server: {message.String}");
    }

    private void OnErrorMessageReceived(WebSocketConnection connection, string errorMessage)
    {
        Debug.LogError($"WebSocket error: {errorMessage}");
    }

    private async UniTaskVoid SendMessagesPeriodically(CancellationToken cancellationToken)
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            if (_connection != null && _connection.State == WebSocketState.Connected)
            {
                var message = "Random message: " + Random.Range(0, 1000);
                _connection.AddOutgoingMessage(message);
                Debug.Log($"Message sent to server: {message}");
            }

            // 送信間隔を待機
            await UniTask.Delay(TimeSpan.FromSeconds(5), cancellationToken: cancellationToken);
        }
    }

    private async UniTaskVoid Reconnect()
    {
        Debug.Log("Attempting to reconnect...");
        await UniTask.Delay(TimeSpan.FromSeconds(5));

        if (_connection != null && _connection.State != WebSocketState.Connected)
        {
            _connection.Connect();
        }
    }

    private void OnDestroy()
    {
        _cts.Cancel();
        _cts.Dispose();

        _shouldReconnect = false;

        if (_connection != null)
        {
            _connection.Disconnect();
            _connection = null;
        }
    }
}

ここでは以下のようなメッセージが表示されます