Node.js + Socket.IOでチャットアプリを作ってみた

Node.js + Socket.IOを使って簡単なチャットアプリを作ってみました。
ベースは『パーフェクトJavaScript (PERFECT SERIES 4)』の「17章 WebSocket」に出てきたサンプルコードです。
今回はこのサンプルコードをSocket.IOを使って書き直してみました。
ソースコードGitHubにアップしています。

サーバサイド

server.js

var io = require('socket.io').listen(8080);

io.sockets.on('connection', function(socket) {
  console.log('onconnection:', socket);

  // クライアントからのイベント'all'を受信する
  socket.on('all', function(data) {
    // イベント名'msg'で受信メッセージを
    // 自分を含む全クライアントにブロードキャストする
    io.sockets.emit('msg', data);
  });

  // クライアントからのイベント'others'を受信する
  socket.on('others', function(data) {
    // イベント名'msg'で受信メッセージを
    // 自分以外の全クライアントにブロードキャストする
    socket.broadcast.emit('msg', data);
  });

  socket.on('disconnect', function() {
    console.log('disconn');
  });
});

サーバサイドの実装です。
イベント名でメッセージの返信先を切り替えています。
イベント名が'all'であればメッセージ送信者を含む全クライアントにブロードキャスト、'others'であればメッセージ送信者以外の全クライアントにブロードキャストしています。

クライアントサイド

client.js

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

$(document).ready(function() {
  $('#text').keydown(function(event) {
    // エンターキーで発言をサーバに送信する
    if (event.keyCode === 13) {
      // イベント名'all'でメッセージをサーバに送信する
      socket.emit('all', {
        action: 'post',
        user: $('#user').val(),
        css: $('#css').val(),
        text: $('#text').val()
      });

    // タイピング中というステータスをサーバに送信する
    } else {
      // イベント名'others'でメッセージをサーバに送信する
      socket.emit('others', {
        action: 'typing',
        user: $('#user').val()
      });
    }
  });

  // サーバからのイベント'msg'を受信する
  socket.on('msg', function(data) {
    switch (data.action) {
      case 'post': // 発言の描画
        $('<li></li>').text(data.user + ': ' + data.text)
                      .attr('style', data.css)
                      .appendTo('body');
        break;
      case 'typing': // タイピング中ステータスの描画
        $('#typing').text(data.user + 'さんがタイピング中です...');
        clearTimeout(timer);
        timer = setTimeout(function() { $('#typing').empty(); }, 3000);
        break;
    }
  });
});

クライアントサイド(JavaScript)の実装です。
発言はイベント名'all'で送信しています。
タイピング中ステータスは相手にだけ表示させたいので、イベント名'others'で送信しています。

chat.html

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>simple chat client powered by socket.io</title>
    <script src="http://localhost:8080/socket.io/socket.io.js"></script>
    <script src="jquery-1.6.4.min.js"></script>
    <script src="client.js"></script>
  </head>
  <body>
    <input id="user">
    <input id="css">
    <input id="text">
    <div id="typing"></div>
  </body>
</html>

クライアントサイド(HTML)の実装です。
シンプルなチャット画面を表示します。

実行

nodeコマンドでサーバを起動させます。

$ node server.js

サーバを起動したら、複数のブラウザでchat.htmlを開きます。
チャット画面から発言を送信すると、Socket.IOサーバ経由で発言がブロードキャストされ、すべてのブラウザのチャット画面に発言が表示されます。

まとめ

Node.js + Socket.IOを使ってみた感想です。

  • サーバサイドでは考慮すべき点がほとんどなかった(クライアントから受け取るイベント名とメッセージの返信先の指定くらい)
  • クライアントサイドでJSONの組み立て方とロジックを変更するだけで、いろいろな機能追加が簡単に実現できた

パーフェクトJavaScript (PERFECT SERIES 4)

パーフェクトJavaScript (PERFECT SERIES 4)