【PHP】PHPでWebSocketサーバー - クライアント間の通信 -

以下の記事を参考にWebSocketをサーバーを立てて、docker+FuelPHP上で実行してみました。

http://madroom-project.blogspot.com/2013/04/phpwebsocket.html

なお、FuelPHPについてフレームワークとしての機能は使用していませんので、どんなフレームワークを使っても同じ方法で行けると思います。

ライブラリのインストール

composer.json の require に以下を追加

"cboden/Ratchet": "0.2.*"

以下コマンドでインストール

$ ./composer.phar update --lock

Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Installing textalk/websocket (1.0.3): Loading from cache
Package guzzle/common is abandoned, you should avoid using it. Use guzzle/guzzle instead.
Package guzzle/http is abandoned, you should avoid using it. Use guzzle/guzzle instead.
Package guzzle/parser is abandoned, you should avoid using it. Use guzzle/guzzle instead.
Package guzzle/stream is abandoned, you should avoid using it. Use guzzle/guzzle instead.
Writing lock file
Generating autoload files

実装

WebSocketサーバー側

以下をプロジェクトの適当なディレクトリに配置します。(requireのパスは適時変更)

websocket_test/websocket.php

<?php
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Server\IoServer;
use Ratchet\WebSocket\WsServer;
 
require __DIR__.'/../fuel/vendor/autoload.php';
 
/**
 * websocket.php
 * Send any incoming messages to all connected clients (except sender)
 */
class WebSocket implements MessageComponentInterface {
    protected $clients;
 
    public function __construct() {
        $this->clients = new \SplObjectStorage;
    }   
 
    public function onOpen(ConnectionInterface $conn) {
        $this->clients->attach($conn);
        echo __CLASS__."::".__FUNCTION__."\n";
    }   
 
    public function onMessage(ConnectionInterface $from, $message) {
        echo __CLASS__."::".__FUNCTION__."({$message})\n";
        foreach ($this->clients as $client) {
            if ($from != $client) {
                $client->send("message:" . $message);
            }   
        }   
    }   
 
    public function onClose(ConnectionInterface $conn) {
        $this->clients->detach($conn);
    }   
 
    public function onError(ConnectionInterface $conn, \Exception $e) {
        $conn->close();
        echo __CLASS__."::".__FUNCTION__."\n";
    }   
}
 
// Run the server application through the WebSocket protocol on port 8080
$server = IoServer::factory(new WsServer(new WebSocket()), 9000);
$server->run();

フロント側

public/websocket-test.html

<html>
<head>
<script>
var conn = new WebSocket('ws://localhost:9000');
conn.onopen = function(e) {
    console.log("Connection established!");
};
conn.onmessage = function(e) {
    console.log(e.data);
};
function send() {
    var message = document.getElementById("text").value;
    conn.send(message);
}
</script>
</head>
<body>
<textarea id="text"></textarea>
<input type="button" id="button" value="Send" onclick="send();" />
</body>
</html>

動作確認

WebSocketサーバー起動

以下コマンドでWebSocketサーバーを実行します。

$ php websocket.php

クライアント起動

ブラウザを二つ起動して以下を開く

http://localhost/websocket-test.html

確認

片方のブラウザからテキストを送信すると、もう片方のブラウザでテキストの受信が確認できます。

この時サーバー側のコンソールでは以下のように出力されています。

WebSocket::onOpen
WebSocket::onOpen
WebSocket::onMessage(send test)

これでクライアント間のテキスト通信ができました。チャットなどのようなシステムではこれで良いでしょうが、サーバー側から一方的に送る方法について次回まとめます。

コメント

このブログの人気の投稿

docker-compose up で proxyconnect tcp: dial tcp: lookup proxy.example.com: no such host

docker-compose で起動したweb、MySQLに接続できない事象

【PHP】PHP_CodeSnifferを使う(コーディングルールのカスタマイズ)