今回は、WebSocket を触ってみます。
調べつつ、よくあるチャットページを作ってみます。
目次
参考
WebSocket とは
そもそも WebSocket とは何なのか。
HTTP 通信の場合は、クライアントのリクエストに基づき、サーバーがレスポンスを返します。
リソースを要求すると、都度コネクションを作るプロトコルです。
WebSocket は、コネクションを確立するとクライアント・サーバー間でコネクションが確立すると、双方向の通信ができる。
ポイントは、「双方向」。
HTTP と異なり、サーバーからクライアントに情報をプッシュできる。
今回やること
今回は、「Socket.IO」を使って、よくあるチャットを作ってみます。
実装 1
ディレクトリ構成
今回作成したプログラムのディレクトリ構成は、以下のようになります。
server.js
とindex.html
の 2 つを作成します。
1 2 3 4 5 6
| . +---public | +---index.html #クライアントのページ +---node_modules \---src +---server.js #サーバープログラム
|
サーバー側 1
server.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| const path = require("path");
const app = require("express")(); const http = require("http"); const server = http.Server(app); const io = require("socket.io")(server);
const port = process.env.port || 3000;
app.get("/", (req, res) => { res.sendFile(path.join(process.cwd(), "public", "index.html")); });
io.on("connection", (socket) => { socket.on("message", (data) => { io.emit("message", data); }); });
server.listen(port, () => { console.log(`start Server at port:${port}`); });
|
クライアント側 1
css はいつも通り、シンプル一番な、「skeleton」を使います。
index.html1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| <html> <head> <title>chat site</title> <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css" /> </head> <body> <div class="container"> <div> <input type="text" id="message_text" /> <button type="button" id="message_send">Send</button> </div> <div id="messages"> <ul id="message_list"></ul> </div> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script>
<script> $(function () { var socket = io();
var emit = function () { if ($("#message_text").val() != "") { socket.emit("message", $("#message_text").val()); $("#message_text").val(""); } };
socket.on("message", function (data) { $("#message_list").prepend($("<li>").text(data)); });
$("#message_text").keypress(function (event) { if (event.which === 13) { emit(); } }); $("#message_send").click(function () { emit(); }); }); </script> </body> </html>
|
確認 1
node src/server.js
で起動し、ブラウザでlocalhost:3000
にアクセスします。
動作の様子は、次のようになります。
2 つのページの間で、入力を共有できました。
収録した動画は、2 つのページですが 3 つ以上でも OK です。
実装 2
今度は、Socket.IOが提供する room
を使って、チャットルームを作ってみます。
room
を用いると、メッセージの送信範囲を制限できます。
サーバー側 2
server.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| const path = require("path"); const crypto = require("crypto");
const app = require("express")(); const http = require("http"); const server = http.Server(app); const io = require("socket.io")(server);
const port = process.env.port || 3000;
app.get("/", (req, res) => { res.sendFile(path.join(process.cwd(), "public", "index.html")); });
io.on("connection", (socket) => { let room = ""; const time = new Date(); const md5 = crypto.createHash("MD5"); md5.update(time.toString()); let username = md5.digest("hex");
console.log("New Connection!"); socket.on("room_in", (data) => { socket.join(data.room); room = data.value; io.to(room).emit("message", `${username}が入室`); }); socket.on("room_out", () => { io.to(room).emit("message", `${username}が退室`); socket.leave(room); }); socket.on("message", (data) => { io.to(room).emit("message", data); }); socket.on("disconnect", function () { console.log("Disconnected!"); }); });
server.listen(port, () => { console.log(`start Server at port:${port}`); });
|
クライアント側 2
css はいつも通り、シンプル一番な、「skeleton」を使います。
しかし、skeletonでは、disabled がついた要素を見分けにくいので、スタイル を追加しました。
index.html1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
| <html> <head> <title>chat site</title> <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css" /> <style> select:disabled { background-color: gray; } input:disabled { background-color: gray; } button:disabled { background-color: gray; } </style> </head> <body> <div class="container"> <div> <select id="select_rooms"> <option value="room1">ROOM01</option> <option value="room2">ROOM02</option> <option value="room3">ROOM03</option> </select> <button id="room_in_out">in</button> </div> <div> <input type="text" id="message_text" disabled="true" /> <button type="button" id="message_send" disabled="true">Send</button> </div> <div id="messages"> <ul id="message_list"></ul> </div> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script>
<script> $(function () { var socket = io(); var room_state = false;
var emit = function () { if ($("#message_text").val() != "") { socket.emit("message", $("#message_text").val()); $("#message_text").val(""); } };
socket.on("message", function (data) { $("#message_list").prepend($("<li>").text(data)); });
$("#message_text").keypress(function (event) { if (event.which === 13) { emit(); } }); $("#message_send").click(function () { emit(); }); $("#room_in_out").click(function () { var selectRoom = $("#select_rooms").val(); room_state = !room_state;
if (room_state) { socket.emit("room_in", { room: selectRoom }); $("#room_in_out").text("out"); $("#select_rooms").prop("disabled", true);
$("#message_text").prop("disabled", false); $("#message_send").prop("disabled", false);
$("#message_list").empty(); } else { socket.emit("room_out"); $("#room_in_out").text("in"); $("#select_rooms").prop("disabled", false);
$("#message_text").prop("disabled", true); $("#message_send").prop("disabled", true);
$("#message_list").empty(); } }); }); </script> </body> </html>
|
確認 2
確認 1 と同様にnode src/server.js
で起動し、ブラウザでlocalhost:3000
にアクセスします。
動作の様子は、次のようになります。
同じ部屋を指定した時だけ 2 つのページの間で、入力を共有できました。
今回は、WebSocket を使用してみました。
Socket.IO のおかげでかなり簡単に 2 つチャットを作れました。
この前作成した Slackbot のライブラリや mqtt のライブラリで使用されているので使ってはいましたが、使っているだけでした。
理解して活用したいですね。
ではでは。