大阪node学園三時限目に参加してきた

2012/04/29

こちらのイベントに参加してきました。大阪node学園三時限目。(ハッシュタグ #ong3)
今回のテーマはSocket.IO
ハンズオン形式のイベントで、実際に手を動かしながらものを作っていく形です。時系列でつらつら作業ログを残していきます。

Socket.IO を使ってみるハンズオン

事前準備

atndに書かれている状態まで準備していきました。
いろいろとインストール方法はあるようですが、私は、ここからpkgファイルをDLしてインストールしました。
あと、nodebrewというのも入れておきました。

curl https://raw.github.com/hokaccha/nodebrew/master/nodebrew | perl – setup
まずは

今回チャットアプリを作るので、その作業用のディレクトリを作成して、そこから

mkdir chat
cd chat
npm install socket.io

supervisorというものをインストール。環境によってはsudoで実行する必要があるようです。

npm install -g supervisor

で、ここを参考にhttp://socket.io/#how-to-use
app.jsとindex.html を作成

supervisor app.js

を叩きます。で、画面の出力が止まればいいのですが、

DEBUG: Starting child process with ‘node app.js’
info: socket.io started
warn: error raised: Error: listen EACCES
DEBUG: Program app.js exited with code 0

これが出続ける場合、80番portへのアクセス権限がないとうことらしいので、ポート番号を変えてあげる。
app.jsの

    //app.listen(80);
    app
.listen(8080);

index.htmlの

          //var socket = io.connect('http://localhost');
         
var socket = io.connect('http://localhost:8080');

ブラウザをリロードすると、consoleでこれが表示されます。

サーバのsupervisorで、

debug: websocket writing 5:::{“name”:”news”,”args”:[{“hello”:”world”}]}
{ my: ‘data’ }

が表示されました。これでサンプル動作完了

jqueryを利用

jqueryのサイト行って、CDNのjqueryを利用します。
http://docs.jquery.com/Downloading_jQuery#CDN_Hosted_jQuery
なので、index.htmlに

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>

を追記します。

chat表示部分

index.htmlのbody直下に追記

        <!-- chat start -->
       
<div>
                name:
<input id="name" type="text" /><br />
                message:
<input id="msg" type="text" /><br />
               
<input id="send" type="button" value="send" />
       
</div>
       
<!-- chat end -->
jquery動作させる

最後のscriptタグの直前に追記

(function($){
        $
(function(){
                $
("#send").click(function(){
                        alert
("click!");
               
});
       
});
})(jQuery);
</script>

ブラウザでsendボタンをクリックして’click!’が表示されればOK

入力値を拾ってサーバに送信

先ほどのalert部分を修正します。

                        // alert("click!");
                       
var name = $("#name").val();
                       
var msg = $("#msg").val();
                       
// send server
                        socket
.emit("sendMsg",{"name":name,"message":msg});
                       
// clear input
                        $
("#msg").val("");

sendMsgという名前で{“name”:name,”message”:msg}を送っています。
で、サーバサイドで先ほどのサンプルであった、app.jsのmy other event部分を書き換えます。

//      socket.on('my other event', function (data) {
//              console.log(data);
//      });
        socket
.on('sendMsg', function (data) {
               
//console.log(data);
                socket
.emit("sendBack",data);
       
});

これでsendMsgを受信しできます。で、その中で、さらにsemdBackという名前で、クライアントに返してます。なのでこれをindex.htmlで受ける記述を加えます。

        //socket.on('news', function (data) {
        socket
.on('sendBack', function (data) {
                console
.log(data);
               
var resData = JSON.stringify(data);
                $
("body").append(resData);
       
});

サンプルのnewsをsendBackに名前を変えて、受け取ったjsonをconsoleに表示しつつ、bodyタグにも出力。これで受信内容が見やすくなりました。

同時配信

先ほどは、リクエストを投げてきたクライアントのみにプッシュしてましたが、

                //socket.emit("sendBack",data);
                io
.sockets.emit("sendBack",data);

このように書き換え、複数ページ(localhost:8080)を開きます。
そして、sendを押すと。。。。


キターーー

こ、これが新しい流れやで。。。。(すでにそんなに新しくもない)

あとは、適当にjqueryやhtmlで整形してあげれば、OKです。

接続数表示

チャットアプリなので、接続している人数を知りたいという事で、その表示方法です。
app.jsで、接続人数用変数を設定します。
app.listenの下辺りに追記しました。

    //app.listen(80);
    app
.listen(8080);

   
var online = 0;

connectionで追加

io.sockets.on('connection', function (socket) {
       
++online;
        io
.sockets.emit('onlineNum', { online: online });

切断はdisconnectで拾えるようなので、

        socket.on('disconnect',function(){
               
--online;
                io
.sockets.emit('onlineNum', { online: online });
       
});

クライアント側(index.html)には受ける処理を追記

        <div>
                online :
<span id="online">0</span>
       
</div>
・・・(中略)・・・
        socket.on("onlineNum",function(data){
                var resData = data.online;
                $("#online").text(resData);
        })

これで、接続人数の把握ができました!アクセスすると人数増えるし、ページを閉じると人数が減ります。いいね!
※operaはdisconnectの動きが変わるようです。
対策はこちら、http://techdows.com/2010/12/enable-websockets-in-opera-11.html

  • アドレスバーに「opera:config#Enable%20WebSockets」と入力してEnter
  • Enable WebSockets をチェック

みんなで、socket.io

会場を提供してもらってるファーストサーバさんのnode-ninja上に、@kamiyamさん作成のチャットを動かして、みんなでチャット大会。
が、セキュリティー対策行ってなかったので、みんな好き勝手タグを埋め込むハッキング大会に・・・w
(ということで今は閉鎖されてます)

名前空間による接続数の管理

チャットルーム等を想定する場合、1ルームの接続数を制限したい場合があると思いますので、それを作ります。先ほど作ったchatディレクトリとは別にchat_multiディレクトリを作って、最初からapp.jsとindex.html作り直します。

mkdri chat_multi
cd chat_multi
npm install socket.io

で、再びこちら(http://socket.io/#how-to-use )からRestricting yourself to a namespace.の部分のサンプルをコピペします。ただし、サンプルコードだけだと動きませんので、修正して動作確認できたのをそのまま貼っておきます。
app.js

var app = require('http').createServer(handler)
 
, io = require('socket.io').listen(app)
   
, fs = require('fs')

   
//app.listen(80);
    app
.listen(8081);

function handler (req, res) {
        fs
.readFile(__dirname + '/index.html',
               
function (err, data) {
                       
if (err) {
                                res
.writeHead(500);
                               
return res.end('Error loading index.html');
                       
}

                res
.writeHead(200);
                res
.end(data);
       
});
}


var chat = io
       
.of('/chat')
       
.on('connection', function (socket) {
                socket
.emit('a message', {
                        that
: 'only'
                       
, '/chat': 'will get'
               
});
                chat
.emit('a message', {
                        everyone
: 'in'
                               
, '/chat': 'will get'
               
});
       
});

var news = io
       
.of('/news')
       
.on('connection', function (socket) {
                socket
.emit('item', { news: 'item' });
       
});

index.html

<html>
       
<head>
       
<meta charset="UTF-8">
       
<title>node sample multi chat</title>
</head>
<body>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
        jQuery
(function($){
               
var chat = io.connect("http://localhost:8081/chat");
               
var news = io.connect("http://localhost:8081/news");


                chat
.on('connect', function () {
                        chat
.emit('hi!');
               
});
                                   
                news
.on('news', function () {
                        news
.emit('woot');
               
});


                chat
.on('a message', function(data){
                        console
.log(data);
               
});
                news
.on('item', function(data){
                        console
.log(data);
               
});
       
});
</script>
</body>
</html>

で再び起動

supervisor app.js

このとき、エラーが出る場合、一度、

ps aux | grep node

で余計なプロセスが邪魔してればkillしてみると解決する場合もあります。
余計なコードが含まれているかもしれませんが、一旦私の環境はこれで無事consoleに出力されました。

サンプル解説

chatとnewsという2つの名前空間を定義しています。なのでこれらの空間別に情報のやりとりができるわけです。

最初のサンプルでio.sockets.emitで送ると接続クライアント全てに送っていましたが、これが分けれるようになるわけですね。

が。。。それを確かめるところ迄はいかず、、、ここは要調査です。

ファーストサーバのヤタニさんLT

ハンズオンが一旦終わって、LT開始。node js boot camp の様子を発表してくれました。気になった事をメモ

  • node.jsって何?ってやつは?ここの資料(見つけたら更新予定)
  • meteorの話とか、Hot Code Push 、SockJSなど。
  • ロードバランサーを挟む場合は、socket.ioではなくwebsocketを使った方がいい。socket.ioはつかえない?

感想・まとめ

13:00〜19:00という長丁場にも関わらず楽しく過ごせたし、あっという間に終わってしまいました。
初めてサーバからのpushを見た感動は大事にしたいですね。

会場を提供し、お菓子も提供してくださったファーストサーバさんに感謝!
あと、@kamiyamさん含めスタッフのみなさまご苦労様でした!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です