====== Ratchet チュートリアル ====== Version 0.4.3 --- //[[http://www.y2sunlight.com|y2sunlight]] 2020-11-14// [[ratchet:top|Ratchet に戻る]] 関連記事 * Ratchet チュートリアル * [[Ratchet:0.4:push|Ratchet Push統合]] リンク * http://socketo.me/ --- Ratchet の本家 * http://socketo.me/docs/hello-world --- Ratchet チュートリアル(Hello World!) 本章は、Ratchet 公式サイトの[[http://socketo.me/docs/hello-world|チュートリアル(Hello World!)]]のレビューです。実際にチュートリアルを行った結果を補足とともに説明します。ここでは、[[psr:psr4|PSR-4]] と [[composer:top|Composer]] に精通していることを前提としています。それらについては本編でも説明しているので、そちらをご覧ください。 \\ ----- ===== プロジェクトの作成 ===== まず、プロジェクトフォルダ(以下 ''{Project-Folder}'' と呼びます)を作成し、そこにComposerファイルを設置します。 { "autoload": { "psr-4": { "MyApp\\": "src" } }, "require": { "cboden/ratchet": "^0.4" } } 上の設定では、プロジェクトフォルダ下の ''src'' フォルダにアプリケーションを設置し、そこを ''MyApp'' 名前空間として定義します。 Composer の規則に従い、ratchet は ''vender/cboden/ratchet'' 下に保存されます。また、チャットサーバ起動用のスクリプトを配置する ''bin'' フォルダを作ります。 プロジェクトフォルダ下に以下のフォルダを作成します: * ''src'' --- アプリケーションソースを格納します * ''bin'' --- アプリケーション起動用のスクリプトを格納します 準備が出来たら、コマンドプロンプトでプロジェクトフォルダに移り、''composer install'' を実行します。 > composer install Loading composer repositories with package information Warning from https://repo.packagist.org: You are using an outdated version of Composer. Composer 2.0 is now available and you should upgrade. See https://getcomposer.org/2 Updating dependencies (including require-dev) Package operations: 18 installs, 0 updates, 0 removals - Installing symfony/polyfill-php80 (v1.20.0): Downloading (100%) - Installing symfony/deprecation-contracts (v2.2.0): Downloading (100%) ... Writing lock file Generating autoload files \\ ===== チャットアプリの外観 ===== チュートリアルでは、簡単なチャットアプリケーションを作成します。それは、すべての着信メッセージを受け入れ、そのメッセージを他のすべての接続に配信するだけのものです。送信メッセージは、お決まりの 「HelloWorld!」 にしましょう。 === Chat クラス === まず、アプリケーション本体になる ''Chat'' クラスをsrcフォルダの下に作成します。 {{fa>folder-open-o}} ** {Project-Folder}/src/Chat.php ** このクラスは、''MessageComponentInterface'' を実装し、次の4つのイベントハンドラを作ります。 * onOpen - 新しいクライアントが接続したときに呼び出されます * onMessage - 接続がメッセージを受信したときに呼び出されます * onClose - 接続が閉じられたときに呼び出されます * onError - 接続でエラーが発生したときに呼び出されます こられのイベントハンドラは、''ConnectionInterface'' オブジェクトを引数に持っています。それは、ソケットの反対側のクライアントの接続を表しています。 === インスタンス化 === ''Chat'' クラスは、実際のアプリケーションロジックを含みますが、これをインスタンス化するスクリプト ( チャットサーバと呼ぶ事にします ) を作ります。このスクリプトは、コマンドラインから呼び出されます。 {{fa>folder-open-o}} ** {Project-Folder}/bin/chat-server.php ** run(); ここでは、[[http://socketo.me/docs/server|IoServer]] を作成しています。 ''IoServer'' はチャットアプリケーションのベースとなるイベント処理を行う中核のサーバクラスです。''IoServer'' クラスは、確立されたすべての接続を保存し、各クライアントとチャットアプリケーション間で送信されるデータを仲介します。また、エラーがあればそれをキャッチします。 ここでは、Chatクラスの新しいインスタンスが ''IoServer'' をラップし、ポート8080で着信要求をリッスンしてイベントループに入るようにサーバーに指示します。 コマンドプロンプトを起動しプロジェクトフォルダに移動し、''bin/chat-server.php'' を起動します: php bin/chat-server.php 次に、別のコマンドコマンドプロンプトを起動し以下のコマンドを実行します。 netstat -an | find "8080" 以下のようにリスニングポートが開いていたらOKです。 TCP 0.0.0.0:8080 0.0.0.0:0 LISTENING まだプログラムは完成していないのでこれ以上は何も起こりません。''Ctrl + c'' でスクリプトを停止して下さい。 \\ ===== チャットロジックの実装 ===== 先に作成した Chat クラスのスケルトンにロジックを追加します。 メッセージを送信するために着信の接続を追跡し、ここでは [[https://www.php.net/manual/ja/class.splobjectstorage.php|SplObjectStorage]] と呼ばれるコンテナに格納します。このストレージコンテナは、オブジェクトを格納するように構築されています。 > [[https://www.php.net/manual/ja/class.splobjectstorage.php|SplObjectStorage]] は、PHP 5.2 以降に搭載された便利なコンテナクラスです。 {{fa>folder-open-o}} ** {Project-Folder}/src/Chat.php ** clients = new \SplObjectStorage; } public function onOpen(ConnectionInterface $conn) { // Store the new connection to send messages to later $this->clients->attach($conn); echo "New connection! ({$conn->resourceId})\n"; } public function onMessage(ConnectionInterface $from, $msg) { $numRecv = count($this->clients) - 1; echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n" , $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's'); foreach ($this->clients as $client) { if ($from !== $client) { // The sender is not the receiver, send to each client connected $client->send($msg); } } } public function onClose(ConnectionInterface $conn) { // The connection is closed, remove it, as we can no longer send it messages $this->clients->detach($conn); echo "Connection {$conn->resourceId} has disconnected\n"; } public function onError(ConnectionInterface $conn, \Exception $e) { echo "An error has occurred: {$e->getMessage()}\n"; $conn->close(); } } * __construct --- ''SplObjectStorage''オブジェクトを作成します * onOpen --- 着信した接続を ''SplObjectStorage''オブジェクトに格納します * onMessage --- 送信者以外の全ての端末に、着信メッセージを送信します * onClose --- ''SplObjectStorage''オブジェクトからクローズされた接続を除外します * onError --- エラーの発生した接続を閉じます 非常にシンプルなロジックですが、Ratchet の ''MessageComponentInterface'' を理解するには良い例題です。 \\ ===== チャットアプリの実行 ===== アプリケーションが完成したので、実行してみましょう。 まず、コマンドプロンプトでチャットサーバ (''chat-server.php'') を起動します。 php bin/chat-server.php 別のコマンドプロンプトから以下のようにTelnetを起動します。 > Telnet が有効になっていない場合は、[[http://www.y2sunlight.com/ground/doku.php?id=tools:telnet|こちら]]をご覧下さい。 telnet localhost 8080 この時、チャットサーバから以下のメッセージが出力されます。 New connection! (37) さらに、別のコマンドプロンプトからもTelnetを起動します。 telnet localhost 8080 上と同じように、チャットサーバから2番目のメッセージが出力されます。 New connection! (37) New connection! (48) Telnetを起動した一方のコマンドプロンプトから、メッセージ('' Hello World!'' )を入力すると、他方のウィンドウにメッセージが表示されます。尚、Telnetを終了するには、''ctrl + ]'' でコマンドモードに移行し、''quit'' コマンドを入力します。 ここまではTCPレベルのアプローチです。主な機能は MessageComponentInterface に集約されており、イベントハンドリングが主体で、WebSocketAPI はまだ機能していません。 \\ ===== WebSocketへの対応 ===== 基本的なチャットアプリケーションが機能するようになったので、今度はWebブラウザでそれが機能するようにチャットサーバを変更します。 {{fa>folder-open-o}} ** {Project-Folder}/bin/chat-server-ws.php ** run(); [[http://socketo.me/docs/websocket|WsServer]] を使用すると [[https://developer.mozilla.org/ja/docs/Web/API/WebSocket|W3C WebSocketAPI]] を使用するWebブラウザーと通信できるようになります。[[http://socketo.me/docs/http|HttpServer]] は、着信HTTPリクエストの解析を担当します。このクラスの目的は、完全なHTTPヘッダー要求を受信して渡すまでデータをバッファリングすることで、 WebSocket リクエストをアップグレードするためのものです。 このチャットをテストするために、次のファイルを作ります。(HTMLファイルでも問題ありません) {{fa>folder-open-o}} ** {Project-Folder}/src/test-ws.php ** コマンドプロンプトでチャットサーバ(''chat-server-ws.php'')を実行します。 php bin/chat-server-ws.php 次に、2つのブラウザウィンドウを開いて ''test-ws.php'' にアクセスし、ブラウザの開発ツールを開いて下さい。そして、デバックコンソールに次のメッセージが出力されていることを確認して下さい。 Connection established! このメッセージが出ていたら、一方のブラウザのデバックコンソールから次のコードを実行します: conn.send('Hello World!'); この時、他方のデバックコンソールに "Hello World!" が表示されます。 これで Ratchet のチュートリアル「Hello World!」を終わります。 \\