こんにちは、福田です。
突然ですが、リアルタイム感のあるサイトは見ていて楽しいですよね。
今回はPHPのWebSocketサーバーライブラリ+jQueryMobileを使って、同じサイトを見ている全員にリアルタイムでメッセージを表示するシンプルなアプリケーションを作成してみます。
WebSoketのおさらい
WebSoketは、サーバーとブラウザ間における双方向通信(リアルタイムweb)の通信規格です。
他にもリアルタイムwebを実現するための技術としてAjaxやCometなどがありますが、高負荷などのデメリットも目立ちます。WebSocketはそれらを克服して、いいとこ取りをしたものと言えそうです。ただ、IEでは未実装(2012/10/14現在。バージョン10で実装予定)など、使用する際は環境に注意する必要があります。今回は以下の環境で動作を確認しました。
実装環境
- さくらVPS CentOS6.3
- PHP5.3.3
- FIrefox16
- Chrome22
- Sarafi(iOS6)
1.ライブラリをサーバーに配置
以下よりWebSocketサーバーライブラリ「php-websocket」ダウンロードし、サーバー上の任意の場所に解凍します。
https://github.com/lemmingzshadow/php-websocket/downloads
ここでは解凍したディレクトリ名を「lemmingzshadow-php-websocket」とします。
2.アプリケーションのクラスを作成
以下の場所に、Application.phpを継承して新規にクラスを作成します。
lemmingzshadow-php-websocket/server/lib/WebSocket/Application/PopupApplication.php(新規作成)
<?php namespace WebSocket\Application; class PopupApplication extends Application { private $_clients = array(); public function onConnect($client){ $id = $client->getClientId(); $this->_clients[$id] = $client; } public function onDisconnect($client){ $id = $client->getClientId(); unset($this->_clients[$id]); } public function onData($data){ foreach($this->_clients as $sendto){ $sendto->send($data); } } }
3.アプリケーションの登録
以下のファイルを編集し、先ほど作成したアプリケーションクラスを登録します。
lemmingzshadow-php-websocket/server/server.php
//======略======= //WebSocketを使用するドメインとポート番号を指定します。実装する環境に合わせて指定してください。 //$server = new \WebSocket\Server('127.0.0.1', 8000, false); $server = new \WebSocket\Server('www13137ue.sakura.ne.jp', 8000, false); //======略======= //ドメインを許可します。実装する環境に合わせて指定してください。 //$server->setAllowedOrigin('foo.lh'); $server->setAllowedOrigin('www13137ue.sakura.ne.jp'); //======略======= //アプリケーションを登録します。今回は「popup」という名前で登録します。 //$server->run();の前の行に追記してください。 $server->registerApplication('popup', \WebSocket\Application\PopupApplication::getInstance()); //======略=======
※ここで指定するポート番号は、iptablesで開放しておく必要があります。
4.WebSocketサーバーを起動
先ほど編集したserver.phpを実行し、WebSocketサーバーを起動します。
$ php lemmingzshadow-php-websocket/server/server.php
以下のように表示されれば、起動成功です。
2012-10-12 17:48:33 [info] Server created
これでサーバー側の準備は完了です。
5.クライアント側の設定
手順1でダウンロードした
lemmingzshadow-php-websocket/client
ディレクトリ内のファイルを全て、ブラウザからアクセスできる場所に配置します。
そして以下のようなHTMLを、同じ場所に作成します。ここでは、popup.htmlとして作成しました。
※jQueryMobile1.2を使用しています。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <style type="text/css"> <!-- .ui-title {overflow: visible !important; white-space: nowrap; margin:.6em 10% .8em !important;} --> </style> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" /> <script src="http://code.jquery.com/jquery-1.8.2.min.js"></script> <script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script> <script> jQuery(function($) { var socket; //server.phpで登録したアプリケーション「popup」でWebSocketオブジェクトを生成 socket = new WebSocket('ws://www13137ue.sakura.ne.jp:8000/popup'); socket.onopen = function(msg) { $('#status').text('online'); }; socket.onmessage = function(msg) { var jmsg = $.parseJSON(msg.data); $('#res p').text(jmsg.data); $('#res').popup("open", "dialog"); }; socket.onclose = function(msg) { $('#status').text('offline'); }; $('#button').click(function() { var payload; payload = new Object(); payload.action = 'echo'; payload.data = $('#mes').val(); return socket.send(JSON.stringify(payload)); }); }); </script> </head> <body> <div data-role="page"> <div data-role="header"> <h1>WebSocketからpopup</h1> </div> status:<b><span id="status"></span></b> <input type="text" id="mes"> <input type="button" id="button" value="send"> <div id="res" data-role="popup"> <p></p> </div> </div> </body> </html>
WebSocketサーバが起動している状態でブラウザからアクセスし、status:onlineと表示されていればWebSocketで接続しています。
inputからテキストを送信すると、アクセスしている人全員にポップアップで表示されます。
デモはこちらです。同時に2箇所以上からご確認ください。
http://www13137ue.sakura.ne.jp/websocket/popup.html
最後に
今回はjQueryMobileのpopupを使用しましたが、チャット的な利用はもちろんバイナリデータも送受信できることから、お絵かきアプリやサウンドを使ったアプリなど、多くの用途で使えるようです。
以下の記事を参考にさせて頂きました。
使用したライブラリ同梱のサンプルアプリケーションについても、こちらで触れられています。
▼PHPでWebSocket
http://demouth.hatenablog.com/entry/20120102/1325516167