はじめに
初期化クラスは、サーバー起動時に必要なデータ(UNITパラメータインスタンス)や処理(ログライター、シリアライザー/アンシリアライザー、コマンドディスパッチャー、緊急停止コールバック)を読み込むための実装を行うところで、専用のコマンドを使ってスキャフォールディングできます。
初期化クラスを生成するコマンドは以下の通り。
> php worker craft:init InitForTest
[success] 初期化クラスの生成に成功しました (InitForTest)
コマンドを実行する事でapp/InitClass
の場所にInitForTest
というクラス名でIInitSocketManager
インターフェイスをimplementsした初期化クラスが生成されます。
以降では生成されたクラス内で実装が必要なインターフェイスメソッドの内訳を見ていきます。
➤ログライター
error_logの標準関数やLoggerなどの有名なライブラリを使ってログを出力する事ができます。
イベントハンドラ(UNIT)内ではパラメータ経由で使いますので
$param->logWriter('debug', ['メッセージ受信' => $message])
のように記述します。
【メソッド】getLogWriter(): Closure|string|null
【パラメータ】なし
【戻り値】
Closure|string|null
- ログ出力を行う場合: Closure
パラメータ:
$p_level - string - 必須 - ログレベル
現状では以下のレベルが定義されています。
debug
info
notice
warning
error
$p_param - array - 必須 - 出力内容
連想配列の形式で以下のように指定します。
['メッセージ受信' => $message]
戻り値: void
- ログ出力を行う場合: string
ヘルパー関数などの関数名
- ログ出力を行わない場合: null
public function getLogWriter()
{
return function(string $p_level, array $p_param)
{
// ファイル名を設定
$filename = date('Ymd');
// 現在日付を含むログ内容を作成
$now = date('Y-m-d H:i:s');
$log = $now." {$p_level} ".print_r($p_param, true)."\n";
// ログ出力(カレントパスはプロジェクトルートになる)
error_log($log, 3, "./logs/socket-manager-log/{$filename}.log");
};
}
カレントパスはプロジェクトルートになるので./logs/debug.log
のように指定します。
このメソッドはフレームワークのライブラリからもコールされますので、イベントハンドラのログも含めて時系列で出力されます。
➤シリアライザー
送信するデータをシリアライズするためのメソッドを実装します。
【メソッド】getSerializer(): Closure|string|null
【パラメータ】なし
【戻り値】
Closure|string|null
- シリアライズを行う場合: Closure
パラメータ:
$p_data - mixed - 必須 - 送信データ
イベントハンドラで設定された送信データがそのまま渡されます。
戻り値: mixed
シリアライズ後のデータ
- シリアライズを行う場合: string
ヘルパー関数などの関数名
- シリアライズを行わない場合: null
public function getSerializer()
{
return function($p_data)
{
return json_encode($p_data);
};
}
シリアライザーはデータ送信時にライブラリから自動でコールされます。
Websocketサーバーとして使う場合はJSON形式で使うのがいいでしょう。
通信データ量を減らすためにバイナリデータを扱う事も可能です。
➤アンシリアライザー
受信データを取得する時にアンシリアライズするためのメソッドを実装します。
【メソッド】getUnserializer(): Closure|string|null
【パラメータ】なし
【戻り値】
Closure|string|null
- アンシリアライズを行う場合: Closure
パラメータ:
$p_data - mixed - 必須 - 受信データ
シリアライズされている受信データがそのまま渡されます。
戻り値: mixed
アンシリアライズ後のデータ
- アンシリアライズを行う場合: string
ヘルパー関数などの関数名
- アンシリアライズを行わない場合: null
public function getUnserializer()
{
return function($p_data)
{
return json_decode($p_data, true);
};
}
アンシリアライザーは受信データ取得時にライブラリから自動でコールされます。
Websocketサーバーとして使う場合はJSON形式で使うのがいいでしょう。
通信データ量を減らすためにバイナリデータを扱う事も可能です。
➤コマンドディスパッチャー
受信データを受け取った時に呼び出され、そのデータを解析した上でサーバーコンテンツ(コマンドUNIT)上の適切なイベントハンドラを呼び出すためのルーティングの役割を果たします。
コマンドディスパッチャーからは、ルーティングするキュー名を返す事でイベントハンドラを呼び出す事ができます。
【メソッド】getCommandDispatcher(): Closure|string|null
【パラメータ】なし
【戻り値】
Closure|string|null
- コマンドディスパッチャーを使う場合: Closure
パラメータ:
$p_param - SocketManagerParameter - 必須 - UNITパラメータクラスのインスタンス
各イベントハンドラで共通の引数として使用されるインスタンス。
SocketManagerParameterクラスを継承した拡張クラスを指定する事も可能。
$p_dat - mixed - 必須 - 受信データ
アンシリアライズ化された受信データがそのまま渡されます。
戻り値: string
ルーティングするキュー名
- コマンドディスパッチャーを使う場合: string
ヘルパー関数などの関数名
- コマンドディスパッチャーを使わない場合: null
public function getCommandDispatcher()
{
return function(SocketManagerParameter $p_param, $p_dat): ?string
{
// コマンド部のキュー名と一致している必要があります
return $p_dat['command'];
};
}
➤緊急切断コールバック
クライアントとの接続が維持できなくなった時に呼び出されるコールバックメソッドを実装します。
例えば以下の場面で呼び出されます。
- アライブチェック処理のタイムアウト
- コマンドディスパッチャーでの例外発生
- 相手先による強制切断
【メソッド】getEmergencyCallback(): Closure|string|null
【パラメータ】なし
【戻り値】
Closure|string|null
- 緊急切断コールバックを使う場合: Closure
パラメータ:
$p_param - SocketManagerParameter - 必須 - UNITパラメータクラスのインスタンス
各イベントハンドラで共通の引数として使用されるインスタンス。
SocketManagerParameterクラスを継承した拡張クラスを指定する事も可能。
戻り値: mixed
シリアライズ後のデータ
- 緊急切断コールバックを使う場合: string
ヘルパー関数などの関数名
- 緊急切断コールバックを使わない場合: null
public function getEmergencyCallback()
{
return function(SocketManagerParameter $p_param)
{
// 送信データを作成
$send_data = [];
$send_data['command'] = 'close';
$send_data['message'] = '切断されました';
$send_data['connection_id'] = $p_param->getConnectionId(); // 接続IDを取得
// 全員へ配信(第二パラメータがtrueの場合は自身を除く)
$p_param->setSendStackAll($send_data, true);
};
}
➤UNITパラメータインスタンス
UNITとしてのイベントハンドラを実行する時に渡されるUNITパラメータクラスのインスタンスを指定します。
基底クラスであるSocketManagerParameter
クラスのインスタンスがデフォルトで指定されていますが、このクラスを継承した拡張クラスを使用する場合はそのインスタンスを戻り値に指定する必要があります。
ここで指定したインスタンスはそのままUNITの引数として使われますので、動的に増殖してメモリを圧迫する心配はありません。
【メソッド】getUnitParameter(): SocketManagerParameter|null
【パラメータ】なし
【戻り値】SocketManagerParameter|null
- UNITパラメータクラスを使う場合: SocketManagerParameter
各イベントハンドラで共通の引数として使用されるインスタンス。
SocketManagerParameterクラスを継承した拡張クラスを指定する事も可能。
- UNITパラメータクラスを使わない場合: null
public function getUnitParameter(): ?SocketManagerParameter
{
return new SocketManagerParameter();
}
▼UNITパラメータクラスについての詳細は以下の記事をご覧ください。
おわりに
生成されたクラスのインスタンスは、メイン処理クラス内で以下のメソッドに引き渡す事で適用されます。
$manager->setInitSocketManager()
複数の初期化クラスやメイン処理クラスを用意している場合は、サーバーの実装内容によって最適なインスタンスを動的、あるいは静的に適用する事で柔軟なサーバー構築が可能になります。