WebSocket★超簡単!Node.jsとExpressとSocket.IOによるチャットアプリ

2022年6月27日

WebSocketを使ってシンプルでお手軽にチャットアプリを作ってみたいと思います。

尚、WebSocketを使った簡単通信アプリはこちらの記事です。

実行環境

今回使用するOSやNodeのバージョンは次の通りです。

  • OS:Ubuntu 18.04.5 LTS
  • Node.js:12.20.1
  • npm:6.14.11
  • Express:4.16.1
  • Socket.IO:4.5.1

Expressフレームワーク

Expressフレームワークとは

高速でコンパクトなWebフレームワークです。

Expressフレームワークのインストール

npmを使ってExpressのインストールを行います。

npm install express

Socket.IO

Socket.IOとは

WebSocketを使ったリアルタイム双方向通信を実現するためのライブラリです。

Socket.IOのインストール

npmを使ってSocket.IOのインストールを行います。

npm install socket.io

チャットアプリのコーディング

構成

ファイルはサーバー側・クライアント側で一つずつのシンプルな構成です。

app.jsサーバー側
Express・Socket.IO・httpモジュールを使ってクライアントから送られてきたメッセージを送り返す
index.htmlクライアント側
Socket.IOによりサーバーにメッセージを送信

仕組み

1.一台のクライアントからサーバーにメッセージを送信します。

2.サーバーは受け取ったメッセージをその他のクライアントにメッセージを送信し、その他のクライアントはメッセージを受信します。

コード解説

コードの全容

コードの全容は次の通りです。

  • サーバー側
let express = require('express');
let app = express();
let http = require('http').createServer(app);

const PORT = process.env.PORT || 3000;
const { Server } = require('socket.io');
const io = new Server(http);

app.get('/' , (req, res)=>{
   res.sendFile(__dirname + '/index.html');
});

http.listen(PORT, ()=>{
  console.log('server listening. Port:' + PORT);
});

io.on('connection',(socket)=>{
    console.log('a user connected');

    socket.on('disconnect', ()=>{
        console.log('user disconnected');
    });
    socket.on('chat message', (msg)=>{
        console.log('message: ' + msg);
        socket.broadcast.emit('chat message',msg);
    });
});
  • クライアント側
<!DOCTYPE html>
<html>
  <head>
    <title>Socket.IO chat</title>
    <style>
      body { margin: 0; padding-bottom: 3rem; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }

      #form { background: rgba(0, 0, 0, 0.15); padding: 0.25rem; position: fixed; bottom: 0; left: 0; right: 0; display: flex; height: 3rem; box-sizing: border-box; backdrop-filter: blur(10px); }
      #input { border: none; padding: 0 1rem; flex-grow: 1; border-radius: 2rem; margin: 0.25rem; }
      #input:focus { outline: none; }
      #form > button { background: #333; border: none; padding: 0 1rem; margin: 0.25rem; border-radius: 3px; outline: none; color: #fff; }

      #messages { list-style-type: none; margin: 0; padding: 0; }
      #messages > li { padding: 0.5rem 1rem; }
      #messages > li:nth-child(odd) { background: #efefef; }
    </style>
  </head>
  <body>
    <ul id="messages"></ul>
    <form id="form" action="">
      <input id="input" autocomplete="off" />
      <button>Send</button>
    </form>

    <script src="/socket.io/socket.io.js"></script>
    <script>
      let socket = io();

      let messages = document.getElementById('messages');
      let form = document.getElementById('form');
      let input = document.getElementById('input');

      form.addEventListener('submit', (e)=>{
          e.preventDefault();
          if(input.value) {
              socket.emit('chat message', input.value);
              input.value = '';
          };
      });

      socket.on('chat message', (msg)=>{
        let item = document.createElement('li');
        item.textContent = msg;
        messages.appendChild(item);
        window.screenTop(0, document.body.scrollHeight);
      });

    </script>
  </body>
</html>

サーバー側の処理

サーバー側の処理の流れは

  1. 各ライブラリのインスタンス化
  2. index.htmlをトップページに設定
  3. 接続するポートの設定
  4. socketを通した接続とメッセージの送受信

となります。順番に見ていきましょう。

1.各ライブラリのインスタンス化
// Expressの取得
let express = require('express');
// Expressアプリケーション(関数ハンドラ)の作成
let app = express();
// Nodeのhttpモジュールを取得し関数ハンドラappを初期化
let http = require('http').createServer(app);
// ポートを設定(環境変数で設定されているポートprocess.env.PORT、或いは3000を選択)
const PORT = process.env.PORT || 3000;
// Socket.IOを取得
const { Server } = require('socket.io');
// httpサーバーオブジェクトを渡しSocket.IOをインスタンス化
const io = new Server(http);
2.index.htmlをトップページに設定
// ウェブサイトのトップページをGETリクエストによりindex.htmlに割当てています
app.get('/' , (req, res)=>{
   res.sendFile(__dirname + '/index.html');
});
3.接続するポートの設定
// PORTで指定したポート番号によりlistenを開始
http.listen(PORT, ()=>{
  console.log('server listening. Port:' + PORT);
});
4.socketを通した接続とメッセージの送受信
// イベント名'connection' クライアントからサーバーへ接続処理
io.on('connection',(socket)=>{
    console.log('a user connected');

    // イベント名'disconnect' 接続が切断された時の処理
    socket.on('disconnect', ()=>{
        console.log('user disconnected');
    });
    // イベント名'chat message' クライアントが送信したメッセージを受信(仕組み参照)
    socket.on('chat message', (msg)=>{
        console.log('message: ' + msg);
        // イベント名'chat message' メッセージを送信者以外に送信(仕組み参照)
        socket.broadcast.emit('chat message',msg);
    });
});
イベント名解説

イベント名’chat message’で送信されたメッセージは、サーバーから送信者以外にメッセージが送られるようになります。この時にクライアントとサーバーでイベント名を揃える必要があります(同じイベントだと認識する必要がある為)。イベント名がクライアントとサーバーで同じなら’zaku’でも’gundam’でも何でもOK。

クライアント側の処理

クライアント側の処理の流れは

  1. サーバーとの接続
  2. メッセージ送受信用の要素の取得
  3. メッセージをサーバーへ送信
  4. (他のクライアントがメッセージを送信した場合)メッセージをサーバーから受信して表示

となります。順を追ってみていきましょう。

1.サーバーとの接続
// 予めsocket.io.jsを取得しておきます
// <script src="/socket.io/socket.io.js"></script>

// クライアントを初期化しサーバーとの接続処理
let socket = io();
2.メッセージ送受信用の要素の取得
// 受信したメッセージを表示する要素
let messages = document.getElementById('messages');
// メッセージを送信する為の要素
let form = document.getElementById('form');
let input = document.getElementById('input');
3.メッセージをサーバーへ送信
// イベントリスナにsubmitイベントの追加
form.addEventListener('submit', (e)=>{
    // preventDefaultは元の動作(submitイベント)を一旦止める
    e.preventDefault();
    if(input.value) {
        // イベント名'chat message'でサーバーにメッセージを送信
        // (上述の通りイベント名は何でもOK、但しサーバー・クライアント間で名前を統一すること)
        socket.emit('chat message', input.value);
        // 入力したメッセージを空にする
        input.value = '';
    };
});
4.メッセージをサーバーから受信して表示

他のクライアントがメッセージを送信した場合に機能します。

// socket.onによりメッセージが来るのを待機している
// イベント名'chat message'がサーバーから送信された場合にその内容を受け取る
socket.on('chat message', (msg)=>{
  // メッセージ用の要素を作成して追加
  let item = document.createElement('li');
  item.textContent = msg;
  messages.appendChild(item);
  window.screenTop(0, document.body.scrollHeight);
});

チャットアプリの起動と動作確認

チャットアプリの起動方法

  • サーバーの起動
node app.js
  • クライアントの起動

HTMLファイルをブラウザで開いてアドレスを入力します。

localhost:3000

動作確認

複数のブラウザ(Chrome、FireFox、Edge等)を開いてアドレスを入力します。画面が開いたらメッセージを送信してみましょう。メッセージの送受信が出来ていれば成功です。

お疲れ様でした。