以前に
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を導入する
