Qiitaに書いたやつ

Socket.ioを使って15分でリアルタイムチャットを実装する

JavaScriptSocket.ioECMAScriptwebsocket
2019年04月08日

Socket.ioのチュートリアルをやったのをまとめました。15分もあればsocket.ioを試すことができます。JavaScriptのコードは20行くらいです。

今回は公式のチュートリアルに沿ってリアルタイムチャット機能の実装を試してみました。 ES6で追加されたアロー関数やconstを使ったりjQueryを使わないで実装をしました。

完成図

qiita.gif

Socket.ioに Get Start

公式をみてみると

It requires almost no basic prior knowledge of Node.JS or Socket.IO, so it’s ideal for users of all knowledge levels

このチュートリアルは事前知識が全然なくてもできると書いてある(多分)ので初心者でも安心できる。

mkdir chat-example
cd chat-example

以下のようにpackage.jsonを作成する。

chat-example/package.json
 { 
    "name": "socket-chat-example", 
    "version": "0.0.1",
    "description": "my first socket.io app",
    "dependencies": {}
}

expressでwebサーバーをたてる

npm install --save express@4.15.2
index.js
const app = require('express')();
const http = require('http').Server(app);

app.get('/', function(req, res){
  res.send('<h1>Hello world</h1>');
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});
node index.js

http://localhost:3000/ にアクセスするとHelloWorldが表示される

The-web-framework

チャットアプリの雛形を表示してみる

res.sendでHTMLの文字列を渡していたけど、sendFileメソッドを使うことでhtmlファイルを提供できる。

index.js
const app = require('express')();
const http = require('http').Server(app);

app.get('/', function(req, res){
  res.sendFile(__dirname + '/index.html'); // HTMLファイルを使う
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});

今回のチャットアプリのためのHTMLファイル

index.html
<!doctype html>
<html>
  <head>
    <title>Socket.IO chat</title>
    <style>
     * { margin: 0; padding: 0; box-sizing: border-box; }
     body { font: 13px Helvetica, Arial; }
     form { background: #21bace; padding: 6px; position: fixed; bottom: 0; width: 100%; }
     form input { border: 0; padding: 10px; width: 90%; margin-right: 1%; border-radius: 3px;}
     form button { width: 9%; background: white; border: none; padding: 10px; border-radius: 3px; }
     #messages { list-style-type: none; margin: 0; padding: 0; }
     #messages li { font-size: 16px; padding: 10px 15px; }
     #messages li:nth-child(odd) { background: #eee; }
    </style>
  </head>
  <body>
    <ul id="messages"></ul>
    <form id="form">
      <input id="messageField" autocomplete="off" /><button>Send</button>
    </form>
  </body>
</html>

http://localhost:3000/ にアクセスするとhtmlファイルが表示されているのがわかる。

Socket.ioをインストールする

npm install --save socket.io
index.js
const app = require('express')();
const http = require('http').Server(app);
const io = require('socket.io')(http);

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

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

http.listen(3000);

bodyタグの閉じタグの前に以下を追加する

index.html
<script src="/socket.io/socket.io.js"></script>
 <script>
   const socket = io();
</script>

http://localhost:3000/ にアクセスするとコンソールに出力される 別タブで開いても表示される。

[xxx:chat-example xxx$ node index.js
a user connected
a user connected
a user connected
a user connected

イベントを送信してみる

emitメソッドを使ってプラウザ側からイベントを送る

index.html
<script src="/socket.io/socket.io.js"></script>
 <script>
      document.getElementById('form').addEventListener('submit', (e) => {
        e.preventDefault(); // prevents page reloading
        const messageField = document.getElementById('messageField');
        socket.emit('chat message', messageField.value);
      });
</script>

サーバ側でイベントを受診する

index.js
io.on('connection', (socket) => {
  socket.on('chat message', (msg) => {
    console.log(msg);
  });
});

文字を入力して送信ボタンを押すと、コンソールに入力した文字が出力され、プラウザーサーバー間でのイベントの送受信が正常に行われていることが確認できる。

Emitting-events

イベントを配信する

あるプラウザからイベントを受診した接続されている全てのプラウザ(ユーザー)に向けてイベントを送信します。

index.js
io.on('connection', (socket) => {
  socket.on('chat message', (msg) => {
    io.emit('chat message', msg);
  });
});

プラウザ側でイベントを購読する。

index.html
<html>
 <body>
   <h1>serve HTML file</h1>
   <script src="/socket.io/socket.io.js"></script>
   <script>
     const socket = io();

     document.getElementById('form').addEventListener('submit', (e) => {
       e.preventDefault(); // prevents page reloading
       const messageField = document.getElementById('messageField');
       socket.emit('chat message', messageField.value);
       messageField.value = '';
     });

     socket.on('chat message', function(msg){
       const item = document.createElement('li')
       item.innerText = msg;
       document.getElementById('messages').appendChild(item);
     });
   </script>
 <body>
</html>

Broadcasting

Socket.ioを使ったチャットアプリのソースコード

index.js
const app = require('express')();
const http = require('http').Server(app);
const io = require('socket.io')(http);

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

io.on('connection', (socket) => {
  socket.on('chat message', (msg) => {
    io.emit('chat message', msg);
  });
});

http.listen(3000);
index.html
<!doctype html>
<html>
  <head>
    <title>Socket.IO chat</title>
    <style>
     * { margin: 0; padding: 0; box-sizing: border-box; }
     body { font: 13px Helvetica, Arial; }
     form { background: #21bace; padding: 6px; position: fixed; bottom: 0; width: 100%; }
     form input { border: 0; padding: 10px; width: 90%; margin-right: 1%; border-radius: 3px;}
     form button { width: 9%; background: white; border: none; padding: 10px; border-radius: 3px; }
     #messages { list-style-type: none; margin: 0; padding: 0; }
     #messages li { font-size: 16px; padding: 10px 15px; }
     #messages li:nth-child(odd) { background: #eee; }
    </style>
  </head>
  <body>
    <ul id="messages"></ul>
    <form id="form">
      <input id="messageField" autocomplete="off" /><button>Send</button>
    </form>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      const socket = io();

      document.getElementById('form').addEventListener('submit', (e) => {
        e.preventDefault(); // prevents page reloading
        const messageField = document.getElementById('messageField');
        socket.emit('chat message', messageField.value);
        messageField.value = '';
      });

      socket.on('chat message', function(msg){
        const item = document.createElement('li')
        item.innerText = msg;
        document.getElementById('messages').appendChild(item);
      });
    </script>
  </body>
</html>

Socketを使ってみた感想

この程度のリアルタイムチャット機能を実装するのにJavaScrpt20行程度で済むのは正直驚きました。

同じタグの投稿

2020 churabou