【初心者向け】Express(Node.js)でSocket.ioを使ったチャットアプリの構築

node.jsのサーバー機能を使ったチャットアプリの作成についてのメモ書きです。フレームワークにexpressを使い、socket.ioにて双方向通信します。
socket.ioというのは簡単に言うとWebSocket 周りの技術を、Node.jsからサクッと簡単に使えるようにしたモジュールです。

使用環境

サーバーの構築

Expressを使ったサーバーを構築します。node.jsはインストール済とします。適当なフォルダを作りそこに移動してから、以下のコマンドを実行します。

npm init
npm install express nodemon  socket.io  

nodemonは開発時において、プログラム修正すれば自動でサーバーを再起動かけてくれる便利なモジュールです。無くても動作しますが、一応インストールします。

フォルダ直下に「public」-「css」-"style.css"ファイルを作りここでスタイルを決めます。また、同じ直下にクライアント側で表示する"index.html"ファイルを作成します。

フォルダ構成

Node.jsフォルダ構成

サーバー

"server.js"にコード実装してローカルサーバーを立ち上げていきます。

server.js

const express = require("express");  // ←expressモジュールを呼び出す
const app = express();                            // ←インスタンス化のような感じ
const PORT = 3001;                                 // ← ローカルで起動するport番号を指定

これでexpressフレームワークが使えるようになります。次にsocket.ioを使えるようにします。

server.js (続き-1)

const http = require("http");                             // ←httpモジュール呼び出し
const server = http.createServer(app);        // ←appを引数にcreateServerを作成
const socketIo = require("socket.io");          // ←socket.ioモジュールを呼び出す
const io = socketIo(server)                                // ←socket.ioの引数にcreateServerを渡す

これでsocket.ioも使えるようになりまたので、サーバーを起動してここまでで問題ないか確認しましょう。server.jsの最後の行に次の待ち受けコマンドを記述します。

server.js (待ち受け)

// appでなくてserverの方を待受状態にします。
server.listen(PORT, ()=>{
    console.log("server is running !!");   // この表示がターミナルで確認できればOKです
});

静的ファイル(CSSファイル、JavaScriptファイル、画像など)の置き場所を、Express標準で実装されているexpress.static ミドルウェア関数を使って指定します。ここではpublicフォルダを作成してそこに置く構成とします。

server.js (ルーチング設定)

app.use(express.static(__dirname + '/public'));

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

socket.ioで使う関数

サーバー側ではクライアント側の接続を受け付けると, io.socketsオブジェクトにconnectionイベントが発生します。使い方は、次の通りです。

io.socket.on(eventname, callback(socketオブジェクト){
   
})

callback関数の引数としてsocketオブジェクトを受け取ることができます。socketオブジェクト名は何でも良いのでここではsocとします。

クライアントからの受信はsoc.on()で受け、クライアントへの送信はio.sockets.emit()メソッドを使用します。ただこのメソッドは、接続しているソケット全てに送信するメソッドになります。
大雑把に言うとonが付けば受信待ちを表し、emitが付けば送信を表します。

io.sockets.emit('server chanel', data.msg)の第1引数は'イベント名'で自由に付けて良く、このイベント名で打2引数のデータを送受信します。(※'server chanel'などのイベント名は、送受信間の紐づけをしますので、間違わないように気をつけてプログラミングしてください。)

従ってクライアントからの送信メッセージは全て、接続している人全員で確認できる簡易チャットとなります。

server.js (socket通信部分)

let counter = 0;    //接続数のカウンタ

io.sockets.on('connect', (soc)=>{
    counter ++;
    console.log(`ユーザーが接続しました。 合計 ${counter} 人です`);

     // --->受信(※後の説明にありますがクライアントはobject形式で送信)
    soc.on('client chanel', (data)=>{
        
        // <---送信(※object形式で返信)
        // io.sockets.emit()は接続しているソケット全てに送信します。
        io.sockets.emit('server chanel', data.msg );   // ...①
    });

    // 切断
    soc.on('disconnect', ()=>{
        counter--;
        console.log(`合計${counter}人に減りました。`);
    });
});

クライアントの構築

jQueryの準備

jQueryをインストールしても良いですが、簡単なCDNを貼り付ける形で検討します。CDNはjQueryの公式サイトGoogleがホストしているサイトなどから入手できます。どちらからでも問題ありませんが、ここでは大手のGoogleから出しているCDNを利用しました。
もちろんJavaScriptだけで実装しても大丈夫です。

クライアントの実装

<script src="/socket.io/socket.io.js"></script>の記述を忘れないようにします。このファイルを別途作る必要はなく、server.jsでsocket.ioと立ち上げておいて、リクエストが来たときに自動生成されるようなので、取り敢えずそう書いておきます。そうすると、以降でioオブジェクトが使えるようになります。

  1. const socket = io.connect(); ←サーバー側と接続するコマンド
  2. socket.emit() ←サーバー側にデータを送信
  3. socket.on()  ←サーバー側からのデータ待ち受け状態

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SocketIoのテスト</title>
    <link rel="stylesheet" type="text/css" href="/css/style.css">
</head>
<body>
    <div class="container">
        <h2>Express チャットアプリ</h2>

        <ul class="chatboard" id="chat_msg">
        </ul>
    
        <form id="socket_form" class="send_form">
            <label>message</label> <input type="text" id="msg">
            <button type="submit" class="submit-btn">送信</button>
        </form>
    </div>
    
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <script src="/socket.io/socket.io.js"></script>

    <script>
        $(function(){
            const socket = io.connect();

           /*************************************
           *   formがsubmitされたときの処理
           * この中でデータを送信する
           **************************************/
            $("#socket_form").on("submit",(e)=>{
                e.preventDefault();

                if ($('#msg').val()){
                     socket.emit('client chanel',{     // ※送信             
                          msg : $('#msg').val(),
                    });
                    $('#msg').val('').focus();
                }
               
            });
 
           /*************************************
           *   サーバーからの受信待ち処理
           * この中でデータを受信する
           **************************************/
            socket.on('server chanel', (data)=>{         // ※受信
                
                // 受信
                let $li = $("<li></li>");
                $li.text(data); 
                $("#chat_msg").append($li);
            })

        });
    </script>
</body>
</html>

動作結果

一斉配信(自分にも配信)

配信に"io.sockets.emit()"メソッドを使います。

一斉送信

io.sockets.on('connect', (soc)=>{   
     // ---受信
    soc.on('client chanel', (data)=>{
         // ---接続しているソケット全てに送信
         io.sockets.emit('server chanel', data.msg);
    });
});

全員に配信する例

接続者全員に送信する。

broadcast配信(自分以外)

配信に"soc.broadcast.emit()"メソッドを使います。

接続しているソケット全てに送信

io.sockets.on('connect', (soc)=>{      
     // ---受信
    soc.on('client chanel', (data)=>{
        //      サーバーに接続されているすべてのソケットにイベントを送信)
         soc.broadcast.emit('server chanel', data.msg);
     });
});

自分以外の人全員に配信

自分には配信されません

以上です。

Follow me!