以前に
Ratchetを利用してPHPでWebソケット 1
ということで、Ratchetを使ってWebソケットを実装しようというのをやりましたが、それから半年以上たって、やっとデプロイするときがやってきました。(゜∀゜)
時間空きすぎて、Ratchetのことをほとんど覚えていなかった…。
しかし、Ratchetを利用してPHPでWebソケット 1の記事が役に立ったことは言うまでもありません。
下記のサイトに親切にデプロイのやり方が書いてあるので、盲目的にまずやってみます。
http://socketo.me/docs/deploy
まず、HAProxyというものを導入します。
http://www.haproxy.org/
ググるとロードバランサーとしてご利用の方が多そうですが、これをつまりWebsocketと別のポートで接続しなくてもよいようにするために利用します。
これだけで、それなりのボリュームになりそうなので、
Linux初心者がHAProxyを導入する
という記事に書いておきます。
次に、Supervisorというプロセス管理ツールを入れます。
これは、Ratchetを永遠にw生かしておくために入れます。
Linux初心者がSupervisorを導入する
で、デプロイのコードを簡潔に書こうと思います。
構造は下記の通りです。
Ratchet | ---bin | --chat-server,php | --push-server.php | ---src --MyApp --Chat.php --entry.php --Pusher.php
ちなみに、HAProxyによって、Webソケットはポート番号1337ですので、各コードの中で1337を指定しています。
詳しくはここを見てくれってばよ→Linux初心者がHAProxyを導入する
上から順に行きます。
chat-server.php
<?php use Ratchet\Server\IoServer; use MyApp\Chat; require dirname(__DIR__) . '/vendor/autoload.php'; $server = IoServer::factory( new Chat(), 1337 ); $server->run(); ?>
push-server.php
<?php require dirname(__DIR__) . '/vendor/autoload.php'; $loop = React\EventLoop\Factory::create(); $pusher = new MyApp\Pusher; // Listen for the web server to make a ZeroMQ push after an ajax request $context = new React\ZMQ\Context($loop); $pull = $context->getSocket(ZMQ::SOCKET_PULL); $pull->bind('tcp://127.0.0.1:5555'); // Binding to 127.0.0.1 means the only client that can connect is itself $pull->on('message', array($pusher, 'onBlogEntry')); // Set up our WebSocket server for clients wanting real-time updates $webSock = new React\Socket\Server($loop); $webSock->listen(1337, '0.0.0.0'); // Binding to 0.0.0.0 means remotes can connect $webServer = new Ratchet\Server\IoServer( new Ratchet\Http\HttpServer( new Ratchet\WebSocket\WsServer( new Ratchet\Wamp\WampServer( $pusher ) ) ), $webSock ); $loop->run();
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(); } }
entry.php …今回、本体のWebアプリはCakePHP3で作っていますが本体と連動しているのがこいつです。
<?php //CakePHPからincludeで呼び出しされて利用される ini_set( 'display_errors', 1 ); $entryData = array( 'category' => "id".$shipper_id , 'title' => $title , 'article' => 'hogeraccho' , 'when' => time() ); // This is our new stuff $context = new ZMQContext(); $socket = $context->getSocket(ZMQ::SOCKET_PUSH, 'my pusher'); $socket->connect("tcp://localhost:5555"); $socket->send(json_encode($entryData));
Pusher.php
<?php namespace MyApp; use Ratchet\ConnectionInterface; use Ratchet\Wamp\WampServerInterface; class Pusher implements WampServerInterface { /** * A lookup of all the topics clients have subscribed to */ protected $subscribedTopics = array(); public function onSubscribe(ConnectionInterface $conn, $topic) { $this->subscribedTopics[$topic->getId()] = $topic; } /** * @param string JSON'ified string we'll receive from ZeroMQ */ public function onBlogEntry($entry) { $entryData = json_decode($entry, true); // If the lookup topic object isn't set there is no one to publish to if (!array_key_exists($entryData['category'], $this->subscribedTopics)) { return; } $topic = $this->subscribedTopics[$entryData['category']]; // re-send the data to all the clients subscribed to that category $topic->broadcast($entryData); } public function onUnSubscribe(ConnectionInterface $conn, $topic) { } public function onOpen(ConnectionInterface $conn) { } public function onClose(ConnectionInterface $conn) { } public function onCall(ConnectionInterface $conn, $id, $topic, array $params) { // In this application if clients send data it's because the user hacked around in console $conn->callError($id, $topic, 'You are not allowed to make calls')->close(); } public function onPublish(ConnectionInterface $conn, $topic, $event, array $exclude, array $eligible) { // In this application if clients send data it's because the user hacked around in console $conn->close(); } public function onError(ConnectionInterface $conn, \Exception $e) { } }
bin/push-server.php
をSupervisorでの設定により、起動させることによって、Ratchetが常時動作します。
詳しくは→Linux初心者がSupervisorを導入する