-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprotocol-unit.html
More file actions
503 lines (411 loc) · 27.2 KB
/
protocol-unit.html
File metadata and controls
503 lines (411 loc) · 27.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>プロトコルUNITクラスの実装 | SOCKET-MANAGER Framework For PHP</title>
<meta name="description" content="SOCKET-MANAGERフレームワークでのプロトコルUNIT実装方法を解説。通信プロトコル上の基本的な送受信データの実装例、イベントハンドラの定義方法、キューとステータスUNITの活用方法を具体的なコード例と共に紹介。" />
<meta content="PHP,ソケット通信,サーバー開発,framework,IPC,ソケットマネージャー" name="keywords">
<link rel="canonical" href="https://socket-manager.github.io/document/protocol-unit.html" />
<script async src="https://www.googletagmanager.com/gtag/js?id=G-LF9W695NNW"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-LF9W695NNW');
</script>
<link rel="icon" href="https://socket-manager.github.io/document/favicon.ico" type="image/x-icon" />
<link type="text/css" rel="stylesheet" href="./css/common.css" media="all" />
<script src="./js/jquery-3.7.1.min.js"></script>
<script type="text/javascript" src="./js/common.js"></script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "TechArticle",
"headline": "SOCKET-MANAGER Framework - プロトコルUNITクラスの実装ガイド",
"description": "SOCKET-MANAGERフレームワークにおけるプロトコルUNITクラスの実装方法を解説。通信プロトコル上の基本的な送受信データの実装例、イベントハンドラの定義方法、キューとステータスUNITの活用方法を具体的なコード例と共に紹介。",
"keywords": "PHP, ソケット通信, プロトコル実装, 非同期処理, ソケットマネージャー",
"articleSection": ["Technical Documentation", "Server Development", "PHP Programming"],
"author": {
"@type": "Person",
"name": "SOCKET-MANAGER開発チーム"
},
"publisher": {
"@type": "Organization",
"name": "SOCKET-MANAGER",
"logo": {
"@type": "ImageObject",
"url": "https://socket-manager.github.io/document/logo.png",
"width": 355,
"height": 50
}
},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://socket-manager.github.io/document/protocol-unit.html"
},
"url": "https://socket-manager.github.io/document/protocol-unit.html",
"breadcrumb": {
"@type": "BreadcrumbList",
"itemListElement": [{
"@type": "ListItem",
"position": 1,
"name": "Framework Top",
"item": "https://socket-manager.github.io/document/"
},{
"@type": "ListItem",
"position": 2,
"name": "プロトコルUNITクラスの実装",
"item": "https://socket-manager.github.io/document/protocol-unit.html"
}]
},
"isPartOf": {
"@type": "WebSite",
"name": "フレームワークのご紹介",
"url": "https://socket-manager.github.io/document/"
}
}
</script>
</head>
<body>
<div class="layout">
<div class="menu" role="navigation" aria-label="ページメニュー">
<h2 class="menu-title">SOCKET-MANAGER</h2>
<h4 class="menu-reference menu-page-title-bottom"><a href="./reference/" target="_blank">>> Reference</a></h4>
<h2 class="menu-label">MAIN-MENU</h2>
<div class="menu-text">
<h3 class="menu-page-title-link"><a href="./">▶フレームワークのご紹介</a></h3>
<h3 class="menu-page-title-link"><a href="./event-handler.html">▶イベントハンドラについて</a></h3>
</div>
<h3 class="menu-label-sub">IMPLEMENT</h3>
<div class="menu-text">
<h3 class="menu-page-title-link"><a href="./init-class.html">▶初期化クラス</a></h3>
<h3 class="menu-page-title-link"><a href="./unit-parameter.html">▶UNITパラメータクラス</a></h3>
<h3 class="menu-page-title">▼プロトコルUNITクラス</h3>
<ul>
<li><a href="./protocol-unit.html#begin">はじめに</a></li>
</ul>
<ul>
<li><a href="./protocol-unit.html#enum-queue">キュー名の定義</a></li>
</ul>
<ul>
<li><a href="./protocol-unit.html#enum-status">ステータス名の定義</a></li>
</ul>
<ul>
<li><a href="./protocol-unit.html#implement">プロトコルUNITクラスの実装</a></li>
</ul>
<ul>
<li><a href="./protocol-unit.html#last">おわりに</a></li>
</ul>
<h3 class="menu-page-title-link"><a href="./command-unit.html">▶コマンドUNITクラス</a></h3>
<h3 class="menu-page-title-link"><a href="./main.html">▶メイン処理クラス</a></h3>
<h3 class="menu-page-title-link"><a href="./setting.html">▶設定ファイル</a></h3>
<h3 class="menu-page-title-link"><a href="./message.html">▶メッセージファイル</a></h3>
</div>
<div class="menu-line"></div>
<div class="menu-text">
<h3 class="menu-page-title-link-for-runtime-manager"><a href="./runtime-manager/" target="_blank">>> ランタイムライブラリ</a></h3>
<h3 class="menu-page-title-link-for-runtime-manager"><a href="./simple-socket/" target="_blank">>> シンプルソケット機能</a></h3>
</div>
<h3 class="menu-label-sub">ADVANCED</h3>
<div class="menu-text">
<h3 class="menu-page-title-link"><a href="./architecture.html">▶アーキテクチャ</a></h3>
<h3 class="menu-page-title-link"><a href="./event.html">▶イベント駆動アーキテクチャ</a></h3>
<h3 class="menu-page-title-link"><a href="./ipc.html">▶IPC(プロセス間通信)</a></h3>
<h3 class="menu-page-title-link"><a href="./multi-server.html">▶マルチサーバーの構成</a></h3>
<h3 class="menu-page-title-link"><a href="./tcp-and-udp.html">▶TCP/UDP通信について</a></h3>
<h3 class="menu-page-title-link"><a href="./laravel.html">▶Laravelと連携する</a></h3>
<h3 class="menu-page-title-link"><a href="./system-setting.html">▶システム設定ファイル</a></h3>
<h3 class="menu-page-title-link"><a href="./custom-command.html">▶カスタムコマンド作成機能</a></h3>
</div>
<h3 class="menu-label-sub">OTHER-PROJECT</h3>
<div class="menu-text">
<h3 class="menu-page-title-link"><a href="./new-project.html">▶新規開発環境</a></h3>
<h3 class="menu-page-title-link"><a href="./websocket.html">▶Websocketサーバー開発環境</a></h3>
<h3 class="menu-page-title-link"><a href="./dev-ops.html">▶フレームワークのDevOps環境</a></h3>
</div>
<div class="menu-line"></div>
<div class="menu-text">
<h3 class="menu-page-title-link-for-minecraft"><a href="./minecraft-contents/" target="_blank">>> マインクラフト専用環境</a></h3>
<h3 class="menu-page-title-link-for-launcher"><a href="./launcher/" target="_blank">>> GUI & CLI ランチャー</a></h3>
<h3 class="menu-page-title-link-for-rest-api"><a href="./rest-api/" target="_blank">>> REST-APIサーバー開発環境</a></h3>
</div>
<h2 class="menu-label">EXTRA-MENU</h2>
<div class="menu-text">
<h3 class="menu-page-title-link"><a href="./extra-demo.html">▶デモサーバーの種類</a></h3>
<h3 class="menu-page-title-link"><a href="./extra-demo-command.html">▶デモのコマンド仕様</a></h3>
<h3 class="menu-page-title-link"><a href="./extra-demo-setting.html">▶デモの設定ファイル</a></h3>
<h3 class="menu-page-title-link"><a href="./extra-minecraft.html">▶マインクラフトの通信仕様</a></h3>
<h3 class="menu-page-title-link"><a href="./extra-close-frame.html">▶切断フレームの検証</a></h3>
</div>
<h2 class="menu-label">PHP-TECHNIQUE</h2>
<div class="menu-text">
<h3 class="menu-page-title-link"><a href="./php-pass-by-reference.html">▶参照渡し</a></h3>
<h3 class="menu-page-title-link"><a href="./php-phpdoc.html">▶PHPDocのフォーマット</a></h3>
</div>
<div class="menu-dummy-for-framework"></div>
</div>
<div class="main" role="main">
<h1>【プロトコルUNITクラスの実装】</h1>
<a id="begin"></a>
<h2 class="subtitle">はじめに</h2>
<div class="text-block">
本フレームワークでは、通信プロトコル層を抽象化したインターフェースを採用しており、TCPやUDPなどのトランスポートプロトコルを柔軟に切り替えられる構成になっています。<br />
これにより、開発時や運用時に用途に応じたプロトコル選択が可能です。<br /><br />
さらに、プロトコル処理のスキャフォールディング(コード自動生成)機能も備えており、テンプレートベースでの開発を通じて、高い拡張性と保守性を確保しながら、実装作業の効率化を実現します。<br /><br />
プロトコルUNITクラスを生成するコマンドは以下の通り。<br />
<pre color-change="command" aria-label="コマンド実行(ProtocolForTestというクラス名を指定する場合)">
> php worker craft:protocol ProtocolForTest
[success] プロトコルUNITクラスの生成に成功しました (ProtocolForTest)
[success] プロトコルUNITのキュー名Enumの生成に成功しました (ProtocolForTestQueueEnum)
[success] プロトコルUNITのステータス名Enumの生成に成功しました (ProtocolForTestStatusEnum)
</pre><br />
コマンドを実行する事で<code>app/ProtocolUnits</code>の場所に以下3つのファイルが生成されます。<br />
<dl>
<dt>・ProtocolForTest.php</dt>
<dd>
<code>IEntryUnits</code>インターフェイスがimplementsされたプロトコルUNITクラスです。<br />
ここにプロトコル処理のイベントハンドラを実装します。<br />
</dd>
<dt>・ProtocolForTestQueueEnum.php</dt>
<dd>
ここにプロトコル処理のキュー(イベント)名を定義します。<br />
</dd>
<dt>・ProtocolForTestStatusEnum.php</dt>
<dd>
ここにプロトコル処理のステータス(UNIT)名を定義します。<br />
</dd>
</dl>
このフレームワーク環境では、キュー名とステータス名をEnumで定義する事を推奨しているので、それぞれのEnumファイルに分けて出力されます。<br /><br />
以降では生成されたファイルの内容を見ていきます。<br />
</div><br />
<a id="enum-queue"></a>
<h2 class="subtitle">キュー名の定義</h2>
<div class="text-block">
<code>ProtocolForTestQueueEnum.php</code>のファイルは、イベントに対応するキュー名を定義するEnumファイルです。<br />
プロトコルUNITのキュー名はあらかじめ<code>ProtocolQueueEnum</code>で予約されていますので、生成されたEnumファイルにはその内容が代入されています。<br />
定義済みのキュー名は以下の通り。<br />
<dl>
<dt>ProtocolForTestQueueEnum::ACCEPT</dt>
<dd>クライアントからの接続要求に対するアクセプト時に呼ばれる</dd>
<dt>ProtocolForTestQueueEnum::CONNECT</dt>
<dd>当該サーバーから他のエンドポイントへ接続する時に呼ばれる</dd>
<dt>ProtocolForTestQueueEnum::RECV</dt>
<dd>通信データを受信する時に呼ばれる</dd>
<dt>ProtocolForTestQueueEnum::SEND</dt>
<dd>通信データを送信する時に呼ばれる</dd>
<dt>ProtocolForTestQueueEnum::CLOSE</dt>
<dd>切断シーケンスを走らせる時に呼ばれる</dd>
<dt>ProtocolForTestQueueEnum::ALIVE</dt>
<dd>アライブチェックを走らせる時に呼ばれる</dd>
</dl>
これらのキュー名はプロトコルUNITクラスで定義されるイベントごとのUNITの集合を特定するためのものです。<br />
今回のケースでは<code>ProtocolForTest</code>クラス内でキューとUNITの紐づけを行います。<br />
紐づけの方法は以下の<font><a href="./protocol-unit.html#implement">>> プロトコルUNITクラスの実装</a></font>の項で説明しています。<br /><br />
※必ずしも全てのキューを使う必要はありませんが、オリジナルプロトコルを開発する場合は少なくともSENDキューとRECVキューが必要になります。<br />
</div><br />
<a id="enum-status"></a>
<h2 class="subtitle">ステータス名の定義</h2>
<div class="text-block">
<code>ProtocolForTestStatusEnum.php</code>のファイルは、プロトコルUNITのステータス名を定義するEnumファイルです。<br />
プロトコルUNITのステータス名であらかじめ予約されているものは<code>StatusEnum::START</code>だけで、生成されたEnumファイルにはその内容が代入されています。<br />
それ以外のステータス名は自由に定義する事ができます。<br />
定義済みのステータス名は以下の通り。<br />
<dl>
<dt>ProtocolForTestStatusEnum::START</dt>
<dd>
同じキューに登録されているUNITの集合のうち一番最初に実行されるステータスです。<br />
UNITは必ずSTARTステータスから始まるルールになっています。<br />
</dd>
</dl>
これらのステータス名はプロトコルUNITクラスで定義したUNITに紐づくものなので、今回のケースでは先ほど生成した<code>ProtocolForTest</code>クラス内でUNITとステータス名の紐づけを行います。<br />
紐づけの方法は以下の<font><a href="./protocol-unit.html#implement">>> プロトコルUNITクラスの実装</a></font>の項で説明しています。<br /><br />
※ここで定義したステータス名は異なるキューで再利用が可能です。<br />
</div><br />
<a id="implement"></a>
<h2 class="subtitle">プロトコルUNITクラスの実装</h2>
<div class="text-block">
<code>ProtocolForTest.php</code>のファイルにはUNIT定義を含めた各種メソッドが実装されています。<br />
各メソッドの仕様と実装例は以下の通り。<br /><br />
<br />
<h3 class="underline">➤キューリストの取得</h3>
フレームワークは以下のメソッドをコールして必要なキューのリストを登録します。<br />
<pre aria-label="シグネチャ">
【メソッド】getQueueList(): array
【パラメータ】なし
【戻り値】array - キュー名のリスト
</pre><br />
例えば予約されている全てのキューを利用する場合、以下のように実装します。<br />
<pre color-change="php" aria-label="メソッドの実装例">
protected const QUEUE_LIST = [
ProtocolForTestQueueEnum::ACCEPT->value, // アクセプトを処理するキュー
ProtocolForTestQueueEnum::RECV->value, // 受信処理のキュー
ProtocolForTestQueueEnum::SEND->value, // 送信処理のキュー
ProtocolForTestQueueEnum::CLOSE->value, // 切断処理のキュー
ProtocolForTestQueueEnum::ALIVE->value // アライブチェック処理のキュー
];
public function getQueueList(): array
{
return (array)static::QUEUE_LIST;
}
</pre><br />
<br />
<h3 class="underline">➤ステータスUNITリストの取得</h3>
以下のメソッドがフレームワーク内部でコールされる事によって、キューとUNITの紐づけが登録されます。<br />
<pre aria-label="シグネチャ">
【メソッド】getUnitList(string $p_que): array
【パラメータ】
$p_que - string - 必須 - キュー名
【戻り値】array - キューごとのUNIT集合のリスト(連想配列)
</pre><br />
フレームワーク内部では<code>getQueueList</code>メソッドで取得したキュー名を元に、<code>getUnitList</code>メソッドがコールされるため、引数にはキュー名が渡されます。<br />
例えば<code>SEND</code>キューと<code>RECV</code>キューにそれぞれ2つずつUNITの集合を登録する場合、以下のように引数で与えられたキュー名に対応するリストを返す必要があります。<br />
<pre color-change="php" aria-label="メソッドの実装例">
public function getUnitList(string $p_que): array
{
$ret = [];
// SENDキューのUNIT集合を登録
if($p_que === ProtocolForTestQueueEnum::SEND->value)
{
// STARTステータスとUNIT(getSendStart)の紐づけ
$ret[] = [
'status' => ProtocolForTestStatusEnum::START->value,
'unit' => $this->getSendStart()
];
// SEND_COMPLETEステータスとUNIT(getSendComplete)の紐づけ
$ret[] = [
'status' => ProtocolForTestStatusEnum::SEND_COMPLETE->value,
'unit' => $this->getSendComplete()
];
}
// RECVキューのUNIT集合を登録
if($p_que === ProtocolForTestQueueEnum::RECV->value)
{
// STARTステータスとUNIT(getRecvStart)の紐づけ
$ret[] = [
'status' => ProtocolForTestStatusEnum::START->value,
'unit' => $this->getRecvStart()
];
// RECV_COMPLETEステータスとUNIT(getRecvComplete)の紐づけ
$ret[] = [
'status' => ProtocolForTestStatusEnum::RECV_COMPLETE->value,
'unit' => $this->getRecvComplete()
];
}
.
.
.
return $ret;
}
</pre><br />
<br />
<h3 class="underline">➤ステータスUNITの実装</h3>
ここでは<code>getUnitList</code>メソッド内で紐づけたUNITを定義します。<br />
<pre aria-label="シグネチャ">
【メソッド】<任意のメソッド名>(): Closure|string|null
【パラメータ】なし
【戻り値】
Closure|string
- ステータスUNITの定義: Closure
パラメータ:
$p_param - SocketManagerParameter - 必須 - UNITパラメータクラスのインスタンス
各イベントハンドラで共通の引数として使用されるインスタンス。
SocketManagerParameterクラスを継承した拡張クラスを指定する事も可能。
戻り値: string|null
- 遷移先がある場合: string
遷移先のキュー名
- 遷移先がない(終了する)場合: null
- ステータスUNITの定義: string
ヘルパー関数などの関数名
</pre><br />
以下では<code>SEND</code>キューのUNIT集合と<code>RECV</code>キューのUNIT集合をポーリングUNITを使って実装した例をご紹介します。<br />
ポーリングUNITの詳細については<font><a href="./event-handler.html" target="_blank">▶イベントハンドラについて</a></font>の説明をご覧ください。<br /><br />
<dl>
<dt>【SENDキューのUNIT集合】</dt>
<dd>
ここでは、スタックエリアの送信データをポーリングUNIT(getSendComplete)を使って送信する例をご紹介しています。<br />
<pre color-change="php" aria-label="SENDキューのUNIT集合の実装例">
protected function getSendStart()
{
return function(ParameterForTest $p_param): ?string
{
// スタックエリアから送信データを取得する
$send_data = $p_param->protocol()->getSendData();
// 送信データの設定
$p_param->protocol()->setSendingData($send_data);
// SEND_COMPLETEステータス(getSendComplete)のUNITへ遷移
return ProtocolForTestStatusEnum::SEND_COMPLETE->value;
};
}
protected function getSendComplete()
{
return function(ParameterForTest $p_param): ?string
{
// データ送信
$w_ret = $p_param->protocol()->sending();
// nullの場合は送信中のためポーリングを続ける
if($w_ret === null)
{
// 自身のステータス名を返してポーリングする
$sta = $p_param->getStatusName();
return $sta;
}
// nullを返して終了する
return null;
};
}
</pre><br /><br />
</dd>
<dt>【RECVキューのUNIT集合】</dt>
<dd>
ここでは、仮に10バイトの固定データをポーリングUNIT(getRecvComplete)を使って受信する例をご紹介しています。<br />
(実際には、実装する各プロトコルフォーマットに合わせてデータ長を取得する必要があります)<br />
<pre color-change="php" aria-label="RECVキューのUNIT集合の実装例">
protected function getRecvStart()
{
return function(ParameterForTest $p_param): ?string
{
// 受信データサイズの設定
$p_param->protocol()->setReceivingSize(10);
// RECV_COMPLETEステータス(getRecvComplete)のUNITへ遷移
return ProtocolForTestStatusEnum::RECV_COMPLETE->value;
};
}
protected function getRecvComplete()
{
return function(ParameterForTest $p_param): ?string
{
// データ受信
$w_ret = $p_param->protocol()->receiving();
// nullの場合は受信中のためポーリングを続ける
if($w_ret === null)
{
// 自身のステータス名を返してポーリングする
$sta = $p_param->getStatusName();
return $sta;
}
// 受信したデータを受信スタックへ設定
$p_param->setRecvStack($w_ret);
// nullを返して終了する
return null;
};
}
</pre><br />
<code>getRecvComplete</code>メソッド(UNIT)内で<code>$p_param->setRecvStack()</code>メソッドを使って受信データを設定する事で、コマンドディスパッチャーやコマンドUNITに受信データを引き渡す事ができます。<br />
</dd>
</dl><br />
※送受信メソッドには<font><a href="./unit-parameter.html" target="_blank">▶UNITパラメータクラス</a></font>のページでご紹介した<code>protocol()</code>のメソッドチェーンを使用しています。<br />
※UNITパラメータクラスには<font><a href="./unit-parameter.html" target="_blank">▶UNITパラメータクラス</a></font>のページで使用した<code>ParameterForTest</code>を指定しています。<br />
</div><br />
<a id="last"></a>
<h2 class="subtitle">おわりに</h2>
<div class="text-block">
プロトコルUNITクラスはプロトコルの実装を担う部分なので、通信データとして扱うデータは基本的にバイナリデータである事に注意してください。<br />
そのため、メソッドチェーンの仲介役である<code>protocol()</code>を介して送受信を行う必要があります。<br /><br />
生成されたクラスのインスタンスは、メイン処理クラス内で<code>$manager->setProtocolUnits()</code>メソッドに引き渡す事で適用されます。<br />
複数のプロトコルUNITクラスやメイン処理クラスを用意している場合は、サーバーの実装内容によって最適なインスタンスを動的、あるいは静的に適用する事で柔軟なサーバー構築が可能になります。<br />
</div>
</div>
</div>
</body>
</html>