ブラック研究室へようこそ!

ブラック研究室。それは大学院生が放り込まれるかもしれない闇のアジト。在籍時代のエピソード・Web/アプリ開発の備忘録など。

【IT備忘録】リアルタイムお絵かきシステムを作ってみた② 〜Node.jsとSocket.IOの導入方法〜

f:id:blackLab:20180531214347j:plain

 

スマホですーっと線を引くと、PC側でもほぼリアルタイムにすーっと線が引かれる、

まさに「平成教育委員会」的なお絵かき・回答システム、作りたくないですか?

 

前回紹介したのがこちらです。

www.blacklab-blog.net

 

今回、その導入編になります!

 

前提条件・方針

  • さくらVPSサーバー

        (東京・CPU2コア・メモリ1GB・SSD)

  • OS: CentOS 6
  • Webサーバソフト:Nginx+Node.js の連携を実現する

※すでに他のWebページを、Nginxを使ってPHPのサイトを運営しているため、

今回ベースはNginxを使ってHTMLを提供し、Socket.IOでのやりとりのみNode.jsを通す、というやり方を模索しました。

 

f:id:blackLab:20180620112530p:plain

つまり、Webページ(HTML)は、そのままNginxを使ってクライアントに提供しますが、

クライアントがサーバとSocket.IOによる双方向通信をしたいよ!という時だけ、Nginxへ一旦要求をもらって、Node.jsへ転送し、クライアント↔サーバ間をコネクションさせます。

 

難しいことを書きましたが、案外簡単にいけました!

 

① Node.jsとnpmのインストール

Node.jsをインストールします。

sudo yum install nodejs

 

次に、npm(Node.jsのパッケージ管理)をインストール。

これがあれば、Socket.IOなどのライブラリを入れることができます。

sudo yum install npm

 

そして、Socket.IOをインストールします。

# 任意のSocket.IOを動かすディレクトリを作成
sudo mkdir /var/sample
# そこへ移動
cd /var/sample
# npmを初期化
sudo npm init -y
# Socket.IOをインストール
sudo npm install socket.io

 

② NginxとNode.js(Socket.IO)との連携

Nginx未導入であれば、インストールします。

sudo yum install nginx

 

Nginxの設定ファイルを書き換えます。

設定ファイルは、一般的に、/etc/nginx/conf.d/default.confを書き換えればOKでしょう。

僕は、以下の形に書き換えました。

# default.conf

#ここがポイント!Socket.IO通信時、ポート3000番にひねる
upstream io_nodes {
    ip_hash;
    server 127.0.0.1:3000;
}

server {
    listen       80 default_server;
    listen       [::]:80 default_server;
    server_name  _;
    #root         /usr/share/nginx/html;

    # Load configuration files for the default server block.
    include /etc/nginx/default.d/*.conf;

    location / {
        root    /var/www/html;
        index   index.php index.html;
    }

  #PHPとの連携設定(PHP未使用なら不要)
    location ~ \.php$ {
        root           /var/www/html;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        fastcgi_param  PATH_INFO   $fastcgi_path_info;
        include        fastcgi_params;
    }

    location ~ \.inc$ {
        deny all;
    }

  #ここがポイント!
    location /socket.io/ {
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_http_version 1.1;
        proxy_pass http://io_nodes;
    }

    error_page 404 /404.html;
        location = /40x.html {
    }

    error_page 500 502 503 504 /50x.html;
        location = /50x.html {
    }

}

 

保存したら、Nginxを再起動します。

sudo service nginx restart

 

③ 双方向通信の動作確認

では、動作確認として、試しにページ更新不要な、リアルタイムチャットシステムを作ってみましょうか。

 

任意の作業ディレクトリ(今回:/var/sample配下)に、

チャットシステムを司る、javascriptのサーバプログラムを以下のように作ります。

「server.js」としました。

//server.js

// 1.モジュールオブジェクトの初期化
//ポート3000番をリッスン var fs = require("fs"); var server = require("http").createServer(function(req, res) { res.writeHead(200, {"Content-Type":"text/html"}); var output = fs.readFileSync("./index.html", "utf-8"); res.end(output); }).listen(3000); var io = require("socket.io").listen(server); // 2.イベントの定義 io.sockets.on("connection", function (socket) { socket.on("msg", function (data) { console.log(data); io.sockets.emit("public", data); }); // 接続開始カスタムイベント socket.on("connected", function () { }); // メッセージ送信カスタムイベント socket.on("publish", function (data) { io.sockets.emit("publish", data); });

 

そして、チャットのWebページを作ります。

(これは、もちろん、Web公開ディレクトリにです)

「chat.html」

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999" xml:lang="ja" lang="ja">
<head>
    <title>Chat Test</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <script src="//code.jquery.com/jquery-1.11.0.min.js" type="text/javascript"></script>
    <script src="/socket.io/socket.io.js" type="text/javascript"></script>
    <script type="text/javascript">

var socket = io();

socket.on("connected", function () {});  // 接続時
socket.on("disconnect", function (client) {}); // 切断時

socket.on('public', function(msg) {
    console.log(msg);
    $("div[id=chat]").append("<div class='messages'>" + msg + "</div>");
});

$(document).ready(function(){


});

function sendMsg(){
    var msg = $("input[name=msg]").val();
    console.log(msg);
    socket.emit("msg", msg);
}

    </script>
</head>
<body>
    <input type="text" name="msg" size="50" />
    <input type="button" value="送信" onclick="sendMsg();" /><br><br>

    <div id="chat"></div>
</body>
</html>

 

このHTMLでは、以下のように、Socket.IOのライブラリを読み込んでいるのですが、

<script src="/socket.io/socket.io.js" type="text/javascript"></script> 

さきほど、②でNginx↔Node.jsで連携を図れるようにした際、

Nginx側で「/socket.io/」へアクセス要求された時にポート3000番にひねる設定をしましたね。

さらに、Node.jsのプログラム(server.js)は、ポート3000番をリッスンしているため、server.jsへ飛んで、Socket.IOで通信ができるという仕掛けなのです!

 

最後に、server.jsを起動したら、リアルタイムチャットが動き出すはずです。

# server.jsを起動
node server.js

  

f:id:blackLab:20180620124701p:plain

どうでしょうか?

ページを更新しなくても、2つのクライアント間で入力した文字が、リアルタイムに画面に反映されます!

 

 

では、次回はお絵かきのシステムを大公開しちゃいます。