43
49

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PHPAdvent Calendar 2014

Day 21

PHPでメッセージ送受信(zeromq)

Last updated at Posted at 2014-12-20

真面目なネタは他の方に任せて、
ちょっと違うアイディアになりそうなものを紹介します

zeromqって何だ?

いわゆるメッセージングが可能になるミドルウェアです
メッセージキューにもいろいろあり、
RabbitMQは利用している方も多いのではないでしょうか?
他にもActiveMQ、zeromqなどがあります
今回はその中でも軽量と言われるzeromqを使って
PHPからの送受信、他の言語との通信などにチラっと触れます

zeromqを通じて言語を問わずシステムを構築するのであれば、
phpだったり、Cだったり、node.jsだったり、
socket.ioの様なものを使ったり等の直接的な連携というより、
イベント駆動による連携になるので、
場合によっては作りたいものをシンプルに実装できる事もあります

php meet zeromq

phpでzeromqと言えば、あまり使っているライブラリなどは見かけませんが、
node.jsライクなReactPHPが結構活用していて、pubsubの実装に使っていたりするので
見てみると面白いかもしれません
普段からReactPHP使ってる方は ああ、あれね というネタです

折角なので突っ込んでみて触ってみましょう
導入方法は色々ありますので好きな方法でインストールして下さい

libzmq

libtool autoconf automake は先に入れておいてください

$ git clone git://github.com/zeromq/libzmq.git
$ cd libzmq/
$ ./autogen.sh
$ ./configure && make
$ make install

php-zmq

$ git clone git://github.com/mkoppanen/php-zmq.git
$ cd php-zmq/
$ phpize
$ ./configure && make
$ make install

iniにzmq.soを追記してあげれば完了です
ちなみにこのエクステンションは残念ながらIDEで補完が効かないはずです
最新版のPHPStormでは補完が効くようです(他のIDEはわかりません)
もし補完が効かない方がいましたら、
packagistに補完のためのファイルを置いてくれている方がいますので
これを入れると手っ取り早いです

composer.json
"require": {
    "php": ">=5.4.0",
    "ext-zmq": "*",
    "moriony/php-zmq-stubs": "dev-master"
}

では早速hello worldから
コンソールアプリとして送信側と受信側を用意します
まずは送信

client.php
$queue = new \ZMQSocket(new \ZMQContext(), \ZMQ::SOCKET_REQ);
$queue->connect("tcp://127.0.0.1:5554");
echo $queue->send("hello")->recv();

通信には127.0.0.1:5554を指定しましたがお好みでどうぞ
各クラスなどは公式のリファレンスをみるといいです
(php.net、またはzeromqの方 基本的にCと同じです)
zeromq

zeromqは途切れたりプロセスが死んだ場合でも再接続するまで待ち続けるので、
このソースを実行するとレシーブするまで待ち続けますが
すでにメッセージは送られた状態になります

$ php client.php

続いて受信
送信側が待ってる状態なのでworld を返してあげます
コンソールはそれぞれ別のタブとかでやって下さい

server.php
$server = new \ZMQSocket(new \ZMQContext(), \ZMQ::SOCKET_REP);
$server->bind("tcp://127.0.0.1:5554");

while (true) {
    $request = $server->recv();
    $server->send("world\n");
}
$ php server.php

送信側のコンソールにworldが表示されているはず!
これがベーシックな流れです
ただのworldだった・・

pubsubやってみよう

イベント駆動型のベーシックなものの一つ、pubsubを実装してみましょう
pubsubは皆さんご存知だと思いますが、
出版購読型モデルというそれらしい名前の仕組みで、
publisherが何かイベントを起こすとsubscriberが反応する仕組みを指します
redisのpubsubなどもまさにこの仕組みです
redisなどは使わずにzeromqを通じて実装します
まずはpublisher

publisher.php
$publisher = new \ZMQSocket(new \ZMQContext(), \ZMQ::SOCKET_PUB);
$publisher->bind("tcp://127.0.0.1:5563");

while (true) {
    $publisher->send("FromPub", \ZMQ::MODE_SNDMORE);
    $publisher->send("hello");
    sleep(5);
}

さっきとそんなに大きく変わりませんが、
\ZMQ::SOCKET_PUB でpublishするぞと指定して、
対象チャンネルの FromPub が追加されたくらいです
一瞬で終わると面白くないので、
whileでsleepしながら実行する様にしました
楽しみを取っておく為にもここではまだスクリプトを実行しない様にしておきましょう
まだ待つんだ・・!

次にsubscriber

subscriber.php
$subscriber = new \ZMQSocket(new \ZMQContext(), \ZMQ::SOCKET_SUB);
$subscriber->connect("tcp://127.0.0.1:5563");
$subscriber->setSockOpt(\ZMQ::SOCKOPT_SUBSCRIBE, "FromPub");
while (true) {
    $address = $subscriber->recv();
    $contents = $subscriber->recv();
    printf ("[%s] %s%s", $address, $contents, PHP_EOL);
}

指定したチャンネルのみを受信する様に実装しただけです
subscriberはいくつあっても構わないので
10個くらいタブ等開いてコンソールで実行してみましょう

$ php subscriber.php

そしてpublisherを起動します

$ php publisher.php

5秒おきに全subscriberにメッセージが配信されて表示されているはず です
publisherの対象チャンネルを変更するとsubscriberには配信されなくなります
ちょっと面白くなってきた所で、ここで他の言語と簡単に連携させてみます

http/pubsub/node.js

ブラウザからアクセスして、ブラウザからpublisherへイベントを送信して、
node.jsで実装したsubscriberに配信します

http.php
$socket = new \ZMQSocket(new \ZMQContext(), \ZMQ::SOCKET_REQ);
$socket->connect("tcp://127.0.0.1:5554");

$result = $socket->send("httpリクエスト")->recv();
echo $result;

publisherは先ほどのやつを利用して少しいじります

publisher.php
$context = new \ZMQContext();
$server = new \ZMQSocket($context, \ZMQ::SOCKET_REP);
$server->bind("tcp://127.0.0.1:5554");
while (true) {
    $request = $server->recv();
    if(!is_null($request)) {
        $server->send("get message");
        break;
    }
}

$publisher = new \ZMQSocket($context, \ZMQ::SOCKET_PUB);
$publisher->bind("tcp://127.0.0.1:5563");
while (true) {
    $publisher->send("FromPub", ZMQ::MODE_SNDMORE);
    $publisher->send($request);
    sleep(5);
}

受信したよとブラウザに返答して、
そのメッセージをそのままsubscriberに送信します
次にsubscriberをnode.jsで実装!
zmqのライブラリがあるので簡単です

package.json
{
  "devDependencies": {
    "zmq": "*"
  }
}
$ npm install

サンプルまんまです

subscriber.js
var zmq = require('zmq'),
    subscriber = zmq.socket('sub');

subscriber.connect('tcp://127.0.0.1:5563');
subscriber.subscribe('FromPub');
console.log('Subscriber connected to port 5563');

subscriber.on('message', function(topic, message) {
    console.log(
        'received a message related to:', 
        topic.toString('utf8'), 
        'containing message:', 
        message.toString('utf8')
    );
});

それぞれ起動させて、ブラウザなりcurlなりでアクセスしてみましょう

$ node subscribe.js
$ php publisher.php

node.js側にブラウザからのメッセージが表示されているはず!

こんな感じでzeromqを利用して簡単に実装する事が出来ます
他のメッセージキューを利用してもほとんど同じはずなので
好みで色んなものを使って実装してみてください

43
49
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
43
49

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?