何をするか
前回、socket.ioでサンプルチャットアプリを作る記事をかいたのですが、今回はそれを少し拡張して、phpからsocket.ioにemitできるようにしてみます。備忘として書きます。
公式ページで下記のように書いてありました。
Sending messages from the outside-world
In some cases, you might want to emit events to sockets in Socket.IO namespaces / rooms from outside the context of your Socket.IO processes.There’s several ways to tackle this problem, like implementing your own channel to send messages into the process.
To facilitate this use case, we created two modules:
簡単にいうと、
socket.ioのプロセスの外部から、namespaceやroomにイベントをemitするには、下記の2つ(socket.io-redis/socket.io-emitter)を実装しましょう。
ってことらしいです。ただ、これだけだと、jsからしか呼べないので、rubyとかphpでAPI書いてる場合だとちょっと保守性悪そうです。そこで、下記のツールが使えそうです。
socket.io-php-emitter
A PHP implementation of socket.io-emitter
socket.io-emitterのphp実装版を書いてくれた方がいたので、今回はこれを使って、php経由でsocket.ioの特定のroomにemitしてみます。
今回の環境
- ec2インスタンス (Amazon Linux AMI release 2014.09)
- Apache (v2.2.29)
- PHP (v5.3.29)
- redis (v2.8.19)
- phpredis (v2.2.5)
- socket.io (v1.3.5)
- socket.io-emitter (v0.2.0)
- socket.io-redis (v0.1.4)
手順
※ httpd、php環境は予め準備されているものとします
- redis関連ツールのインストールとredisサーバの起動
- socket.io-php-emitterのインストール(途中必要に応じてcomposerもインストール)
- socket.io-redis, socket.io-emitterのインストール
- server.jsをアップデート & nodeサーバ再起動
- 簡易APIを用意
- iOS側のソースも少しアップデート
- ready to go!
1. redis関連ツールのインストールとredisサーバの起動
redis本体のインストール
AWS EC2にredisをインストールする
以前はmakeしてたんですが、yumでinstallすると秒速且つ設定ファイルなども自動で配置してくれました...ありがとうございます。
redis実行環境を整える
僕の環境だと、/etc/redis.conf
にconfファイルが配置されました。中の設定を少し変更します。
37c37
< daemonize yes
---
> daemonize no
そのあと下記のようにコマンドを打っていきます。
# vm.overcommit_memory=1を現状で反映させる
sysctl vm.overcommit_memory=1
# 末尾に vm.overcommit_memory = 1 を追加
vi /etc/sysctl.conf
# redisログのgroup:userを変更
chown redis:redis /var/log/redis/redis.log
# 実行
/etc/init.d/redis start
# 実行確認
ps ax | grep [r]edis
29143 ? Ssl 0:19 redis-server 127.0.0.1:6379
# サーバ再起動で自動的に実行されるように
chkconfig redis on
# 2~5までonならOK
chkconfig --list redis
※ yumでいれた場合実行スクリプトは、既に /etc/init.d/redis
に配置されていました
※ redisグループ/ユーザも勝手に追加されておりましたのでここでは省略(いつのまに?)
※ 参考その1: Redisインストール
※ 参考その2:さくらのVPSにredisをインストール
phpredisのインストール
sudo yum -y install php-pecl-redis --enablerepo=epel
※ 参考: PHPでRedisを使ってみる
2. socket.io-php-emitterのインストール(途中必要に応じてcomposerもインストール)
composerをインストール
今回つかうツールはcomposerパッケージとしてインストールするので、まずcomposerがないと始まりません。
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
# 必要であればpathをbashrcやzshrcに追加
# PATH=$PATH:/usr/local/bin
# vi ~.bashrc
socket.io-php-emitterのインストール
# documentrootへ移動
cd /var/www/html
# ソースを落とす & ソースディレクトリへ移動
git clone https://github.com/rase-/socket.io-php-emitter.git
cd socket.io-php-emitter/
# composerで一括インストール
# (自分の環境では、the requested PHP extension dom is missing from your systemっていうエラーがでたので、一旦 yum install php-xml して再度 composer installしました)
composer install
3. socket.io-redis, socket.io-emitterのインストール
# server.jsがあるディレクトリまで移動
cd /path/to/server.js
# インストール
npm install socket.io-redis
npm install socket.io-emitter
4. server.jsをアップデート & nodeサーバ再起動
# 2,3行目に下記を追加
1a2,3
> var redis = require('socket.io-redis');
> var adapter = io.adapter(redis({ host: '127.0.0.1', port: 6379 }));
# node-server再度実行
node server
5. 簡易APIを用意
例えばこんな感じの簡易APIをサーバ側に用意しておきます。
<?php
header('Content-type: application/json');
$json_string = file_get_contents('php://input');
$json = json_decode($json_string);
$sepStr = ',';
$param = $json->param;
$params = split($sepStr, $param);
$room = $params[0];
if(empty($room) || empty($param)){
exit;
}
//echo 'post to' . $room;
require('src/Emitter.php');
$redis = new \Redis();
$redis->connect('127.0.0.1', '6379');
$emitter = new SocketIO\Emitter($redis);
$emitter->in($room)->emit('update', $param);
echo json_encode(array('param' => $param));
?>
6. iOS側のソースも少しアップデート
とりあえず、ニックネームを変更すると、http POSTポストが飛ぶようにしました。
該当箇所はこんな感じ。
AFHTTPRequestOperationManager* manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
NSString *postFilePath = [NSString stringWithFormat:@"%@/%@",
kHTTPHostName, kEmitFilePath];
[manager POST:postFilePath
parameters:@{@"param":[param paramStr]}
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSLog(@"posted");
} failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(@"Error: %@", error);
}];
※ ソースは下記においてます。
https://github.com/mitolog/SIOChat
7. ready to go!
6のソースを実行して、1つのroomに2名以上参加してみます。で、自分のnicknameを変更してみると、room内の他のメンバーに 「changed nickname from "hogehoge" to "fugafuga"」という感じでメッセが飛びます。
感想
- 概念的にはなんとなく分かるのだけど、中身がそんなに理解できていないので、要勉強
- ステキな勉強会があったら是非いきたい
(話それるけど)勉強になりそうなもの
- 今更だけどSocket.ioについてまとめてみる
- Socket.IO, Redisを使用し各ゲーム間でプッシュ通知するシステム
- 今日から始めるNode.jsコードリーディング - libuv / V8 JavaScriptエンジン / Node.jsによるスクリプトの実行
以上でした〜。