Node.js、Socket.IO、MongoDBでリアルタイムWeb:Node.jsを使ってみよう(1)(2/2 ページ)
Node.jsとSocket.IO、MongoDBを使用して、Webページの更新内容がリアルタイムに画面に反映されるサイトを作ってみた
Socket.IOを使用してチャットアプリ
次は、ExpressとSocket.IOを使用して簡単なチャットアプリを作ってみよう。サンプルコードをGitHubに公開しているので試しにダンロードして実行してみよう。
gitの導入
サンプルコードを試すにはgitを使用してダウンロードするのが一番手軽だ。gitは分散型のバージョン管理システムだ。
Node.jsを使う上でgitを使う必要はないが、Node.jsやExpress、やサンプルのWebアプリなどのコードがGitHubで公開されており、gitを覚えるといろいろ便利になるので、せっかくなのでこの機会に導入してみよう。
gitは分散型のバージョン管理システムだ。今回はgitの詳しい説明はしないが、バージョン管理やGitHubにソースコードを公開/共有するときに便利なので使い方を覚えておいて損はない。
gitはこちらからダウンロードできる。
Linuxはコマンドからインストールすることになるが、その方法の上のリンクに書いてある。
ちなみに、gitはコンソールから実行することになるが、WindowsならTortoiseGit(http://code.google.com/p/Tortoisegit/)を使用すれば、GUIでコミット操作などができるので個人的におすすめだ。
gitがインストールされたかどうかチェックしよう。
$ git --version git version 1.7.11.msysgit.0
インストールされていれば、バージョンが表示されるはずだ。うまく動かない場合は、gitへのパスが通っているかどうか確認しよう。
サンプルのダウンロードと実行
では、サンプルをダンロードして実行してみよう。
$git clone git://github.com/coppieee/node-chat-demo.git $cd node-chat-demo $npm install $node app
アプリを起動したらhttp://localhost:3000にブラウザからアクセスしてください。テキストに文字を入力して、sendボタンを押すと、入力したメッセージが送信される。
1つの画面だけで見た場合、ただ単にブラウザ上だけでテキストを表示しているだけに見える。ページを複数ブラウザで開いてみると、送信したメッセージが別のブラウザにも表示されているのが分かるだろう。
これはsendボタンを押したときに、入力した値をSocket.IOを使用してサーバ経由で他のクライアントに送信している。Socket.IOはWebSocketを使用していて、WebSocketはサーバ/クライアント間での双方向通信をするための規格だ。今回のようなチャットアプリにWebSocketは最適だ。
サンプルコードはExpressで自動生成したテンプレートに30行ほどJavaScriptのコードを追加しただけで、とてもシンプルなコードになっている。少しのぞいてみよう。
サーバサイドの処理
サーバサイドの処理は、socket.ioでクライアントから受信したときに、すべてのクライアントにそのメッセージを送信する処理をapp.jsに追加している。
app.js
//socket.ioのインスタンス作成 var io = require('socket.io').listen(server); //クライアントから接続があった時 io.sockets.on('connection',function(socket){ //クライアントからmessageイベントが受信した時 socket.on('message',function(data){ //念のためdataの値が正しいかチェック if(data && typeof data.text === 'string'){ //メッセージを投げたクライアント以外すべてのクライアントにメッセージを送信する。 socket.broadcast.json.emit('message',{text:data.text}); } }); });
クライアントサイドの処理
クライアントサイドはclient.jsがメインの処理になる。
public/javascript/client.js
jQuery(function($) { "use strict"; //socket.ioのサーバに接続 var socket = io.connect('http://'+location.host+'/'); //サーバからmessageイベントが送信されたとき socket.on('message',function(data){ $('#list').prepend($('<div/>').text(data.text)); }); //sendボタンがクリックされたとき $('#send').click(function(){ var text = $('#input').val(); if(text !== ''){ //サーバにテキストを送信 socket.emit('message',{text:text}); $('#list').prepend($('<div/>').text(text)); $('#input').val(''); } }); });
ボタンをクリックしたらサーバにテキストの内容を送信し、サーバからメッセージを受信したら、テキストを表示している。
たったこれだけのコードで、チャットアプリが作成できた。
Socket.IOを使ったアプリではクライアントからメッセージを受け取り、処理した内容をクライアントに送信するといった処理になる。
Socket.IOのAPIは以下のURLに詳しい説明があるので、そこを参考にしてほしい。
https://github.com/learnboost/socket.io
API自体シンプルなので、一通り読めばSokcet.IOでどのようなことができるか理解できるだろう。
あとは、Socket.IOを使用して、どのようなデータを通信して、どのように表示するか考え、プログラミングすれば、チャットシステムだけでなく、TwitterのようなリアルタイムなSNS、オンラインゲームも作れるようになるだろう。
通信対戦シューティングゲーム
サンプルとしてチャットアプリだけではつまらないので、応用編として対戦型のシューティングゲームを作成した。
これもチャットアプリと同じくExpressとSocket.IOを使用している。
サンプルの実行
サンプルの実行はチャットアプリと同じくgitでコードを取得して実行する。
$ git clone git://github.com/coppieee/node-shooting-demo.git $ cd node-shooting-demo $ npm install $ node app
そしてhttp://localhost:3000/を複数のブラウザで立ち上げてみよう。Startのリンクをクリックでスタートだ。
操作方法は十字キーで自機を操作し、スペースキーで弾を発射する。自機を操作し、相手に弾を当てると相手は消滅する。逆に弾を当てられるとゲームオーバになる。
あくまでデモとして用意したので、見た目はショボイが、コードはなるべく読みやすいように、短くまとめている。JavaScriptのコード量としては、サーバサイドが20行、クライアントサイドが140行程度だ。
ページ構成
ページはトップページとゲーム画面(/game)、ゲームオーバ画面(/gameover)と、3つの画面で構成されている。
それぞれの画面は/views以下のフォルダにindex.ejs、game.ejs、gameover.ejsに対応しており、rotues.jsとapp.jsでURLとの関連付けを行っている。
app.js
app.get('/', routes.index); app.get('/game', routes.game); app.get('/gameover', routes.gameover);
routes/index.js
exports.index = function(req, res){ res.render('index'); }; exports.game = function(req, res){ res.render('game'); }; exports.gameover = function(req, res){ res.render('gameover'); };
遷移はhtmlのaタグに指定しているだけだ。
今回のデモではページ遷移のためにページを複数用意しているが、ページの切り替えもJavaScriptを使用して要素の変更をすればもっとダイナミックなページ遷移も可能だろう。Tech Releaseではページの遷移を1つのHTML上で行っている。切り替えの際にURLも動的に変更しているが、これはHTML5 History APIを使用して実装している。
Socket.IOを使用した通信
Socket.IOでの通信は基本的にチャットと同じように、クライアントから受けたメッセージを、各クライアントにブロードキャストしている。
var io = require('socket.io').listen(server,{'log level':1}); var _userId = 0; io.sockets.on('connection',function(socket){ socket.handshake.userId = _userId; _userId ++; socket.on('player-update',function(data){ socket.broadcast.json.emit('player-update',{userId:socket.handshake.userId,data:data}); }); socket.on('bullet-create',function(data){ socket.broadcast.json.emit('bullet-create',{userId:socket.handshake.userId,data:data}); }); socket.on('disconnect',function(){ socket.broadcast.json.emit('disconnect-user',{userId:socket.handshake.userId}); }); });
クライアントからSocket.IOで送信されるデータは、プレイヤの座標アップデートと、弾の生成イベント、切断イベントを扱っている。
クライアントから接続があったときにuserIdを発行して、それでid管理を行っている。userIdとクライアントを関連付けるため、Socket.IOのセッションとして扱われるsocket.handshake.userIdに格納している。
クライアントの方では、キーボード入力の処理や、衝突判定、自機や弾のアップデート処理を行っている。
自分座標のコントロールや弾の発射は自分自身で更新し、他のクライアントの座標や弾の生成はサーバを経由してSocket.IOで送信されたデータを元に更新している。
クライアント/サーバ間での処理の切り分けとセキュリティ
このサンプルアプリではほとんどの処理をクライアントにさせている。しかしながら、実際アプリを作る際には一部の処理をサーバサイドで行うこともあるだろう。
クライアントサイドで処理する場合は、ユーザーが不正な処理をできないかどうか注意が必要だ。例えばユーザーが位置を操作するメッセージを送信した場合、自機がワープするような処理ができてしまう。他にも衝突判定の処理をサーバに送信しないようにすれば、自機が無敵になってしまう。
このようにクライアントの処理はユーザーがJavaScriptの知識があればいくらでも改造できてしまう。なので、ユーザーに不正をさせたくない処理は基本的にサーバサイドで処理しなければならない。
そういったセキュリティまで考えて実装しようとするとけっこう難しい。
とはいえ、ちょっとしたデモなどを公開する分には、最低限XSSのチェックだけで問題ないだろう。ちなみに今回デモで紹介したチャットとシューティングのソースコードはMITライセンスで改造して公開してOKなので、試しにコードをいじってみて公開してみてはどうだろう。
次回予告
第1回はNode.jsでExpressとSocket.IOを使用したアプリの作成方法を説明した。
弊社で作成した野球盤ゲームHandyStadiumと対戦型ビンゴゲームのまじかるビンゴもExpressとSocket.IOを使用して実装している。
さて、Webアプリとしてすぐに終わるゲームやチャットなどでは、これらの技術で十分実装可能だが、そうでない場合あと1つ必要な技術が必要である。
チャットやブログなどのシステムでは、データを保存しなければならない。そのためにはデータベースが必要になるが、次回はデータベースの1つであるMongoDBの説明をしていく。Tech ReleaseはMongoDBを使用して、記事のデータを保存している。Tech Releaseでは、他にもNode.jsやExpressなどの紹介していない機能を使用して実装している。それは次回の後半で説明していく。
Copyright © ITmedia, Inc. All Rights Reserved.