ObjectDeliverer

TCP/IP、UDP、共有メモリ、Fileなど様々な通信方式を簡単に切り替えて実装可能にするライブラリ

概要

ObjectDelivererは、Unreal Engineプロジェクトでのデータ通信を簡素化するための柔軟なライブラリです。TCP/IP、UDP、共有メモリ、Fileなど、様々な通信プロトコルを簡単に切り替えることができ、C++とBlueprintの両方で利用可能です。

このプラグインの最大の特徴は、通信方式を変更する際にコードをほとんど変更する必要がないことです。プロトコルを切り替えるだけで、残りのコードはそのまま使用できます。

そのため、TCP/IPで実装していた通信を簡単にUDPに切り替えたりできます。これは検証段階のプロジェクトで様々な通信方式を試す場合などに役立ちます。

主な機能

  • 様々な通信プロトコルのサポート(TCP/IP、UDP、共有メモリ、ファイルなど)
  • プロトコル間の簡単な切り替え
  • C++とBlueprintの両方でのフル機能サポート
  • 非同期通信のサポート(メインスレッドをブロックせずに通信します)
  • 柔軟なデータフォーマット対応 (バイナリ、プレーンテキスト、Jsonテキスト)

使用例

以下は、ObjectDelivererを使用してTCPサーバーを作成する基本的な実装例です

ブループリント
C++
void UMyClass::Start()
{
    auto deliverer = UObjectDelivererManager::CreateObjectDelivererManager();

    // Set up event handlers
    deliverer->Connected.AddDynamic(this, &UMyClass::OnConnect);
    deliverer->Disconnected.AddDynamic(this, &UMyClass::OnDisConnect);
    deliverer->ReceiveData.AddDynamic(this, &UMyClass::OnReceive);

    // Start communication
    // Protocol: TCP/IP Server
    // Data division rule: Header(Size) + Body
    // Serialization method: Byte array
    deliverer->Start(UProtocolFactory::CreateProtocolTcpIpServer(9099),
                     UPacketRuleFactory::CreatePacketRuleSizeBody());
}

void UMyClass::OnConnect(UObjectDelivererProtocol* ClientSocket)
{
    // Send data
    TArray<uint8> buffer;
    deliverer->Send(buffer);
}

void UMyClass::OnDisConnect(UObjectDelivererProtocol* ClientSocket)
{
    // Handle disconnection
    UE_LOG(LogTemp, Log, TEXT("closed"));
}

void UMyClass::OnReceive(UObjectDelivererProtocol* ClientSocket, const TArray<uint8>& Buffer)
{
    // Handle received data
}


プロトコルの切り替え

プロトコルの変更をするにはStartメソッドに別のプロトコルを渡すだけです。上記の例から以下の変更をするだけで、UDP送信プロトコルに変更ができます。

ブループリント
C++
// UDP Sender
deliverer->Start(UProtocolFactory::CreateProtocolUdpSocketSender("192.168.0.100", 9099),
                 UPacketRuleFactory::CreatePacketRuleSizeBody());

ObjectDelivererは以下のプロトコルをサポートしています。またオリジナルのプロトコルを作ることも可能です。

  • TCP/IP Server
  • TCP/IP Client
  • UDP Sender
  • UDP Receiver
  • Shared Memory(Windows only)
  • File writer
  • File reader
  • Reflection
TCP/IP Server, Client

TCP/IP通信をするためのプロトコルです。TCP/IP通信は1対多の通信をサポートしているので、1つのサーバーに対して複数のクライアントを接続することができます。

またパケットの再送機能が備わっているので、基本的に送信したメッセージは確実に相手に届きます。

UDP Sender, Receiver

UDP通信をするためのプロトコルです。UDP通信はTCP/IPのように接続するステップを踏まずに相手に一方的にメッセージを送信します。

またパケットの再送機能は備わっていないので、ネットワークの状況によってはパケットが届かない場合もあります。その分TCP/IPに比べてパフォーマンスには優れます。

Shared Memory

Shared Memoryは複数のアプリケーションでシェア可能なメモリ空間を作り、そこへメッセージの書き込みと読み込みをするための機能です。

通信ではないので、同一PCでのみ値の送受信を行うことができます。

また送信(書き込み)したことを相手が知る手段がないので、受信側は定期的にメモリを読み込んで新しい書き込みがあるかどうかを調べる必要があります。ObjectDelivererはこのあたりの処理を自動で行うため利用者は通常意識する必要はありません。ただし第三者が作成したメモリを読み込む場合などはどのようなルールで読み込むのかを確認しておく必要があります。

Shared Memoryは同一PCでしか使えないデメリットがありますが、メッセージの読み書きのスピードは他よりも勝るのでサイズの大きなメッセージのやりとりに向いています。

現時点ではこのプロトコルはWindowsでのみ使えます。

File writer, reader

Fileは特定のファイルにメッセージを書き込み、読み込みするためのプロトコルです。

これの挙動はShared Memoryに似ていますが、実際のファイルに書き込みを行うのでアプリケーション終了後にもメッセージを確認することができます。

そのため何らかのデータを保管しておく用途に向いています。

Reflection

これは送受信を自分自身で行うプロトコルです。メッセージの送信を行うと自分自身に受信イベントが発生します。そのため自分以外とのメッセージのやり取りはできません。

主に開発中のデバッグ用とで使われることを想定しています。

パケット分割ルールの切り替え

TCP/IPなどのプロトコルは送受信されるメッセージが複数のパケットに分割されたり、逆に複数のメッセージが1つのパケットに結合されたりします。

そこでObjectDelivererはこのようなパケットの分割ルールを設定することで、この問題を解決します。

パケット分割ルールは、プロトコルの切り替えと同様にStartメソッドに分割ルールを渡すことで指定できます。

ブループリント
C++
// UDP Sender
deliverer->Start(UProtocolFactory::CreateProtocolUdpSocketSender("192.168.0.100", 9099),
                 UPacketRuleFactory::CreatePacketRuleSizeBody());

ObjectDelivererは以下の分割ルールをサポートしています。またオリジナルのルールを作ることも可能です。

  • FixedLength
  • Terminate
  • SizeBody
  • Nodivision

これらの分割ルールは送受信の双方で同じルールを使う必要があります。そのため第三者が作成したプログラムと送受信をする必要がある場合はそれがどの分割ルールを用いているのかを事前に調べる必要があります。

FixedLenth

FixedLengthはメッセージのサイズを固定の長さに決めることで分割する方法です。これは毎回送信するパケットサイズが固定になるので分割ロジックはシンプルになりますが、指定したサイズより大きなメッセージは送れない制限があります。

Terminate

Terminateはメッセージの区切りに特定の値を指定して区切り方法です。よく使われる方法としては改行コードで区切る方式がこれに当たります。この方法は動的に送信するメッセージの長さを変えることができますが、毎回終端値を探す必要があるのでややパフォーマンスが落ちます。

SizeBody

SizeBodyはメッセージの先頭にメッセージサイズを埋め込む方法です。この方法は動的にサイズを変えることもできまたパケットを分割するロジックも割とシンプルなためパフォーマンスにも優れます。

Nodivision

Nodivisionはパケットを分割、結合せずに受信したパケットをそのまま1つのメッセージとして扱います。

DeliveryBoxの切り替え

ObjectDelivererは標準ではバイト配列を送受信しますが、これを指定のフォーマットのデータに変換することができます。

これを使用することでより毎回バイト配列に変換する手間がなくなります。

ブループリント
C++
auto deliverybox = UDeliveryBoxFactory::CreateObjectDeliveryBoxUsingJson(SampleObject::StaticClass());
deliverybox->Received.AddDynamic(this, &UMyClass::OnReceiveObject);

deliverer->Start(UProtocolFactory::CreateProtocolTcpIpServer(9099),
                 UPacketRuleFactory::CreatePacketRuleSizeBody(),
                 deliverybox);

DeliveryBoxを使用する場合は、メッセージの送受信はObjectDelivererManagerではなくDeliveryBox経由で行うことになることに注意してください。

ブループリント
C++
auto message = NewObject<SampleMessage>();
deliveryBox->Send(message);

ObjectDelivererは以下のDeliveryBoxをサポートしています。またオリジナルのDeliveryBoxを作ることも可能です。

  • ObjectDeliveryBoxUsingJson
  • Utf8StringDeliveryBox

ObjectDeliveryBoxUsingJson

ObjectDeliveryBoxUsingJsonはユーザーが定義した任意のUObjectクラスをJson形式の文字列に変換して送受信するためのDeliveryBoxです。

Unreal Engineで使用できるクラスはすべてがUObjectを継承しているので、多くのクラスインスタンスをそのまま送受信できます。

通信のメッセージをJson形式でやり取りするのは他のプログラム言語でも一般的な方法なので、これを利用して別のアプリケーションとメッセージの送受信をすることも可能です。

Utf8StringDeliveryBox

Utf8StringDeliveryBoxは任意の文字列をそのまま送受信するためのDeliveryBoxです。エンコードはUTF-8で実行されます。

FAQ

こちらでよくある質問を確認することができます