本文書はMRSの開発環境を構築し、動作確認をする方法を説明します。
アーカイブ容量がかなり大きいため、
必要に応じて、
こちらよりダウンロードをお願いいたします。
Cocos2d-x版のドキュメントはアーカイブに同梱しております。
C++プロジェクトでMRSを使うには、ヘッダファイルをインクルードし、ライブラリファイルをリンクします。
組み込みに必要なファイルは以下の位置にあります。
パス | 概要 |
---|---|
mrs/include | C++用のmrsライブラリのヘッダファイルが格納されています |
mrs/library/mrs | C++用のライブラリファイルがプラットフォームごとに分けて格納されています |
OSの種類によりません。 mrs/include
ディレクトリの位置をコンパイラに設定してください。
以下のコードがコンパイルできたら問題ありません。
#include <mrs.hpp>
MRSが提供するライブラリと、それらが依存しているWindowsのライブラリの両方を設定する必要があります。
MRSが提供するライブラリは以下のものがあります。
リンカの入力ファイルに設定してください。
mrs/library/mrs/windows/enet_uv_openssl_1.1.1/{MSVSバージョン}/{MSVSランタイム}/$(Platform)/$(Configuration)/
mrs.lib
uv.lib
enet.lib
crypto.lib
ssl.lib
MRSが依存しているライブラリは以下のものがあります。
リンカの入力に設定してください。
Ws2_32.lib
psapi.lib
Iphlpapi.lib
Userenv.lib
winmm.lib
Advapi32.lib
Gdi32.lib
Crypt32.lib
また、コンパイル時に以下のオプションを定義してください。
/EHsc
以下の位置にあるライブラリファイルをリンク時に指定してください。
mrs/library/mrs/mac/{Macバージョン}/enet_uv_openssl_1.1.1/
libmrs.a
libuv.a
libenet.a
libcrypto.a
libssl.a
また、コンパイル時に以下のマクロを定義してください。
-DMRS_MAC
以下のライブラリファイルをリンク時に指定してください。
mrs/library/mrs/linux/{OS_GCCバージョン}/enet_uv_openssl_1.1.1/
libmrs.a
libuv.a
libenet.a
libcrypto.a
libssl.a
MRSが依存しているライブラリは以下のものがあります。
リンカの入力に設定してください。
pthread
rt
dl
また、以下のマクロをコンパイル時に定義してください。
-DMRS_LINUX
MRSの配布パッケージには、基本的な動作を確認できるソースが含まれています。
ソースはコンパイルすることもできるので、サンプルコードをコピーして開発を始めることも可能です。
サンプルコードは以下の位置にあります。
ソースコードのパス | 実行ファイル名 | 概要 |
---|---|---|
mrs/sample/cpp/source/base_loop.cpp | base_loop | C++用のmrsライブラリの基本のサンプル |
mrs/sample/cpp/source/log.cpp | log | C++用のmrsライブラリのログ出力のサンプル |
mrs/sample/cpp/source/echo_server.cpp | echo_server | C++用のmrsライブラリのエコーサーバーのサンプル |
mrs/sample/cpp/source/echo_client.cpp | echo_client | C++用のmrsライブラリのエコークライアントのサンプル |
それぞれのサンプルコードの使い方は、以下の通りです。
ビルド済みの実行ファイルの位置は、OSごとに以下の位置に分けて配置されています。
mrs/sample/cpp/build/
mrs/sample/cpp/build/windows/
スクリプト名 | 概要 |
---|---|
setup_dev.sh | 開発環境に必要なパッケージをインストール |
setup_ops.sh | 運用環境に必要なパッケージをインストール |
setup_timezone.sh | 指定されたタイムゾーンを設定 |
上記スクリプトを必要に応じて実行することで、MRSに必要な環境構築を行います。
./setup_dev.sh
./setup_ops.sh
./setup_timezone.sh Asia/Tokyo
cd mrs/sample/cpp/build
MRS_PLATFORM_TYPE=mac MRS_PLATFORM_VERSION=10.12 ./cmake.sh
make clean all
上記を実行すると、mrs/sample/cpp/build以下に、base_loopなど実行ファイルが生成されます。
cd mrs/sample/cpp/build
MRS_PLATFORM_TYPE=linux MRS_PLATFORM_VERSION=centos7_4.8.5 ./cmake.sh
make clean all
上記を実行すると、mrs/sample/cpp/build以下に、base_loopなど実行ファイルが生成されます。
cd mrs/sample/cpp/build
MRS_PLATFORM_TYPE=windows MRS_PLATFORM_VERSION=2017 ./cmake.sh
上記を実行すると、mrs/sample/cpp/build/windows以下に、2017_MT_x64_Release/mrs_sample.slnなどのファイルが生成されます。
echo_serverと echo_clientは、ゲームサーバー開発の起点となるプログラムです。
ここでは動作確認の方法を詳しく説明します。
コマンドライン引数の意味は次の通りです。
./echo_server <スリープ時間(ミリ秒)> <サーバーのアドレス> <サーバーのポート番号> <バックログ数> <レコードによる送受信を行うかどうか>
標準出力の例
$ ./echo_server
arg 01: sleep_msec [1]
arg 02: server_addr [0.0.0.0]
arg 03: server_port [22222]
arg 04: backlog [10]
arg 05: is_valid_record(OFF:0 ON:1) [1]
sleep_msec=1 server_addr=0.0.0.0 server_port=22222 backlog=10 arg_is_valid_record=1
TCP listening on 0.0.0.0 22222
UDP waiting on 0.0.0.0 22222
WS listening on 0.0.0.0 22223
WSS listening on 0.0.0.0 22224
TCP_SSL listening on 0.0.0.0 22225
MRU waiting on 0.0.0.0 22226
コマンドライン引数の意味は次の通りです。
./echo_client <コネクションタイプ> <鍵交換フラグ> <レコード暗号フラグ> <送信データ長> <送信レコード数> <送信コネクション数> <スリープ時間(ミリ秒)> <サーバーのアドレス> <サーバーのポート番号> <タイムアウト時間(ミリ秒)> <レコードによる送受信を行うかどうか> <WS|WSS接続時に指定するパス>
echo_clientは、echo_serverを起動した後に起動してください。
通信を始めると、以下のフォーマットでログが出力されます。
read_echo data=TCP NOCRYPT <コネクション番号>: <レコード番号> data_len=1024 diff_time=<遅延時間(秒.マイクロ秒)>(<受信時間> - <送信時間>)
標準出力の例
$ ./echo_client 1 1 0
arg 01: connection_type(TCP:1 UDP:2 WS:3 WSS:4 TCP_SSL:5 MRU:6 TCP -> WSS -> WS:*) [1]
arg 02: is_key_exchange(OFF:0 ON:1) [1]
arg 03: is_encrypt_records(OFF:0 ON:1) [1]
arg 04: write_data_len [1024]
arg 05: write_count [10]
arg 06: connections [1]
arg 07: sleep_msec [1]
arg 08: server_addr [127.0.0.1]
arg 09: server_port [22222]
arg 10: timeout_msec [5000]
arg 11: is_valid_record(OFF:0 ON:1) [1]
arg 12: connection_path [/]
connection_type=1 is_key_exchange=1 is_encrypt_records=0 write_data_len=1024 write_count=10 connections=1 sleep_msec=1 server_addr=127.0.0.1 server_port=22222 timeout_msec=5000 is_valid_record=1 connection_path=/
on_fallback_connect connection_type=1 addr=127.0.0.1 port=22222 timeout_msec=5000
on_connect local_mrs_version=0x2000000 remote_mrs_version=0x2000000
on_key_exchange
parse_record seqnum=3 options=0x00 payload=0x01/1036
read_echo data=TCP NOCRYPT 1: 1 data_len=1024 diff_time=0.000122(1567480792.207487 - 1567480792.207365)
parse_record seqnum=4 options=0x00 payload=0x01/1036
read_echo data=TCP NOCRYPT 1: 2 data_len=1024 diff_time=0.001563(1567480792.208944 - 1567480792.207381)
parse_record seqnum=5 options=0x00 payload=0x01/1036
read_echo data=TCP NOCRYPT 1: 3 data_len=1024 diff_time=0.001571(1567480792.208959 - 1567480792.207388)
parse_record seqnum=6 options=0x00 payload=0x01/1036
read_echo data=TCP NOCRYPT 1: 4 data_len=1024 diff_time=0.001575(1567480792.208969 - 1567480792.207394)
parse_record seqnum=7 options=0x00 payload=0x01/1036
read_echo data=TCP NOCRYPT 1: 5 data_len=1024 diff_time=0.001578(1567480792.208978 - 1567480792.207400)
parse_record seqnum=8 options=0x00 payload=0x01/1036
read_echo data=TCP NOCRYPT 1: 6 data_len=1024 diff_time=0.001573(1567480792.208984 - 1567480792.207411)
parse_record seqnum=9 options=0x00 payload=0x01/1036
read_echo data=TCP NOCRYPT 1: 7 data_len=1024 diff_time=0.001569(1567480792.208990 - 1567480792.207421)
parse_record seqnum=10 options=0x00 payload=0x01/1036
read_echo data=TCP NOCRYPT 1: 8 data_len=1024 diff_time=0.001569(1567480792.208996 - 1567480792.207427)
parse_record seqnum=11 options=0x00 payload=0x01/1036
read_echo data=TCP NOCRYPT 1: 9 data_len=1024 diff_time=0.001570(1567480792.209002 - 1567480792.207432)
parse_record seqnum=12 options=0x00 payload=0x01/1036
read_echo data=TCP NOCRYPT 1: 10 data_len=1024 diff_time=0.001569(1567480792.209009 - 1567480792.207440)
Since all records have been received, it is finished.
on_disconnect local_mrs_version=0x2000000 remote_mrs_version=0x2000000
通信が始まると、以下のフォーマットでログが出力されます。
read_echo data=TCP CRYPT <コネクション番号>: <レコード番号> data_len=1024 diff_time=<遅延時間(秒.マイクロ秒)>(<受信時間> - <送信時間>)
標準出力の例
$ ./echo_client 1 1 1
arg 01: connection_type(TCP:1 UDP:2 WS:3 WSS:4 TCP_SSL:5 MRU:6 TCP -> WSS -> WS:*) [1]
arg 02: is_key_exchange(OFF:0 ON:1) [1]
arg 03: is_encrypt_records(OFF:0 ON:1) [1]
arg 04: write_data_len [1024]
arg 05: write_count [10]
arg 06: connections [1]
arg 07: sleep_msec [1]
arg 08: server_addr [127.0.0.1]
arg 09: server_port [22222]
arg 10: timeout_msec [5000]
arg 11: is_valid_record(OFF:0 ON:1) [1]
arg 12: connection_path [/]
connection_type=1 is_key_exchange=1 is_encrypt_records=1 write_data_len=1024 write_count=10 connections=1 sleep_msec=1 server_addr=127.0.0.1 server_port=22222 timeout_msec=5000 is_valid_record=1 connection_path=/
on_fallback_connect connection_type=1 addr=127.0.0.1 port=22222 timeout_msec=5000
on_connect local_mrs_version=0x2000000 remote_mrs_version=0x2000000
on_key_exchange
parse_record seqnum=3 options=0x01 payload=0x01/1036
read_echo data=TCP CRYPT 1: 1 data_len=1024 diff_time=0.000461(1567480796.171236 - 1567480796.170775)
parse_record seqnum=4 options=0x01 payload=0x01/1036
read_echo data=TCP CRYPT 1: 2 data_len=1024 diff_time=0.000449(1567480796.171266 - 1567480796.170817)
parse_record seqnum=5 options=0x01 payload=0x01/1036
read_echo data=TCP CRYPT 1: 3 data_len=1024 diff_time=0.000461(1567480796.171309 - 1567480796.170848)
parse_record seqnum=6 options=0x01 payload=0x01/1036
read_echo data=TCP CRYPT 1: 4 data_len=1024 diff_time=0.000433(1567480796.171329 - 1567480796.170896)
parse_record seqnum=7 options=0x01 payload=0x01/1036
read_echo data=TCP CRYPT 1: 5 data_len=1024 diff_time=0.000383(1567480796.171345 - 1567480796.170962)
parse_record seqnum=8 options=0x01 payload=0x01/1036
read_echo data=TCP CRYPT 1: 6 data_len=1024 diff_time=0.003025(1567480796.174018 - 1567480796.170993)
parse_record seqnum=9 options=0x01 payload=0x01/1036
read_echo data=TCP CRYPT 1: 7 data_len=1024 diff_time=0.002997(1567480796.174040 - 1567480796.171043)
parse_record seqnum=10 options=0x01 payload=0x01/1036
read_echo data=TCP CRYPT 1: 8 data_len=1024 diff_time=0.002986(1567480796.174058 - 1567480796.171072)
parse_record seqnum=11 options=0x01 payload=0x01/1036
read_echo data=TCP CRYPT 1: 9 data_len=1024 diff_time=0.002949(1567480796.174075 - 1567480796.171126)
parse_record seqnum=12 options=0x01 payload=0x01/1036
read_echo data=TCP CRYPT 1: 10 data_len=1024 diff_time=0.002929(1567480796.174092 - 1567480796.171163)
Since all records have been received, it is finished.
on_disconnect local_mrs_version=0x2000000 remote_mrs_version=0x2000000
各サンプルプログラムがどの程度の量のメモリやCPUを使用しているかは、ps コマンドで知ることが可能です。
以下を参考にしてください。
http://qiita.com/white_aspara25/items/cfc835006ae356189df3
実際の例
$ ps aux | grep echo
3017 4.4 0.6 21092 3220 pts/0 S+ 21:00 0:01 ./echo_server
3019 4.2 0.4 20036 2196 pts/1 S+ 21:01 0:01 ./echo_client
C#プロジェクトにMRSを使うには、まずC#フレームワークを選択します。
フレームワーク | 概要 |
---|---|
.NET Core 2.0以降 | マルチプラットフォームのC#フレームワーク。推奨フレームワークです。サンプルプログラムではこちらを使用しています。 |
.NET Framework | Windows専用のフレームワークです。Windowsでのみ使用するならこちらを選択します。 |
ここでは推奨フレームワークである.NET Coreのバージョン2.1系を用いて説明していきます。
以下のサイトから各プラットフォームに.NET Core SDKをダウンロードして、インストールしてください。
https://github.com/dotnet/core/blob/master/release-notes/2.1/2.1.12/2.1.12-download.md
CentOS上でのインストール方法については、以下のシェルを実行してください。
mrs\sample\csharp\netcoreapp2.1\script\inst.h
$ sh inst.sh
最新版の.NET Coreを使用する場合などは、以下を参考にしてください。
上記のシェル内に記述されている.NET Coreのバージョンを変更すればインストールが可能です。
https://github.com/dotnet/core/blob/master/release-notes/2.2/2.2.6/2.2.6-download.md
.NET Core 2.0以降においては、VisualStudio 2017以降を使用してプロジェクトを作成します。
「ファイル」→「新規作成」→「プロジェクト」でプロジェクト作成ダイアログを開き、
「Visual C#」→「.NET Core」→「コンソール アプリ(.NET Core)」を選択してプロジェクト作成を作成します。
空プロジェクトを作成すると、プロジェクトファイル内は以下のような内容で作成されます。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
</Project>
プロジェクトのビルドイベントで、ファイルコピーなどを行う事があります。(mrs.dllなど)
Linux上でシェルを実行した際に、コピーのエラーの元となりますので、LinuxとWindowsではプロジェクトを分けておくと便利です。
.NET Coreを使用してのビルド&実行の手順です。
尚コマンドは、Windowsのバッチ処理や、Linux上のシェルからも同じ構文となります。
.NET Coreを使用してのビルドコマンドは以下の通りになります。
dotnet restore {プロジェクト名}.csproj
dotnet publish {プロジェクト名}.csproj --configuration {Debug|Release}
dotnetコマンドではpublishを指定してビルドしています。これはpublishを指定すると、特定フォルダに実行に必要なファイル一式がコピーされ、ビルド後にフォルダを移動しても実行できるからです。
.NET Coreを使用しての実行コマンドは以下の通りになります。
出力フォルダがデフォルトでDebugビルドの場合
dotnet bin/Debug/netcoreapp2.1/publish/{プロジェクト名}.dll
プロジェクトを選択しても実行できます
dotnet run {プロジェクト名}.csproj --configuration {Debug|Release}
ここまでで.NET Core2.1のプロジェクトを作成しましたので、次はMRSクラスライブラリを組み込んでいきます。
パス | 概要 |
---|---|
mrs\sample\csharp\libmrs\Monobit\mrs | MRS用のクラスライブラリが入っています。 |
mrs\sample\csharp\netcoreapp2.1\2017 | 各フォルダにはC#用のサンプルアプリのプロジェクトファイルやビルド&実行スクリプトが入っています。 |
mrs\sample\csharp\source | C#用のサンプルアプリのソースコードが入っています。 |
MRSクラスライブラリを参照するために、プロジェクトに参照パスを追加します。
MRSクラスライブラリでは高速化のためにunsafeコードを使っていますので、
PropertyGroupの中でunsafeコードの許可も同時にプロジェクトに追加しておきます。
最後にビルド後のイベントとして、PostBuildEventにてmrs.dllをパッケージよりコピーしてきます。
mrs.dllはVisualStudio 2015でビルドされたもので問題ありません。
但し、このコピーコマンドを入れるとLinux上では当然のようにエラーが表示されます。
そのためPostBuildEventを省いたLinux版のプロジェクトファイルを作っておくと便利です。
下記の例では、サンプルアプリのフォルダ位置と同列の場所にWindows版のプロジェクトファイルを作成している例となります。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\..\source\base_loop.cs" />
<Compile Include="..\..\libmrs\Monobit\mrs\Mrs.cs" />
<Compile Include="..\..\libmrs\Monobit\mrs\MrsBuffer.cs" />
<Compile Include="..\..\libmrs\Monobit\mrs\MrsDateTime.cs" />
<Compile Include="..\..\libmrs\Monobit\mrs\MrsTime.cs" />
<Compile Include="..\..\libmrs\Monobit\mrs\MrsUtility.cs" />
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="copy $(ProjectDir)..\..\..\..\..\library\mrs\windows\enet_uv_openssl_1.1.1\2017\MT\x64\$(ConfigurationName) $(OutDir)
" />
</Target>
</Project>
C++版同様にサンプルコードをコピーして開発を始めることが可能です。
サンプルコードは以下の位置にあります。
パス | 概要 |
---|---|
mrs\sample\csharp\source\base_loop.cs | C#用のmrsライブラリの基本のサンプル |
mrs\sample\csharp\source\base_server.cs | C#用のmrsライブラリ+プラットフォーム共通シグナル基本処理 |
mrs\sample\csharp\source\base_server_linux.cs | C#用のmrsライブラリ+Linux用シグナル基本処理 |
mrs\sample\csharp\source\base_server_win.cs | C#用のmrsライブラリ+Windows用シグナル基本処理 |
mrs\sample\csharp\source\echo_client.cs | C#用のmrsライブラリのエコーサーバーのサンプル |
mrs\sample\csharp\source\echo_server.cs | C#用のmrsライブラリのエコークライアントのサンプル |
mrs\sample\csharp\source\log.cs | C#用のmrsライブラリのログ出力のサンプル |
基本的にC++版サンプルコードの使い方に準じます。
但し、実行コマンドが異なるので注意が必要です。
上記に実行コマンドを説明していますので、参照してください。
実行コマンド以外では、引数の指定方法が違います。
例としてecho_serverの引数の指定方法を説明します。
dotnet bin/Debug/netcoreapp2.1/publish/echo_server.dll --sleep_msec=1 --server_addr="0.0.0.0" --server_port=22222 --backlog=10
.NET Coreでは、C++と違いOSからのシグナル処理の対応がプラットフォーム間においてまちまちです。
その為、MRSにおいてはプラットフォーム間のシグナル処理を吸収した便利クラスがありますので、
実装のお役に立ててください。
・ExitSignalの使い方
using()内で使用します。
以下のようにSetSignal()で設定したハンドラ内でループフラグをOFFにして、
正常にループを終了させる事ができます。
using System.Threading;
using MrsLibs.Signal
class Hoge
{
private static volatile bool s_bIsRun = true;
publib static void Main(string[] args)
{
using(var sig = new ExitSignal())
{
sig.SetSignal((obj, e) => {
var ev_arg = e as SignalEventArgs;
Console.WriteLine($"Event: {event_args.SignalEnums}");
s_bIsRun = false;
Thread.Sleep(10);
});
while(s_bIsRun)
{
// ループ処理
...
}
}
}
}
ちなみに名前空間のMrsLibsは、
mrs/sample/csharp/source/base_libs.cs
に定義されています。