-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patharchitecture.html
More file actions
584 lines (440 loc) · 41.6 KB
/
architecture.html
File metadata and controls
584 lines (440 loc) · 41.6 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
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>アーキテクチャ | SOCKET-MANAGER Framework For PHP</title>
<meta name="description" content="SOCKET-MANAGER Framework の CUEI アーキテクチャを詳細解説。通信抽象化・共有基盤・非同期イベント処理・IPC を統合した統一レイヤー設計により、TCP/UDP/WebSocket/REST-API などをプロトコル非依存で扱える堅牢なリアルタイム基盤を提供。UNIT/Queue モデルや CycleDrivenManager による状態遷移制御も図解付きで紹介。" />
<meta name="keywords" content="PHP, ソケット通信, アーキテクチャ, CUEI, プロトコル抽象化, 非同期処理, ステートマシン, UNIT, Queue, CycleDrivenManager, IPC, マルチサーバー, ノンブロッキング, リアルタイム通信基盤" />
<link rel="canonical" href="https://socket-manager.github.io/document/architecture.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 - アーキテクチャ解説",
"description": "SOCKET-MANAGERフレームワークにおけるアーキテクチャを詳細解説。ノンブロッキングモード、マルチサーバー構成、プロトコル/コマンド層の実装、UNITパラメータの管理など、システム設計の核となる技術を図解付きで紹介。",
"keywords": "PHP, ソケット通信, アーキテクチャ, CUEI, プロトコル抽象化, 非同期処理, ステートマシン, UNIT, Queue, CycleDrivenManager, IPC, マルチサーバー, ノンブロッキング, リアルタイム通信基盤",
"articleSection": [
"Architecture Overview",
"CUEI Unified Model",
"Protocol Abstraction",
"Event-driven Processing",
"State Machine / UNIT / Queue",
"CycleDrivenManager",
"IPC and Multi-Server Design",
"Non-blocking Architecture",
"PHP Realtime Framework"
],
"image": "https://socket-manager.github.io/document/img/architecture/CUEIO.png",
"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/architecture.html"
},
"url": "https://socket-manager.github.io/document/architecture.html",
"breadcrumb": {
"@type": "BreadcrumbList",
"itemListElement": [{
"@type": "ListItem",
"position": 1,
"name": "Framework Top",
"item": "https://socket-manager.github.io/document/"
},{
"@type": "ListItem",
"position": 2,
"name": "アーキテクチャ",
"item": "https://socket-manager.github.io/document/architecture.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-link"><a href="./protocol-unit.html">▶プロトコルUNITクラス</a></h3>
<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="./concept.html">▶設計コンセプト</a></h3>
<h3 class="menu-page-title">▼アーキテクチャ</h3>
<ul>
<li><a href="./architecture.html#begin">はじめに</a></li>
</ul>
<ul>
<li><a href="./architecture.html#philosophy-architecture">アーキテクチャ思想</a></li>
</ul>
<ul>
<li><a href="./architecture.html#outline">レイヤー概念図</a></li>
</ul>
<ul>
<li><a href="./architecture.html#que_and_unit">キューとUNITの関係</a></li>
</ul>
<ul>
<li><a href="./architecture.html#unit-implementation">UNIT定義クラス</a></li>
</ul>
<ul>
<li><a href="./architecture.html#init">初期化クラス</a></li>
</ul>
<ul>
<li><a href="./architecture.html#main">メイン処理クラス</a></li>
</ul>
<ul>
<li><a href="./architecture.html#last">おわりに</a></li>
</ul>
<h3 class="menu-page-title-link"><a href="./communication.html">▶通信抽象化</a></h3>
<h3 class="menu-page-title-link"><a href="./union.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>
<h3 class="menu-page-title-link"><a href="./high-performance.html">▶ハイパフォーマンスモード</a></h3>
<h3 class="menu-page-title-link"><a href="./scale-test.html">▶実運用スケールベンチマーク</a></h3>
<h3 class="menu-page-title-link"><a href="./itil.html">▶技術版 ITIL としての CUEI/O</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>【アーキテクチャ】</h1>
<a id="begin"></a>
<h2 class="subtitle">はじめに</h2>
<div class="text-block">
SOCKET-MANAGER Framework は、<strong>CUEIアーキテクチャ(キューイ、通称キュー)</strong> をビルトイン採用した、軽量で拡張性のある通信フレームワークです。<br />
CUEIアーキテクチャは、以下の4つの要素を統合した設計思想を指します。<br />
<ul>
<li><strong>Communication(通信抽象化)</strong>:多様なプロトコルを統一的に扱う</li>
<li><strong>Union(共有基盤)</strong>:処理全体を束ねる共有基盤</li>
<li><strong>Event(非同期処理)</strong>:イベント駆動型の非同期処理</li>
<li><strong>IPC(サーバー間通信)</strong>:マルチサーバー構成・分散処理</li>
</ul>
これら4つの柱をビルトインで備えることにより、外部ライブラリや追加サーバーに依存せず、効率的でスケーラブルな通信アプリケーションを構築できます。<br /><br />
CUEIは以下の4つの柱で構成されます。<br />
<div class="img-block">
<figure class="center-figure">
<a href="./img/architecture/CUEI.png" target="_blank"><img src="./img/architecture/CUEI.png" width="700px" loading="eager" alt="四象限モデル(CUEIの4大要素)" title="CUEIアーキテクチャを構成する4大要素" /></a>
<figcaption><strong>CUEIアーキテクチャを構成する4大要素</strong></figcaption>
</figure><br />
</div>
<br />
<h3 class="underline">四象限モデル(CUEIの4要素)</h3>
CUEIアーキテクチャは、<strong>Communication / Union / Event / IPC</strong> の4要素を四象限モデルとして整理できます。<br />
それぞれが独立しつつも相互に連携し、フレームワーク全体を支える基盤を形成しています。<br />
<h4>当フレームワークで置き換えると…</h4>
<dl>
<dt>・Communication(通信抽象化)</dt>
<dd>
TCP・UDP・WebSocket・独自プロトコルなど多様な通信方式を抽象化する事でビジネスロジックとのシームレスな分離が可能。<br /><br />
</dd>
<dt>・Union(共有基盤)</dt>
<dd>
UNITパラメータによる統合コンテキスト。イベント処理全体のハブとして機能し、接続情報や送受信データを一元管理。<br />
送受信データに関してはFIFO方式バッファを採用する事でイベント多重起動を防止。<br /><br />
</dd>
<dt>・Event(非同期処理)</dt>
<dd>
独自のイベントループとコルーチンによる軽量なイベント駆動処理を実装する事で、動的なプロセスやスレッドに頼らない設計が可能。<br />
FIFOバッファの送受信データを順次取り出し、ビルトインの状態遷移制御により処理順序を保障。<br />
詳細は <font><a href="./event.html">▶イベント駆動アーキテクチャ</a></font> を参照。<br />
UNIT / Queue を用いたイベント処理の具体的な実装方法については、<font><a href="./event-handler.html">▶イベントハンドラについて</a></font> にて詳しく紹介しています。<br /><br />
</dd>
<dt>・IPC(サーバー間通信)</dt>
<dd>
サーバー間通信を前提としたマルチサーバー構成とスケーラビリティの確保。<br />
INETソケットを使う事でスケールアップ/スケールアウト時も統一的なインターフェースを提供する事が可能。<br />
詳細は <font><a href="./ipc.html">▶IPC(プロセス間通信)</a></font> を参照。<br /><br />
</dd>
</dl>
<strong>これらの4大要素を体系化する事で、自作によらないCLIコマンドによるスキャフォールディングのビルトイン実装を可能にしています。</strong><br /><br />
<br />
<h3 class="underline">CUEI/O(開発から運用まで)</h3>
さらに、SOCKET-MANAGER には <strong>SOCKET-MANAGER Launcher</strong> というサーバーリソース監視付きのサービス管理ランチャーを用意しています。<br />
これを組み合わせることで、<strong>CUEI/O(キューアイオー)</strong> として「開発から運用まで」を一貫してカバーできます。<br />
<ul>
<li><strong>CUEI</strong> = 開発思想(通信・共有基盤・非同期処理・サーバー間通信)</li>
<li><strong>CUEI/O</strong> = 開発+運用(Operation)を含む完全版</li>
</ul>
「/O」を付けることで、運用まで含めた包括的な基盤であることを明示できます。<br /><br />
SOCKET-MANAGER Launcherを組み合わせることでCUEIはCUEI/Oへ拡張されます。<br />
<div class="img-block">
<figure class="center-figure">
<a href="./img/architecture/CUEIO.png" target="_blank"><img src="./img/architecture/CUEIO.png" width="700px" fetchpriority="high" loading="eager" alt="CUEI/O──開発と運用を統合する拡張モデル" title="CUEI/O──開発と運用を統合する拡張モデル" /></a>
<figcaption><strong>CUEI/O──開発と運用を統合する拡張モデル</strong></figcaption>
</figure>
</div>
<p>
REST-API 環境における CUEI の実装レベルでの関係については、<font><a href="./rest-api/cuei.html" target="_blank">▶CUEIとの実装レベルでの関係</a></font>を参照してください。
</p>
<p>
CUEI/O の運用面での位置づけについては、<font><a href="./itil.html">▶技術版 ITIL としての CUEI/O</a></font>にて補足しています。
</p>
</div><br />
<a id="philosophy-architecture"></a>
<h2 class="subtitle">アーキテクチャ思想</h2>
<div class="text-block">
SOCKET-MANAGER Framework のアーキテクチャは、
<strong>CUEI(Communication / Union / Event / IPC)</strong> を中心に構築されています。<br />
これは単なるイベントループや非同期処理の実装ではなく、
異なる通信方式を統一的に扱うための <strong>基盤レイヤー</strong> を提供するものです。<br /><br />
特に重要なのは、プロトコル部とコマンド部が
<strong>UNIT / Queue モデル</strong> によって接続されている点です。<br />
この構造により、WebSocket・TCP・UDP・REST-API といった
通信方式の違いを越えて、すべての処理が同じレイヤー構造で動作します。<br /><br />
また、CycleDrivenManager による状態遷移制御により、
非同期処理中でも <strong>状態破壊が起きない堅牢な実行環境</strong> を実現しています。<br />
これは一般的な非同期ランタイムでは難しい特徴であり、
本フレームワークが「実運用スケール」を重視する理由でもあります。<br /><br />
CUEIアーキテクチャは、通信方式やサーバー構成の違いを吸収し、
<strong>統一されたリアルタイム基盤(Unified Realtime Layer)</strong> として機能します。<br />
</div><br />
<a id="outline"></a>
<h2 class="subtitle">レイヤー概念図</h2>
<div class="text-block">
CUEIアーキテクチャの思想を具体的に実装した構造が、以下の「レイヤー概念図」です。<br />
ここではプロトコル部とコマンド部の分離、UNITパラメータの役割、CycleDrivenManagerによる制御など、ノンブロッキングモードによる実装を前提とした仕組みを詳しく解説していきます。<br />
<div class="img-block">
<a href="./img/architecture/outline.png" target="_blank"><img class="img-zoomout" src="./img/architecture/outline.png" loading="lazy" alt="SOCKET-MANAGERフレームワークのレイヤー構造図" /></a>
</div>
サーバーのアプリケーションの部分はプロトコル部とコマンド部に大きく分かれています。<br />
最初にそれらをライブラリ内の <code>CycleDrivenManager</code> のプロトコル部とコマンド部へ取り込ませてから使う事になります。<br /><br />
プロトコル部とコマンド部に分けているのは、それぞれを自由に入れ替える事ができるようにするためです。<br />
作成したクライアントのプロトコルに合わせてプロトコル部を入れ替えたり、サーバーサイドのコンテンツを切り替えるためにコマンド部を入れ替えたりする事で様々な組み合わせのサーバーを構築する事が可能です。
</div><br />
<a id="que_and_unit"></a>
<h2 class="subtitle">キューとUNITの関係</h2>
<div class="text-block">
まずは <code>CycleDrivenManager</code> の動きを理解するためにキューとステータスUNITの関係を知る必要があります。<br />
図にすると以下のようなイメージになります。
<div class="img-block">
<a href="./img/architecture/que-and-unit.png" target="_blank"><img class="img-zoomout" src="./img/architecture/que-and-unit.png" loading="lazy" alt="SOCKET-MANAGERフレームワークのイベント処理部分であるキューとUNITの関係図" /></a>
</div>
通信データの送受信の特徴として送りたいデータ、あるいは欲しいデータが一度に全て送信/受信できるとは限らないためこのような構成になっています。<br />
また、WAIT が発生するような処理(送信/受信をセットにしている動作など)を UNIT で分ける事で、キューの処理を待たせる事なく次の UNIT 処理へと進む事ができるようになります。<br /><br />
例えば Websocket の opening ハンドシェイクの場合はクライアントからヘッダ情報を受信した後は同じようにヘッダ情報をサーバーから送り返さないといけませんが、これをブロッキングモードで送信が完了するまで待っていると他の接続も巻き込んで処理が待たされる事になってしまいます。<br /><br />
この回避策として当ライブラリでは以下の UNIT 処理のようにノンブロッキングモードで送信が行えるようにしています。<br />
<pre color-change="php" aria-label="UNIT処理の一部を抜粋">
// CREATEステータスのUNIT
{
// 送信データの設定
$p_param->protocol()->setSendingData(<送信データ>);
return ProtocolStatusEnumForWebsocket::SEND->value;
}
// SENDステータスのUNIT
{
// データ送信
$w_ret = $p_param->protocol()->sending();
// 送信中の場合は再実行
if($w_ret === null)
{
$sta = $p_param->getStatusName();
return $sta;
}
return null;
}
</pre><br />
実際にデータを送信する <code>SEND</code> ステータスのひとつ前のUNIT処理( <code>CREATE</code> ステータス)であらかじめ送信したいデータを設定しておき、送信を実行するUNIT処理( <code>SEND</code> ステータス)で <code>sending</code> メソッドの戻り値が null 以外になるまで繰り返しています。<br /><br />
※ <code>sending</code> メソッドは設定された送信データを送信しきるまで null を返す処理です。<br />
※ <code>getStatusName</code> メソッドは現在実行中のステータス名を取得するものです。<br /><br />
受信の場合も同じように受信サイズを設定するメソッド <code>setReceivingSize</code> と受信しきるまで null を返すメソッド <code>receiving</code> に分けています。<br /><br />
このように UNIT の処理の実装は極力処理の停滞(ブロッキング)がおきないように構成する事が求められます。<br /><br />
また、UNIT ステータスはリターン値によって遷移していきます。そしてキューの処理が全て完了したら null を返すルールとなっています。<br />
処理の流れはリターン値で制御できるので、同じような処理を繰り返し行ったり、分岐したいケースがある場合には処理を構造化しながらコントロールする事が可能になります。<br /><br />
このようなキューとステータスUNITをコントロールする役割を <code>CycleDrivenManager</code> が担っています。<br /><br />
<h3 class="underline">throwブレイク</h3>
このシステムでの throw ブレイクは、UNIT のステータスを維持したまま処理を中断して待ち受け状態に戻る事を意味します。<br />
ステータスUNIT内で <code>UnitException</code> クラスを用いて例外( throw )を発行する事で throw ブレイクとなります。
</div><br />
<a id="unit-implementation"></a>
<h2 class="subtitle">UNIT定義クラス</h2>
<div class="text-block">
UNIT の処理はプロトコル/コマンド部を問わず <code>IEntryUnits</code> インターフェースに従って実装する必要があります。<br />
プロトコル部を作成する時は <code>craft:protocol</code> コマンドを、コマンド部を作成する時は <code>craft:command</code> コマンドを実行してファイルを生成します。<br />
生成されるファイルの種類は以下の通り。<br />
<ul>
<li>UNIT 定義クラス</li>
<li>キュー名定義の Enum</li>
<li>ステータス名定義の Enum</li>
</ul>
UNIT 定義クラスの実装イメージは次の通りです。<br />
<div class="img-block">
<a href="./img/architecture/unit_class.png" target="_blank"><img class="img-zoomout" src="./img/architecture/unit_class.png" loading="lazy" alt="SOCKET-MANAGERフレームワークのイベント処理部分であるキューとUNITを定義するクラスの内部構造イメージ" /></a>
</div>
プロトコル部のキュー名は <code>ProtocolQueueEnum</code> で予約されているので、作成された Enum ファイルにはこの予約された Enum 値がエイリアス名として定義されます。<br /><br />
コマンド部のキュー名の定義は自由です。UNIT 定義クラスの実装に合わせてキュー名を追加していく事になります。<br /><br />
<dl>
<dt>■ getQueueList メソッドの実装</dt>
<dd>プロトコル部、コマンド部それぞれで定義されたキュー名の Enum 値をピックアップしてリストに追加します。</dd>
<dt>■ getUnitList メソッドの実装</dt>
<dd>引数で渡されたキュー名と一致するリストを返します。プロトコル部、コマンド部それぞれで定義されたステータス名定義の Enum 値をピックアップしてステータス名に対応する UNIT メソッドとセットでリストを作成します。各キューの処理は <code>START</code> ステータスから始まるので必ず含める必要があります。</dd>
</dl>
</div><br/>
<a id="init"></a>
<h2 class="subtitle">初期化クラス</h2>
<div class="text-block">
初期化クラスは <code>IInitSocketManager</code> インターフェースに従って実装する必要があります。<br />
インターフェース実装に必要な内容は以下の通りです。<br /><br />
<h3 class="underline">UNITパラメータクラス</h3>
<code>SocketManagerParameter</code> クラスやそれを継承しているクラスの事を UNIT パラメータクラスと呼びます。<br />
このインスタンスは UNIT 処理の引数として渡されるもので、<code>SocketManager</code> との橋渡し役を担っています。<br /><br />
<code>SocketManagerParameter</code> クラスを継承する事でデータの送受信やディスクリプタ(クライアント接続子)の操作を行うための機能を提供すると同時に、アプリケーションで利用するグローバルエリアを管理する役割も担っています。<br />
プロトコル部・コマンド部・コマンドディスパッチャー間で同じグローバルエリアの利用が可能です。<br />
接続子単位でのグローバル管理が必要なデータに関しては、UNIT パラメータクラス内の <code>getTempBuff/setTempBuff</code> メソッドで取得・設定が可能です。<br />
これを図にすると以下のようになります。<br />
<div class="img-block">
<a href="./img/architecture/global.png" target="_blank"><img class="img-zoomout" src="./img/architecture/global.png" loading="lazy" alt="SOCKET-MANAGERフレームワーク内でのグローバル管理領域のアクセス概念図" /></a>
</div>
初期化クラス内の <code>getUnitParameter メソッド</code> でインスタンスを返す必要がありますが、インスタンス化するタイミングは初期化クラスの内側/外側を問いません。<br /><br />
プロトコル部では UNIT パラメータクラス内でインプリメントされた <code>IProtocolParameter</code> インターフェースを返す <code>protocol</code> メソッドを介して送受信用のメソッドを使う必要があります。<br />
これに対してコマンド部では UNIT パラメータクラス内でインプリメントされた <code>getRecvData</code> メソッドを使って受信データを取得し、<code>setSendStack</code> メソッドを使って送信データを設定する流れが基本となります。<br /><br />
このような構成になっているのは以下の処理を前提としているからです。<br />
<dl>
<dt>・受信処理</dt>
<dd>受信データはプロトコル部で組み立てたものをコマンド部に渡します(コマンド部では <code>getRecvData</code> メソッドを通して受信データを取得します)。</dd>
<dt>・送信処理</dt>
<dd>コマンド部で組み立てた送信データはプロトコル部で必要に応じて分解され、送信されます(コマンド部では <code>setSendStack</code> メソッドを通して送信データを引き渡します)。</dd>
</dl>
この為コマンド部の処理では、ノンブロッキングの処理を意識する事なく通信データの送受信の実装が可能となります。<br /><br />
※ protocol メソッドをコマンド部で呼び出すと <code>UnitExceptionEnum::ECODE_METHOD_CALL_FAIL</code> 例外が発生してエラー終了しますのでご注意ください。<br />
※ 具体的にどんなメソッドが存在するのかについては <code>SocketManagerParameter</code> クラスの<font class="code"><a href="./reference/classes/SocketManager-Library-SocketManagerParameter.html" target="_blank">>> Reference</a></font>をご覧ください。<br /><br />
<h3 class="underline">シリアライザー/アンシリアライザー</h3>
この処理はディスクリプタ内で管理された先入れ先出し方式である送受信スタックエリア(メモリ上のスタック領域とは無関係です)と深く関わっています。<br />
送受信スタックエリア内ではシリアライズ化されたデータが保持されるため、データ取得時にはアンシリアライザーが、データ設定時にはシリアライザーが呼び出されます。<br />
これを図にすると以下のようになります。<br /><br />
<div class="img-block">
<a href="./img/architecture/data_stack.png" target="_blank"><img class="img-zoomout" src="./img/architecture/data_stack.png" loading="lazy" alt="クライアントごとに管理している送受信データスタック領域とアクセス概念図" /></a>
</div>
<h3 class="underline">コマンドディスパッチャー</h3>
プロトコル部で受信したデータは UNIT パラメータクラスの <code>setRecvStack</code> メソッドを使って受信スタックへ格納する必要があります。<br />
コマンドディスパッチャーはその受信データを解析してコマンド部に処理を振り分ける役割を担っています。<br /><br />
コマンド部から送信するデータは UNIT パラメータクラスの <code>setSendStack</code> メソッドを使って送信スタックへ格納する必要があります。<br />
送信時はコマンドディスパッチャーの介入はなく、送信スタックに溜まったものをプロトコル部を経由して順次クライアントへ送信されます。<br /><br />
これを図にすると以下のようになります。<br /><br />
<div class="img-block">
<a href="./img/architecture/recv_flow.png" target="_blank"><img class="img-zoomout" src="./img/architecture/recv_flow.png" loading="lazy" alt="受信データを解析してコマンドディスパッチャーが処理を振り分ける概念図" /></a>
</div>
<div class="img-block">
<a href="./img/architecture/send_flow.png" target="_blank"><img class="img-zoomout" src="./img/architecture/send_flow.png" loading="lazy" alt="コマンドディスパッチャーを介さずに送信データが送出されるまでの概念図" /></a>
</div>
<h3 class="underline">緊急停止時のコールバック</h3>
以下の場面で呼び出されます。<br />
<ul>
<li>アライブチェック処理のタイムアウト</li>
<li>コマンドディスパッチャーで例外キャッチ時</li>
<li>相手先による強制切断</li>
</ul><br />
<h3 class="underline">ログライター</h3>
ライブラリ内を含めアプリケーションレイヤー内からも呼ばれるログ出力ハンドラーです。<br />
アプリケーションレイヤーからは UNIT パラメータクラスを通して呼ばれます。<br />
</div><br />
<a id="main"></a>
<h2 class="subtitle">メイン処理クラス</h2>
<div class="text-block">
実装イメージは以下の通りです。<br />
<div class="img-block">
<a href="./img/architecture/main_class.png" target="_blank"><img class="img-zoomout" src="./img/architecture/main_class.png" loading="lazy" alt="メイン処理クラスの内部構造イメージ" /></a>
</div>
このうち初期設定ブロックは <code>SocketManager</code> の準備処理として必要な部分です。<br />
ポート設定ブロックではマルチサーバーの子サーバーとして起動する場合、親サーバーへの接続を行うための <code>connect</code> メソッドが使用される事があります。<br />
ノンブロッキングループブロックは以下のイメージで動作します。<br />
<div class="img-block">
<a href="./img/architecture/main1.png" target="_blank"><img class="img-zoomout" src="./img/architecture/main1.png" loading="lazy" alt="クライアント接続単体でのノンブロッキングループ動作イメージ" /></a>
</div>
1つの接続に対してプロトコル部とコマンド部が連携し合って動作します。<br />
このうち1回の周期(ループ)で実行されるのはプロトコル/コマンド部のそれぞれ1 UNIT ずつとなります。<br />
これが複数の接続になると以下のイメージになり、1つのサーバーで処理する単位になります。<br />
<div class="img-block">
<a href="./img/architecture/main2.png" target="_blank"><img class="img-zoomout" src="./img/architecture/main2.png" loading="lazy" alt="複数のクライアント接続時のノンブロッキングループ動作イメージ" /></a>
</div>
そして複数のサーバーを起動している場合は以下のイメージになり、プロセスが順当に割り当てられると1つのサーバープロセスが CPU の各コア(このケースではコアが4つの場合)に割り当てられてデュアルで動作します。<br />
<div class="img-block">
<a href="./img/architecture/main3.png" target="_blank"><img class="img-zoomout" src="./img/architecture/main3.png" loading="lazy" alt="複数のサーバープロセス稼働時のノンブロッキングループ動作イメージ" /></a>
</div>
※ 実際にサーバーをスケーリングする際には上記のイメージを基に計算/設計していく事になりますが、サーバー上の個々のプロセスを OS が必ずしも別々の CPU に割り当てるとは限らないため、リソースや処理時間等の実測値を見ながら調整していく事になります。通常は OS が自動的に CPU 割り当てを行いますが、<a href="./launcher/" target="_blank">SOCKET-MANAGER Launcher</a> を利用することで任意の CPU にプロセスを割り当てることが可能となり、プロセス間の競合を抑制しながらより効率的なリソース活用が行えます。
<br /><br />
</div>
<a id="last"></a>
<h2 class="subtitle">おわりに</h2>
<div class="text-block">
ここでご紹介した内容は特に新規プロジェクト開発をする時に必要になる情報ばかりですが、Websocket 開発環境でもより高度な実装をするために必要な情報でもあります。<br />
サーバー間通信を伴うマルチサーバーを構築する際の基礎的な内容でもありますので<font><a href="./multi-server.html" target="_blank">▶マルチサーバーの構成</a></font>のページも合わせてご覧ください(マルチサーバーの構築を予定していない場合は読み飛ばしてもらっても構いません)。
</div>
</div>
</div>
</body>
</html>