MRS API解説

本文書はMRSライブラリが提供する関数群の概要を説明します。
セットアップと動作確認,
関数リファレンス
も合わせてご活用ください。

MRS APIの概要

MRSは、バイナリデータを「レコード」と呼ぶ単位で送受信するためのC++ライブラリです。
リアルタイムゲームの実装に適した低遅延・高効率で動作するように設計されています。

利用可能なトランスポート層プロトコルはTCPとUDPで、
UDPを使う場合には再送機能や順序制御機能のあるモード(RUDP)とそうでない通常のUDPを使うモードを選択できます。

TCPとUDPのどちらでも、AES128を用いた暗号化通信を使うよう設定できます。
暗号の土台となる秘密鍵の交換には、ECDH(楕円曲線ディフィー・ヘルマン)アルゴリズムを利用します。
暗号化は送受信するレコードの単位で有効化・無効化を切り替えることができます。

MRSのC++ APIはクライアントとしてもサーバとしても利用でき、
Linux, MacOS, Windows, iOS, Androidなど各種のプラットフォームで動作します。

多くの言語向けのバインディングを提供するときの複雑なバグやAPIの仕様変更による動作不良を減らすため、外部APIは出来る限りC++の機能を使わず、C言語風の関数として構成されています。
ただし、内部的にはC++の機能を使っています。

MRS APIに含まれないもの

ゲームのデータをルームの参加メンバーで送受信するルームサーバーや、
チャット、ゲームマッチングなどの上位の機能については、
MRS APIには含まれません。それぞれ対応するドキュメントを参照してください。

またRPCを実装するためのシリアライズを行うためのスタブソースコードジェネレータは含みません。

MRS APIにおけるプロセスとスレッド

(TODO:内容を充実予定)

MRS APIはスレッドセーフではありません。
シングルスレッドプログラムで最大の効率が達成できるように、
マルチスレッド動作時の排他制御を実装していません。

MRS APIの最も小さい使用例

MRSはフレームワークではなくライブラリなので、
既存のアプリケーションコードに組み込んで使います。

main関数はアプリケーション側で定義し、
mrs_initialize()を呼び出してMRSを初期化し、
メインループで mrs_update()を呼び出し、
mrs_finalize()で終了処理を実行します。

以下は最小限のアプリケーションコードの例です。
動作するソースの全体は、サンプルの base_loop.cppを参照してください。

#include <mrs.hpp>
int main(){
    mrs_initialize();
    while(true) {
        mrs_update();
        mrs_sleep(1000);
    }
    mrs_finalize();
    return 0;
}     

上記の例ではMRSを用いた通信を行っていません。
通信をするためにはさらにいくつかの設定が必要です。

MRSで通信をするための初期化コード例

実際に通信をするソースの全体は、サンプルの echo_server.cppと、
echo_client.cppを参照してください。

TCPのサーバを開始するには、mrs_initialize()を呼び出した後、次のようにします。

MrsServer tcp_server = mrs_server_create( MRS_CONNECTION_TYPE_TCP, "0.0.0.0", 22222, 10 );

これだけでローカルアドレス"0.0.0.0", ポート番号22222,
listenバックログ10の設定でTCPサーバーが起動します。
ただしこのままでは、何の仕事も提供できません。

新しい接続を受け入れたこと(TCPソケットをacceptしたこと)を検出して仕事を開始するには、
tcp_serverにコールバック関数(on_new_connection_tcp)を登録します。

mrs_server_set_new_connection_callback( tcp_server, on_new_connection_tcp );                               

コールバック関数の実体はアプリケーションで定義します。
新しく受け入れたTCPソケットは、レコードを受信して通信をすることですから、
clientに対してレコードを一つ受信するごとに1回呼び出されるコールバック関数、
on_read_recordを、 mrs_set_read_record_callback関数を用いて設定します。

void on_new_connection_tcp( MrsServer server, void *server_data, MrsConnection client ){
    mrs_set_read_record_callback( client, on_read_record );
}     

on_read_record関数の実体は、やはりアプリケーションで定義します。

void on_read_record( MrsConnection connection, void *connection_data, uint32 seqnum, uint16 options, uint16 payload_type, const void* payload, uint32 payload_len ){
    switch ( payload_type ){                                                                                       
    case 0x01:
        mrs_write_record( connection, options, payload_type, payload, payload_len );                               
        break;
    default:
        break;
    }
}           

上記の例は、受信したパケットをそのまま正確に返信する、エコー(こだま)をするサーバーの例です。
mrs_write_record関数で受信したものとまったく同じ内容のレコードをconnectionに対して送出しています。

connection_dataは接続にひも付けられている任意のアプリケーションデータへのポインタ、
seqnumはレコードの通し番号、optionsは暗号化などのレコードの各種設定、
payload_typeはアプリケーションが規定の値の範囲で自由に定義する値で、キャラクターの同期なら0x10, 攻撃アクションなら0x11,
のように処理を分けるために使います。上記の例では 0x01だけを定義しています。
payloadはアプリケーションが自由に構成したバイナリデータの先頭アドレスへのポインタで、
これがレコードで送信するデータの中身になります。
payload_lenはpayloadの有効な長さを指定します。

上記のようにサーバーの設定をした後、サーバのメインループの中で mrs_update()関数を呼び出し続けることで、
サービスを継続します。
mrs_update()関数は、ソケットの状態を確認し、データを実際にシステムコールを呼び出して送信したり受信する処理を行います。

以上でエコーサーバーの実装は終わりです。

次はクライアント側のアプリケーションコードを見ます。

クライアント側では、サーバーへの接続を以下のようにして初期化します。

MrsConnection client = mrs_connect( MRS_CONNECTION_TYPE_TCP, "192.168.1.121", 22222, 10000 );

上記により、TCPクライアントをひとつ作り、IPv4アドレス 192.168.1.121、
ポート番号22222にタイムアウト10秒(1万ms)で接続処理を開始します。

サーバから送信されてきたレコードを受信するためには、次の例のように
サーバの場合と同様に、 mrs_set_read_record_callback関数を用いてコールバック関数を登録します。

mrs_set_read_record_callback( client, on_read_record );                                                    

また、クライアントのGUIでボタンが押されたときなどに、能動的にレコードをサーバに対して送信するためには、
サーバでも使用した mrs_write_record関数を使って任意のデータ(ペイロード)を送信します。

mrs_write_record( client, 0, 0x01, "hello", 5 );

上記の例では、clientに対して、オプションの値は0(暗号化無し)、
ペイロードタイプは0x01、データは文字列の "hello"、長さは5を送信しています。
ペイロードタイプに0x01を設定することで、
サーバ側のswitch文の case 0x01:に対応している部分で受信処理を書くことができます。

クライアント側での設定は以上です。 設定をしたあとは、
サーバと同様にメインループで mrs_update()関数を呼び出し続ければ、
レコードの送受信をすることができます。

C#版MRS APIについて

C#において、MRS APIを使用するには以下のクラス使用する、または派生したクラスを使用すると簡単に実装する事が可能になります。

// MRSクラス
public class Mrs{
    ...
}

以下のフォルダに配置されています。
mrs\sample\csharp\libmrs\Monobit\mrs\Mrs.cs

C++版とC#版との違い

Mrsクラス内でmrs.dllをDllImportして使用するため、C++版のMRS APIと使い勝手は変わりません。

ただし言語の違いがあるため、引数にあるポインタに関してはIntPtrに変更されています。


Copyright © 2019 MONOBIT ENGINE Inc.