Block Rockin’ Codes

back with another one of those block rockin' codes

node.js で エコーサーバと簡易コンテンツサーバ

追記

ここの内容は Socket.IO のバージョンが v0.7 に上がったことで、古くなりました。
v0.7 については Socket.IO API 解説 - Block Rockin’ Codes を参照してください。

本文

リアルタイムWebハッカソン : ATND に参加しました。

みなさん websocket を用いて開発する感じで、websocket の実装としては node.js を筆頭に
jetty や ChannelAPI の話も聞けてかなり充実したハッカソンだったと思います。

ここで自分は node.js の websocket ライブラリである socket.io をいじってたんですが、
いくつかアプリ書いて、共通するのは以下のような感じだなということで簡単なメモ。

socket.io でエコーサーバ

websocket でリアルタイムなアプリとなると、socket.io を使ってとりあえずエコーサーバ(サーバに送信すると、サーバがクライアント全員にそれを配信する)を実装する感じかと思います。
シンプルに書くとこれだけ。

var socketio = require('socket.io');

// websocket
var io = socketio.listen(server);

io.on('connection', function(client) {
    client.on('message', function(message) {
        //クライアントがメッセージを送って来たら実行される。
        //messageが送って来たデータ
        client.send(message); //送って来た本人だけに送る。
        client.broadcast(message); //送って来た人以外全員に送る。
    });
});

こんな感じに実装しておきます。

で、ここに投げて受け取るだけのクライアントは、 jQuery を使うとこんな感じ。

$(function() {

    // socket の生成
    var port = 8080;
    var socket = new io.Socket(null, {port: port});
    socket.connect();

    // 送信
    $('#button').click(function() {
        var message = $('#input').val();
        socket.send(message);
        return false;
    });

    // 受信
    socket.on('message', function(obj) {
        $('#output').text(obj);
    });

});

あとは、受け取ったクライアント側でそれをどう表現するかですね。



なので後は html やら js ファイルを配信出来れば良いわけです。

簡易コンテンツサーバ

node ではフレームワークを使わない場合は静的コンテンツの配信も自分でやる必要が有ります。
いちいち書くのは面倒くさいので、相対パスから必要なファイルが落ちるように、以下の様なものを書いておくと幸せになれます。

var http = require('http'),
    url = require('url'),
    path = require('path'),
    fs = require('fs'),

var port_local = 8080;

var load_static_file = function(uri, response) {
    // 相対パスで静的リソースを配信する。
    var tmp = uri.split('.');
    var type = tmp[tmp.length - 1];
    var filename = path.join(process.cwd(), uri);

    path.exists(filename, function(exists) {
        if (!exists) {
            response.writeHead(404, {'Content-Type': 'text/plain'});
            response.write('404 Not Found\n');
            response.end();
            return;
        }

        fs.readFile(filename, 'binary', function(err, file) {
            if (err) {
                response.writeHead(500, {'Content-Type': 'text/plain'});
                response.write(err + '\n');
                response.end();
                return;
            }

            switch (type) {
            case 'html':
                response.writeHead(200, {'Content-Type': 'text/html'});
                break;
            case 'js':
                response.writeHead(200, {'Content-Type': 'text/javascript'});
                break;
            case 'css':
                response.writeHead(200, {'Content-Type': 'text/css'});
                break;
            }
            response.write(file, 'binary');
            response.end();
        });
    });
};

これで、ファイルが一通り配れます。

結局リアルタイムウェブって

client.broadcast(message); 

この1行がリアルタイムらしさってことなんですかね。


なので、上のようなエコーサーバとファイルサーバを用意しておいて、
クライアント側でサーバのプッシュをうまいこと取り回す JS を書くって感じになることが多いかと思います。


という意味で上の二つはちょっとしたものを書くなら結構汎用的だと思います。


一応、動く様にした物を github に上げておきます。(socket.io.nodeは npm 等で用意してください。)

http://github.com/Jxck/node-blog-sample

cloneしたら移動して、

% node server.js

で起動して、http://localhost:8080/client.html でアクセス出来ます。

and more

上のような実装でちょっと遊んだら、次に欲しくなりそうなもの。

  • websocket のマルチチャネル
    • この実装では例えばチャットルームを複数作ることができないので、こういうのが欲しくなる。
  • 永続化(DB)
    • node でも DB を使う場合は KVS と合わせるのがトレンドのようです。mongo や redis あたりが多いようです。
  • テンプレートエンジン
    • haml とか使えるんですが、JS 大好きなあなたは jed/fab · GitHub に挑戦すると良いでしょうw


後はアイデア次第ですね。