テレビ朝日メディアプレックス

BLOGブログ

『Ratchet』を使ってPHPのwebsocketを試してみた

初めまして、テクニカルデザインセンターのゆっちーと申します。
今回より不定期で技術系のお話を書いていければと思いますので宜しくお願いします。

 

第一回目はPHPのライブラリ「Ratchet」を使って、websocketを試してみたいと思います。

【Websocketとは?】
WebSocket(ウェブソケット)は、コンピュータ・ネットワーク用の通信規格の1つである。インターネットの標準化団体であるW3CとIETFがウェブサーバーとウェブブラウザとの間の通信のために規定を予定している双方向通信用の技術規格であり、APIはW3Cが、WebSocket プロトコルはIETFが策定に関与している。プロトコルの仕様は RFC 6455。TCP上で動く。
※wikipediaより引用

 

■今回使用するライブラリ「Ratchet」

http://socketo.me/

 

Websocketを使えば、ユーザに画面リロードを行ってもらう必要なく画面の表示を変えたり出来るようになります。管理ツール上等で、リアルタイムにステータスを変更したり「○○さんが記事を編集中です!」といったお知らせも表示出来て便利ですね!

今回は、Ratchet公式のチュートリアルに従い、簡単なチャットクラスを作っていきたいと思います。
実行環境は特に制限はありませんが、私はwindowsのローカル環境でXAMPPで動作確認を行いました。

それでは早速導入手順を見ていきましょう。

 

1.Composerを使って1ステップでインストール

composerを使えばインストールを簡単に行う事が出来ます。
※Composer自体のダウンロード&インストールは「コチラ」から

composer.jsonは以下のように記述します。

{
    "autoload": {
        "psr-0": {
            "MyApp": "src"
        }
    },
    "require": {
        "cboden/ratchet": "*"
    }
}

 

2.MessageComponentInterfaceに則り応答処理を記述する

Websocketは大きくわけて4つのメソッドによって成り立っています。
今回の場合であれば、既にMessageComponentInterfaceによって以下の4つのInterfaceが宣言されています。

  • onOpen – 最初にクライアントから接続要求があった際に呼ばれる実体化メソッド
  • onMessage – 接続クライアントからメッセージが送信された際に呼ばれる処理メソッド
  • onClose – 接続クライアントから切断要求があった際に呼ばれる処理メソッド
  • onError – 接続に何らかのエラーが発生した際に呼ばれる処理メソッド

上記に従って、応答するメソッドをそれぞれ組み立てていきます。 composer.jsonのあるディレクトリで構いませんので「src」ディレクトリを作成しその中に「MyApp」ディレクトリを作成します。
※ご自身のプロジェクト名を記述する箇所ですが、チュートリアルにあわせる形としています。

「MyApp」の中に「Chat.php」を作り、以下のように記述します。

<?php
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

class Chat implements MessageComponentInterface {
    protected $clients;

    public function __construct() {
        $this->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();
    }
}

 

3.シェルスクリプトプログラムを作成し起動する

「Chat.php」は出来ましたか?
今度はクライアントからの接続を待ち受けるシェルスクリプトを作成します。
composer.jsonのあるディレクトリで構いませんので「bin」ディレクトリを作成し、その中に「chat-server.php」を作り、以下のように記述します。

<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyApp\Chat;

    require_once '{ご自身の環境}\composer\vendor\autoload.php';

    $server = IoServer::factory(
        new HttpServer(
            new WsServer(
                new Chat()
            )
        ),
        8080
    );

    $server->run();

 

作り終わったら、phpを実行します。

php chat-server.php

※待ち受けるスクリプトプログラムになりますので、実行時に画面に何もでなくても問題ありません。

 

4.htmlでクライアントを作ってみる

「chat-server.php」は無事実行出来ましたか?
それでは最後に接続用のクライアントを作成してみましょう。

どこでもよいので、「index.html」を作り、以下のように記述します。

<html>
<script>
var conn = new WebSocket('ws://localhost:8080');
conn.onopen = function(e) {
    console.log("Connection established!");
};

conn.onmessage = function(e) {
    console.log(e.data);
};
</script>
<body>
</body>
</html>

 

5.接続してみる

「index.html」は無事作れましたか?それではいよいよ、出来上がった「index.html」をchrome等で読み込んでみましょう。
問題なければ真っ白な画面が表示され、サーバ側のシェルスクリプトが「New connection! (XX)」と表示されたはずです。

ここから、chromeの開発ツール(F12で実行出来ます)を起動し、Consoleを開いてみましょう。
「Connection established!」と表示されているはずです。

chromeから実行してみたイメージ
Consoleは任意のjavascriptを実行出来るので、ここに以下のコマンドを入力してみてください。

conn.send(‘Hello World!’);

 

サーバ側のウィンドウに送信メッセージが表示されましたでしょうか?
表示されていればwebsocketは完成です!
複数のブラウザで「index.html」を読み込み、リクエストを画面リロードなくやり取りが行える事を確認してみましょう。

 

いかがでしたでしょうか?
サーバ側とクライアント側それぞれの応答処理である「onMessage」をカスタマイズすることで
様々な見せ方を実現する事が出来るので、是非みなさんWebsocketにチャレンジしてみてください!

 

以上、お疲れ様でした。

関連する記事

記事を書いた人

ゆっちー

Webエンジニア歴10年位。最近の業務がコーディングから離れつつあり寂しさを覚えています。

まだまだ若い気でいるつもりですが、少しずつ老いを感じています。好きなものはファーファです。