SOCKET-MANAGERを使った自作サーバー開発の手引き＜UNITパラメータクラスの実装＞

# はじめに

キューとUNITが通信状態のステータス管理を担っているのに対して、このクラスはデータドリブンによるステータス管理の役割を担い、専用のコマンドを使ってスキャフォールディングできます。

UNITの引数として渡されるこのクラスには送受信データスタックを操作するメソッド群が含まれており、UNITを跨ったグローバルコンテキストを制御します。

▼キューとUNITの詳細については以下の記事を参照。

https://qiita.com/glasses_seven/items/2f16c3ab748ccabe764d

<br />
UNIT内では主にこのインスタンスを使って通信処理を実装していく事になりますので、このクラスが制御する通信データの概要と代表的なメソッド群の詳細を以降の項目でご紹介しています。

<br />
<br />
基底クラスのまま利用する場合は特に新たなクラスを生成する必要はありませんが、例えばチャットサーバーのユーザーリストを管理したり、サーバー間通信で必要になる独自仕様の拡張を行いたいような場合に以下のコマンドを使って生成します。

```terminal:コマンド実行（ParameterForTestというクラス名を指定する場合）
> php worker craft:parameter ParameterForTest

[success] UNITパラメータクラスの生成に成功しました (ParameterForTest)
```

コマンドを実行する事で`app/UnitParameter`の場所に`ParameterForTest`というクラス名で`SocketManagerParameter`クラスを継承したUNITパラメータクラスが生成されます。


# 通信データの管理イメージ

このフレームワークでは送受信バッファとして確保しているスタックエリアの制御を行う事で通信データを操作します。

管理イメージは次の通りです。

![SOCKET-MANAGER Frameworkの通信データ管理イメージ](https://socket-manager.github.io/document/img/architecture/data_stack.png "SOCKET-MANAGER Frameworkの通信データ管理イメージ")

上の図の通り、このクラスはディスクリプタ（クライアント接続子）上のデータ制御と深く関わっています。
また、このようなFIFO方式のデータスタックの仕組みを活用する事で、送受信データの取りこぼしを防ぐことができます。

以降ではこのディスクリプタ上の操作を行う代表的なメソッドをご紹介します。


# スタックエリアの操作

ここではディスクリプタ上の送受信スタックエリアを操作するメソッドをご紹介します。

## ➤受信データの取得

コマンドディスパッチャーやコマンドUNITで受信データを取得する時に使います。

```php:シグネチャ
【メソッド】getRecvData(): mixed|null

【パラメータ】なし

【戻り値】mixed|null（データなし）
    - mixed: アンシリアライザーによって変換された最古の受信データ
    - null: 受信データなし
```

## ➤受信データのスタック

プロトコルUNITでデータを受信後、コマンドUNITで利用するためにスタックします。
シリアライザーによって変換された受信データがスタック領域にプッシュされます。

:::note info
プロトコル部ではシリアライズ化されているデータをそのまま渡す事ができます（内部で自動判別されます）。
プロセス間通信によって受信したデータをスタックしたい時も使えます。
:::

```php:シグネチャ
【メソッド】setRecvStack($p_data = null, ?bool $p_convert = null, ?string $p_cid = null): void

【パラメータ】
    $p_data    - mixed|null  - 任意 - スタックするデータ（データタイプは問わない）。デフォルトはnull
    $p_convert - bool|null   - 任意 - シリアライズ／アンシリアライズの行使フラグ（true：行使する、false：行使しない、デフォルト or null：自動判別）
    $p_cid     - string|null - 任意 - スタック先のクライアント（接続IDで指定）。デフォルト（null）は自分自身

【戻り値】なし
```

:::note info
第一パラメータはnullを許容するため「任意」となっていますが、基本的には第一パラメータの指定だけで問題ないでしょう。
:::

## ➤送信データのスタック

コマンドUNITでデータを送信する時にスタックします。
シリアライザーによって変換された送信データがスタック領域にプッシュされます。

:::note info
スタックされたデータはプロトコルUNITを通してクライアントへ送信されます。
プロセス間通信で送信するデータをスタックしたい時も使えます。
:::

```php:シグネチャ
【メソッド】setSendStack($p_data = null, ?string $p_cid = null): void

【パラメータ】
    $p_data    - mixed|null  - 任意 - スタックするデータ（データタイプは問わない）。デフォルトはnull
    $p_cid     - string|null - 任意 - スタック先のクライアント（接続IDで指定）。デフォルト（null）は自分自身

【戻り値】なし
```

:::note info
第一パラメータはnullを許容するため「任意」となっていますが、基本的には第一パラメータの指定だけで問題ないでしょう。
:::

## ➤全配信データのスタック

コマンドUNITで全クライアントへデータを送信する時にスタックします。
シリアライザーによって変換された送信データがスタック領域にプッシュされます。

:::note info
スタックされたデータはプロトコルUNITを通してクライアントへ送信されます。
プロセス間通信で送信するデータをスタックしたい時も使えます。
:::

```php:シグネチャ
【メソッド】setSendStackAll($p_data, bool $p_self_remove = false, $p_fnc = null, $p_param = null): void

【パラメータ】
    $p_data        - mixed      - 必須 - スタックするデータ（データタイプは問わない）
    $p_self_remove - bool       - 任意 - 自身のディスクリプタの除外フラグ（true：自身を除外する or false：自身を除外しない）
    $p_fnc         - mixed|null - 任意 - 処理対象の接続ID評価コールバック
        パラメータ:
            $p_param - SocketManagerParameter - 任意 - UNITパラメータクラスのインスタンス
                SocketManagerParameterクラスのgetConnectionId()メソッドで自身の接続IDを取得する事が可能。
                SocketManagerParameterクラスを継承したクラスを指定する事も可能。
        戻り値: bool（true：送信対象とする or false：送信対象としない）
                SocketManagerParameterクラスの
    $p_param       - mixed|null - 任意 - コールバックのパラメータ

【戻り値】なし
```

# ユーザー定義エリアの操作

ディスクリプタ上では送受信バッファ以外にもデベロッパーが自由定義できるユーザー定義エリアも確保しています。
ここではそのユーザー定義エリアを操作するメソッドをご紹介します。

## ➤ユーザー定義エリアのデータ追加／更新

コマンドディスパッチャーや各UNITで独自のデータを保持したい場合に使います。
指定されたプロパティのキーが存在しなければ追加し、存在していれば上書きします。

```php:シグネチャ
【メソッド】setTempBuff(array $p_prop, ?string $p_cid = null): void

【パラメータ】
    $p_prop - array       - 必須 - プロパティのリスト（連想配列で指定）
        例えばキーと値の関係で['test-data1' => 'テストデータ１', 'test-data2' => 'テストデータ２']のように複数指定可能
    $p_cid  - string|null - 任意 - 追加／更新先のクライアント（接続IDで指定）。デフォルト（null）は自分自身

【戻り値】なし
```

## ➤ユーザー定義エリアのデータ取得

コマンドディスパッチャーや各UNITで独自のデータを取得したい場合に使います。
取得対象プロパティのキーのリストを指定して複数取得できます。
一つでも対応するキーが存在しない場合はnullを返します。

```php:シグネチャ
【メソッド】getTempBuff(array $p_prop, ?string $p_cid = null): mixed

【パラメータ】
    $p_prop - array       - 必須 - プロパティのリスト（連想配列で指定）
        例えば['test-data1', 'test-data2']のように複数指定可能。
    $p_cid  - string|null - 任意 - 保存先のクライアント（接続IDで指定）。デフォルト（null）は自分自身

【戻り値】mixed|null
    - データが存在する場合: mixed
        例えば['test-data1', 'test-data2']と指定した場合、['test-data1' => 'テストデータ１', 'test-data2' => 'テストデータ２']のように返す。
    - データが存在しない場合: null
```


# プロトコルUNIT専用メソッド

通信データの性質上、必要なデータを一度に送受信できるとは限らないため、ここではポーリング送受信の処理をご紹介しています。

UNITパラメータクラス専用の`IProtocolParameter`インターフェースを介してメソッドチェーンでアクセスするため`$param->protocol()->メソッド名(パラメータ)`のように記述します。

なお、このメソッドをコマンドUNITで使おうとすると例外エラー（UnitExceptionEnum::ECODE_METHOD_CALL_FAIL）が発生しますのでご注意ください。

## ➤受信サイズの設定

シリアライズされた通信データをポーリングしながら受信する時の受信サイズを設定します。
データフォーマット上のペイロード長などを指定するために使います。

```php:シグネチャ
【メソッド】setReceivingSize(int $p_size): void

【パラメータ】
    $p_size - int - 必須 - 受信サイズ

【戻り値】なし
```

## ➤データ受信

シリアライズされた通信データをポーリングしながら受信する時に使用します。
`setReceivingSize`メソッドで設定されたサイズ分を受信するまでnullを返します。
データ長が設定されたペイロードデータなどを受信するために使います。

```php:シグネチャ
【メソッド】receiving(): mixed

【パラメータ】なし

【戻り値】mixed|null
    - 受信データが届いている場合: mixed
    - 受信データが届いていない場合: null
```

## ➤送信データの設定

シリアライズされた通信データをポーリングしながら送信する時の送信データを設定します。

```php:シグネチャ
【メソッド】setSendingData(string $p_data): void

【パラメータ】
    $p_data - string - 必須 - シリアライズされた送信データ

【戻り値】なし
```

## ➤データ送信

シリアライズされた通信データをポーリングしながら送信する時に使用します。
設定されたデータを送信完了するまでnullを返します。

```php:シグネチャ
【メソッド】sending(): mixed

【パラメータ】なし

【戻り値】true|null
    - 送信完了している場合: true
    - 送信中の場合: null
```


# おわりに

UNITパラメータクラスはデベロッパーによってインスタンス化され、初期化クラスの`getUnitParameter`メソッドの戻り値に設定される事で利用可能になり、各UNIT引数を通して渡されます。

つまりフレームワーク内でインスタンス化する事はないので、動的にメモリを圧迫するような心配はなくなります。

ここでご紹介したメソッド群は`SocketManagerParameter`クラスの一部分です。<a href="https://socket-manager.github.io/document/reference/">>> Reference</a>も合わせてご覧ください。