はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Unity】websocket-sharpを用いてリアルタイムな通信をしてみる

はじめに

今回はwebsocket-sharpを用いてリアルタイムな通信をしてみる記事になります!

このwebsocket-sharpというライブラリを使うことで、手軽にオンラインゲームといったリアルタイムに通信が必要なものを実装できます。

またサーバーとクライアントの両方をこのライブラリで対応しているので、Unityとこのライブラリだけでどちらも実装できるのも魅力の一つですね。

では早速みていきましょう。

websocketとは?

このライブラリの名前にもあるwebsocketですが、以下のような意味があるようです。

Webにおいて双方向通信を低コストで行うための仕組み。プロトコルの一種。

今さら聞けないWebSocket~WebSocketとは~ - Qiita

オンラインゲームのような複数によるリアルタイムなやり取りに向いているというわけですね。

下準備

websocket-sharpは残念ながらAssetStoreにはないみたいなので、GitHubからダウンロードして自分でビルドする必要があります。

github.com

cloneをしてもいいですが、Download Zipの方に今回はします。すると.zipのファイルがダウンロードできるので、解凍しましょう。

f:id:hanaaaaaachiru:20190924035804p:plain

サンプルは必要ないのでExampleを削除し、websocket-sharp.slnをVisual Studioで開きます。

f:id:hanaaaaaachiru:20190924040939p:plain

ここでビルドしようとしたところエラーが出てしまったので、少しだけコードを追加します。

CookieException.cs

修正前

[Serializable]
public class CookieException : FormatException


修正後

[Serializable]
public class CookieException : FormatException, ISerializable

修正ができたらビルドし、出力のところに.dllのパスが表示されているので確認してみましょう。

f:id:hanaaaaaachiru:20190924042451p:plain

websocket-sharp.dllをUnityのPluginsフォルダに入れれば下準備は終了です。

f:id:hanaaaaaachiru:20190924043157p:plain

サーバー側の実装をする

using UnityEngine;
using WebSocketSharp;
using WebSocketSharp.Server;

public class WSServer : MonoBehaviour
{
    private WebSocketServer _server;

    private void Start()
    {
        _server = new WebSocketServer(3000);
        _server.AddWebSocketService<Echo>("/");
        _server.Start();
    }

    private void OnDestroy()
    {
        _server.Stop();
        _server = null;
    }

    public class Echo : WebSocketBehavior
    {
        protected override void OnMessage(MessageEventArgs e)
        {
            Sessions.Broadcast(e.Data);
            Debug.Log(e.Data);
        }
    }

}

これがサーバー側のスクリプトになります。

WebSocketServerのコンストラクタによりポート番号を設定できます。

WebSocketBehaviorを継承したクラスには、メッセージをサーバーが受信したときの処理をOnMessageに書きました。

今回はこれだけですが、コネクションを確立したときのOnOpen,エラーが発生したときのOnError,接続を切断したときのOnCloseは必要に応じて書き加えても良いでしょう。

そしてWebSocketBehavior.Sessions.Broadcastメソッドによってクライアントから受け取ったメッセージをそのまますべてのクライアントに送信しています。

試してみる

サーバー側のスクリプトがちゃんと動くのか見てみます。

動作を確認するためにwscatを用いることで簡単にできます。
WebSocket の動作確認に wscat が便利すぎる件 - tricknotesのぼうけんのしょ

ただこれはNode.jsが必要なので、まだインストールしていない方は以下の記事を参考に設定してみてください。
Node.jsをWindows10にインストールする方法 - Qiita

インストールができら以下のコマンドをコマンドプロンプト等で打ち込みます。

$ npm install -g wscat

準備が整ったら、以下のコマンドにてサーバー繋ぐことができます。
(ポート番号が3000の場合)

$ wscat -c ws://localhost:3000

実際にUnityで上のサーバー側のコードを書いたものをゲームオブジェクトにアタッチした後再生ボタンを押し、wscatでサーバーにつないでみてください。

f:id:hanaaaaaachiru:20190929183328p:plain

クライアント側の実装する

using UnityEngine;
using WebSocketSharp;

public class WSClient : MonoBehaviour
{
    private WebSocket _webSocket;

    private const string WEBSOCKET_URL = "ws://localhost3000/";

    private void Start()
    {
        _webSocket = new WebSocket(WEBSOCKET_URL);

        _webSocket.OnMessage += (sender, e) => Debug.Log(e.Data);
        _webSocket.OnClose += (sender, e) => Debug.Log("Close");

        _webSocket.Connect();
    }

    private void Update()
    {
        if (Input.GetKeyDown("s"))
            _webSocket.Send("Send a message");
    }

    private void OnDestroy()
    {
        _webSocket.Close();
        _webSocket = null;
    }
}

WebSocketのコンストラクタでWebSocketのURLを設定します。

そしてメッセージを受け取ったときのOnMessage,通信を終了したときのOnCloseのイベントを。

さきほどと同様にOnOpenOnErrorもつけても良いと思います。

またWebSocket.OpenSendCloseはともにOpenAsyncのように書くことで非同期にできるようです。

f:id:hanaaaaaachiru:20190929220451p:plain

さいごに

このサーバーのスクリプトを含むシーンをLinux向け等にビルドして、自前のサーバーやレンタルサーバー(VPSとかEC2とか?)で動作させるとまさにオンラインゲームの完成です。

色々なことに応用できると思うので、かなり夢が広がりますね!