-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwebsocket.html
More file actions
507 lines (404 loc) · 25.4 KB
/
websocket.html
File metadata and controls
507 lines (404 loc) · 25.4 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
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Websocketサーバー開発環境 | SOCKET-MANAGER Framework For PHP</title>
<meta name="description" content="PHPでWebSocketサーバーを簡単に構築!SOCKET-MANAGERフレームワークを使用したチャットサーバーの実装例やクライアント連携の方法など、具体的なコード例と共に解説。" />
<meta content="PHP,ソケット通信,websocket,フレームワーク,サーバー開発,ソケットマネージャー" name="keywords">
<link rel="canonical" href="https://socket-manager.github.io/document/websocket.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 - WebSocketサーバーの実装ガイド",
"description": "PHPでWebSocketサーバーを簡単に構築!SOCKET-MANAGERフレームワークを使用したチャットサーバーの実装例やクライアント連携の方法など、具体的なコード例と共に解説。",
"keywords": "PHP, WebSocket, サーバー開発, チャットサーバー, ソケットマネージャー",
"articleSection": ["Technical Documentation", "Server Development", "PHP Programming"],
"image": "https://socket-manager.github.io/document/img/websocket/browser_exec.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/websocket.html"
},
"url": "https://socket-manager.github.io/document/websocket.html",
"breadcrumb": {
"@type": "BreadcrumbList",
"itemListElement": [{
"@type": "ListItem",
"position": 1,
"name": "Framework Top",
"item": "https://socket-manager.github.io/document/"
},{
"@type": "ListItem",
"position": 2,
"name": "Websocketサーバー開発環境",
"item": "https://socket-manager.github.io/document/websocket.html"
}]
},
"tutorial": {
"@type": "HowTo",
"name": "WebSocketサーバーの実装手順",
"step": [
{
"@type": "HowToStep",
"name": "インストール",
"text": "composerを使用してプロジェクトを作成"
},
{
"@type": "HowToStep",
"name": "サーバーの実装",
"text": "コマンドUNITの実装とメッセージ処理の追加"
},
{
"@type": "HowToStep",
"name": "クライアントの実装",
"text": "WebSocket接続とイベントハンドラの実装"
}
]
},
"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="./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">▼Websocketサーバー開発環境</h3>
<ul>
<li><a href="./websocket.html#begin">はじめに</a></li>
</ul>
<ul>
<li><a href="./websocket.html#install">インストール</a></li>
</ul>
<ul>
<li><a href="./websocket.html#implementation">実装例</a></li>
</ul>
<ul>
<li><a href="./websocket.html#run">動作確認</a></li>
</ul>
<ul>
<li><a href="./websocket.html#log">ログ出力について</a></li>
</ul>
<ul>
<li><a href="./websocket.html#last">おわりに</a></li>
</ul>
<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>【Websocketサーバー開発環境】</h1>
<a id="begin"></a>
<h2 class="subtitle">はじめに</h2>
<div class="text-block">
この環境はデモ版のWebsocketサーバーからコマンド部を含めWebsocketに不要な部分を取り除いて再構築したものです。<br />
プロトコルの主要な部分は実装済みなので、コマンド部を自分で作成しながらブラウザを使って動作確認できますので、新規でプロジェクトを起こす場合に比べてソケット通信初心者向けの環境と言えます。<br /><br />
以降ではインストール方法と実装例を見ながら進めていきます。
</div><br />
<a id="install"></a>
<h2 class="subtitle">インストール</h2>
<div class="text-block">
以下のコマンドでインストールできます。<br />
※GitHubから直接ダウンロードする場合は<font><a href="https://github.com/socket-manager/websocket-project" target="_blank">>> こちら</a></font>からどうぞ。<br />
<pre color-change="command" aria-label="Websocketサーバー開発環境のインストール">
> composer create-project socket-manager/websocket-project <インストール先のディレクトリ名>
</pre><br />
それでは上記でインストールしたプロジェクトルートに移動して<code>php worker</code>コマンドを実行してみます。<br />
<pre color-change="command" aria-label="Usage表示">
> php worker
SOCKET-MANAGER Framework 1.0.0
Usage:
command [arguments]
main
app:websocket-server Websocketサーバー
craft
craft:init <初期化クラス名> 初期化クラスの生成
craft:parameter <UNITパラメータクラス名> UNITパラメータクラスの生成
craft:protocol <プロトコルUNIT定義のクラス名> プロトコルUNIT定義のクラスとステータス名Enumの生成
craft:command <コマンドUNIT定義のクラス名> コマンドUNIT定義のクラスとキュー/ステータス名Enumの生成
craft:main <メイン処理のクラス名> メイン処理クラスの生成
craft:setting <設定ファイル名> 設定ファイルの生成
craft:locale <メッセージファイル名> メッセージファイルの生成
runtime
runtime:init <初期化クラス名> 初期化クラスの生成
runtime:parameter <UNITパラメータクラス名> UNITパラメータクラスの生成
runtime:units <ランタイムUNIT定義のクラス名> ランタイムUNIT定義のクラスとキュー/ステータス名Enumの生成
runtime:main <メイン処理のクラス名> メイン処理クラスの生成
simple
simple:tcp-server <メイン処理のクラス名> TCPサーバー用メイン処理クラスの生成
simple:tcp-client <メイン処理のクラス名> TCPクライアント用メイン処理クラスの生成
simple:udp <メイン処理のクラス名> UDP通信用メイン処理クラスの生成
</pre><br />
ご覧のように<code>app:websocket-server</code>が含まれている事が確認できます。<br />
これを以下のように実行する事でサーバーを起動できます。<br />
<pre color-change="command" aria-label="Websocketサーバーの起動">
> php worker app:websocket-server [<ポート番号>]
</pre><br />
※コマンドの詳しい使い方は<font class="code"><a href="./new-project.html" target="_blank">▶新規開発環境</a></font>のページでご紹介しています。
</div><br />
<a id="implementation"></a>
<h2 class="subtitle">実装例</h2>
<div class="text-block">
ここではコマンド部のチャットメッセージを実装してみます。<br /><br />
<h3 class="underline">クライアントの実装</h3>
このプロジェクトでは<code>client</code>ディレクトリに検証用として最低限の実装でファイルを同梱しています。<br />
それでは<code>client</code>ディレクトリ内の<code>test.js</code>を編集します。<br />
<code>test.js</code>内には以下のように<code>onopen</code>メソッドがあるのでここに処理を入れます。<br />
以下の黄色の部分が今回追加したソースです。<br />
<pre color-change="php" aria-label="onopenメソッドの実装:app/client/test.js">
// Websocket接続
websocket = new WebSocket(uri);
/**
* 接続完了イベント
*
* @param {*} event イベントインスタンス
* @returns
*/
websocket.onopen = function(event)
{
<font class="pre-yellow">let data =
{
'cmd': 'message'
, 'comment': 'テスト'
};
websocket.send(JSON.stringify(data));</font>
};
</pre><br />
<code>onopen</code>メソッドはWebsocketの接続が確立した時に呼び出されるイベントです。<br />
上記のようにコマンド名は<code>message</code>、送信コメントは<code>テスト</code>にしてJSONデータを送信する処理を入れています。<br /><br />
そして以下のように<code>onmessage</code>メソッドで受信したデータを受け取れますので受信したデータはコンソールに表示されるようになっています。<br />
<pre color-change="php" aria-label="onmessageメソッド:app/client/test.js">
/**
* データ受信イベント
*
* @param {*} event イベントインスタンス
* @returns
*/
websocket.onmessage = function(event)
{
let data = JSON.parse(event.data);
console.dir(data);
};
</pre><br />
<h3 class="underline">サーバーの実装</h3>
まずは<code>CommandForWebsocketQueueEnum.php</code>のファイルに今回追加するコマンド名を定義します。<br />
以下の黄色の部分が今回追加したソースです。<br />
<pre color-change="php" aria-label="キュー名の追加:app/CommandUnits/CommandForWebsocketQueueEnum.php">
<?php
/**
* コマンド部のキュー名のENUMファイル
*
* Websocket用
*/
namespace App\CommandUnits;
/**
* コマンド部のキュー名定義
*
* Websocket用
*/
enum CommandForWebsocketQueueEnum: string
{
<font class="pre-yellow">case MESSAGE = 'message';</font>
}
</pre><br />
次に<code>CommandForWebsocket.php</code>を編集します。<br />
以下の黄色の部分が今回追加したソースです。<br />
<pre color-change="php" aria-label="ステータスUNITの実装:app/CommandUnits/CommandForWebsocket.php">
class CommandForWebsocket implements IEntryUnits
{
/**
* @var const QUEUE_LIST キュー名のリスト
*/
protected const QUEUE_LIST = [
<font class="pre-yellow">CommandForWebsocketQueueEnum::MESSAGE->value,</font>
];
/**
* キューリストの取得
*
* @return array キュー名のリスト
*/
public function getQueueList(): array
{
return (array)static::QUEUE_LIST;
}
/**
* ステータスUNITリストの取得
*
* @param string $p_que キュー名
* @return array キュー名に対応するUNITリスト
*/
public function getUnitList(string $p_que): array
{
<font class="pre-yellow">$ret = [];
if($p_que === CommandForWebsocketQueueEnum::MESSAGE->value)
{
$ret[] = [
'status' => CommandForWebsocketStatusEnum::START->value,
'unit' => $this->getMessageStart()
];
}
return $ret;</font>
}
<font class="pre-yellow">protected function getMessageStart()
{
return function(ParameterForWebsocket $p_param): ?string
{
$p_param->logWriter('debug', ['COMMAND:MESSAGE' => 'START']);
$w_ret = $p_param->getRecvData();
$msg = $w_ret['data'];
$data =
[
'data' => $msg
];
$p_param->setSendStackAll($data);
return null;
};
}</font>
}
</pre><br />
追加したポイントは以下の通り。<br />
<dl>
<dt>■QUEUE_LISTへEnum値を追加</dt>
<dd><code>MESSAGE</code>というキュー名を追加</dd>
<dt>■getUnitListメソッドの実装</dt>
<dd><code>MESSAGE</code>コマンドに対応するUNIT(メソッド)処理を登録</dd>
<dt>■getMessageStartメソッドの実装(※)</dt>
<dd>受信したデータを配信する処理を実装(上記ソース内のlogWriterメソッドでログ出力できます)</dd>
</dl>
※サーバーから<code>setSendStackAll</code>メソッドを使ってデータを送信する時、データ構造に<code>data</code>というキーを噛ませていますが、これはWebsocketの切断フレームの仕様が特殊なため敢えてこのような構造にしています。コマンド部でデータを送受信する時は<code>data</code>キーを噛ませる事で切断フレームを含めたデータ構造を一律に保つようにしています。<br />
※引数の<code>ParameterForWebsocket</code>クラスは<code>SocketManagerParameter</code>クラスを継承しています。詳しくは<code>SocketManagerParameter</code>クラスの<font class="code"><a href="./reference/classes/SocketManager-Library-SocketManagerParameter.html" target="_blank">>> Reference</a></font>をご覧ください。<br />
※ここで扱っている<code>CommandForWebsocket</code>というクラスは広義の意味で<code>コマンド部</code>に分類される処理で<code>コマンドUNITクラス</code>と言います。コマンドUNITクラスの基本的な実装方法は<font><a href="./command-unit.html" target="_blank">▶コマンドUNITクラス</a></font>のページをご覧ください。<br />
</div><br />
<a id="run"></a>
<h2 class="subtitle">動作確認</h2>
<div class="text-block">
以下のコマンドを実行してサーバーを10000ポートで起動します。<br />
<pre color-change="command" aria-label="Websocketサーバーの起動">
> php worker app:websocket-server 10000
</pre><br />
次にクライアントをブラウザで開きます。<br />
<code>client/test.html</code>をブラウザへドラッグ&ドロップした上でF12を押して以下の画面を開いてください。<br />
<img src="./img/websocket/browser.png" width="700px" loading="lazy" alt="WebSocketクライアントのデバッグコンソール画面 - SOCKET-MANAGER Framework" /><br /><br />
この状態で接続ボタンをクリックすると以下のようにコンソール画面でメッセージコマンドが返ってきている事が確認できます。<br />
<img src="./img/websocket/browser_exec.png" width="700px" loading="lazy" alt="WebSocketサーバーの実行結果画面 - メッセージの送受信デモ" /><br /><br />
そしてさらにブラウザをもう一つ開いて同じ操作をすると二つのブラウザウインドウに同じメッセージが配信されている事が確認できますので色々と試してみてください。<br />
</div><br />
<a id="log"></a>
<h2 class="subtitle">ログ出力について</h2>
<div class="text-block">
以下のディレクトリ構成でログファイルが出力されます。<br />
<pre aria-label="ログ出力先のディレクトリ">
/logs
/socket-manager-log Websocketサーバーのログ
</pre><br />
ファイルの命名規則は次の通り。<br />
<dl>
<dt>■Websocketサーバーのログ</dt>
<dd><日付文字列("Ymd"形式)>_W<ポート番号>.log</dd>
</dl>
</div><br />
<a id="last"></a>
<h2 class="subtitle">おわりに</h2>
<div class="text-block">
コマンドUNITの処理は上記で実装したように以下の流れが基本となります。<br />
<dl>
<dt>1.受信データの取得</dt>
<dd>getRecvDataメソッドで取得</dd>
<dt>2.送信データの作成</dt>
<dd>シリアライズ前のデータを作成する</dd>
<dt>3.送信データの設定</dt>
<dd>setSendStack、setSendStackAllメソッドで設定</dd>
</dl>
Websocketサーバー開発環境では上記のようにコマンド部の処理を追加していく事でサーバーコンテンツを作成していく事になります。<br />
(<font><a href="./architecture.html" target="_blank">▶アーキテクチャ</a></font>を理解しておいた方がより高度な実装が可能になります)<br /><br />
自作のプロトコルを実装する必要がある場合は<font><a href="./new-project.html" target="_blank">▶新規開発環境</a></font>をご利用ください。<br /><br />
ホスト名やポート番号等の設定ファイルの詳細は<font><a href="./extra-demo-setting.html" target="_blank">▶デモの設定ファイル</a></font>のページでまとめています。
</div>
</div>
</div>
</body>
</html>