やさしいsocket.io

# はじめに
非同期通信はハードル高いって思ってる方(昔の自分)へ
ゆっくりしっかり理解していったら、簡単じゃん
ってなるので、チャットルームを作成して楽しんでね

**※`javascript` と `node.js`の知識を前提としております**

# `node.js`のモジュールである`socket.io`の使い方

## 1. 概要
**webSocket**
サーバーからプッシュする（双方向）
たまに対応していないブラウザやバージョンがある

## 2. 導入
```sh
npm install socket.io
```


***
## 3. 基本的な記述方法
**Socket通信**
`emit` データの送信
`on` 接続の待ち受け

### クライアント側
```html:client.html
<!-- ライブラリの取得（CDN） -->
<script src="/socket.io/socket.io.js"></script>
<script>
// Socket接続（コネクション）
const socketio = io();
// サーバーに送信
socketio.emit('c2s', input_msg);
// 待ち受け
socketio.on('s2c', function(msg){
   console.log('ソケットs2c: '+msg);
});
</script>
```

### サーバー側
#### server setup
ExpressとSocket.IOを統合してWebSocketサーバーを作成
```js:server.js
// official
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const socketio = new Server(server);
```
上記をいろいろ省略して記述したものが下記
```js:server.js
// simplex
const express = require('express');
const app = express();
const Server = require('http').Server(app);
```

#### サーバーの起動
```js:server.js
const socketio = require('socket.io')(Server);
Server.listen(config.port);
// Socket接続（コネクション）
socketio('connection',(socket)=>{
   // クライアントに送信
   socket.emit('s2c', server_msg); // only the client
   socketio.emit('s2c', server_msg); // all client
   // 待ち受け
   socket.on('c2s', function(msg){
      console.log('ソケットc2s: '+msg);
   });
})
```
##### ソケット通信で変数を使いたい場合
```js:server.js
// ここ宣言した変数は全クライアントで共通利用
socketio('connection',(socket)=>{
   // ここで宣言した変数は各クライアントで利用
})
```

***
## 4. 応用的な記述方法
### 送信タイミングの指定
```js:client.html
const socketio = io(); // サーバーへ接続
// ソケット接続確立直後に送信
socketio.on('connect', () => {
  // socketID : 001
  socketio.emit('login', my_user_name);
});
```
`connect` イベントはクライアントがサーバーに接続したことを通知するための特別なイベントです。クライアントがサーバーに接続すると、Socket.io は自動的に `connect` イベントを発生させます。
```js:client.html
// ボタン押下時
const form = document.getElementById("chat-form");
form.addEventListener("submit", function(event){
    event.preventDefault(); // イベントに関連するデフォルトの動作を防ぐ
    const input_message = document.getElementById("get-text").value;
    socketio.emit('c2s', input_message); // サーバーに送信
});
// ボタン押下時２
const submitBtn = document.getElementById("submit-btn");
submitBtn.addEventListener("click", ()=>{
    const input_message = document.getElementById("get-text").value;
    socketio.emit('c2s', input_message); // サーバーに送信
});
```

### 複数のデータ(オブジェクト)の送受信
```js:client.html
const sendData = {
   input1 : document.getElementById("chat-input1").value,
   input2 : document.getElementById("chat-input2").value
};
socketio.emit('c2s', sendData); // サーバーに送信
```
```js:server.js
socket.on('c2s',function(msg){ // データ「c2s:msg」を受信したら
   console.log('c2s[input1]: ' + msg.input1);
   console.log('c2s[input2]: ' + msg.input2);
});
```


***
## 5. room

`room`は双方向・リアルタイムデータ送受信を任意の範囲で行うための仕組み。
`room`を使用すると、その部屋に所属するクライアント間のみでデータをやり取りすることが可能。

(ネットワークのマルチキャスト通信みたいなイメージ)
(`socketio.emit('s2c', server_msg); // only the client`がブロードキャスト)
(`socket.emit('s2c', server_msg); // all client`がユニキャスト)

### 動きの流れ
1. クライアントがルーム名(namespace)を送信
   ```js:client.html
   socket.emit('joinRoom', 'room1');
   ```

2. サーバーがルーム名を受け取り、参加
   ```js:server.js
   socket.on('joinRoom', (room) => {
      socket.join(room);
   });
   ```

3. クライアントからの送信はネームスペースを付ける
   ```js:client.html
   const sendData = {
      room: "1",
      message: document.getElementById("message-input").value,
   }
   socket.emit('roomMessage', sendData);
   ```

4. サーバーからの送信はルーム名を付ける
   ```js:server.js
   socket.on('roomMessage', (data)=>{
      socketio.to(data.room).emit('message', data,message);
   });
   ```

5. クライアントが待ち受ける
   ```js:client.js
   socketio.on('message', (msg) => {
      console.log('s2c_msg:', msg);
   });
   ```


***
## 6. まとめ
```html:client.html
<div class="contents">
   <h2>chat space</h2>
   <ul id="chat_output"></ul>
   <form id="chat-form">
      <input type="text" name="get_text" id="get-text">
      <input type="submit" value="GET送信">
   </form>
</div>
<!-- ライブラリの取得（CDN） -->
<script src="/socket.io/socket.io.js"></script>
```

```js:client.js
// Socket接続（コネクション）
const socketio = io();
// ルームに参加する
socketio.on('connect', () => {
   const sendData = {
      chatid: "1"
   }
   socketio.emit ('c2s-join', sendData);
});
// ボタン押下時
const form = document.getElementById("chat-form");
form.addEventListener("submit", function(event){
   event.preventDefault(); // イベントに関連するデフォルトの動作を防ぐ
   const sendData = {
      chatid: "1",
      input: document.getElementById("get-text").value,
   }
   socketio.emit('c2s', sendData);
});
// サーバーからメッセージを受信したときの処理
socketio.on('s2c', (msg) => {
   // htmlに表示
   let ul = document.getElementById("chat_output");
   let li = document.createElement('li');
   li.innerHTML = msg;
   ul.appendChild(li);
});
```

```js:server.js
const express = require('express');
const app = express();
const Server = require('http').Server(app);
const socketio = require('socket.io')(Server);
//　サーバー起動
Server.listen(config.port);

// Socket接続（コネクション）
socketio('connection',(socket)=>{
   // ルームに参加する
   socket.on('c2s-join', (data)=>{
      socket.join(data.chatid);
      console.log(`${socket.id} joined room ${data.chatid}`);
   });
   // 待ち受け
   socket.on('c2s', (msg)=>{
      // クライアントに送信
      socket.emit('s2c', server_msg); // only the client
      socketio.emit('s2c', server_msg); // all client
      socketio.to(data.chatid).emit('s2c', data,input);
   });
   // クライアントが切断したときの処理
   socket.on('disconnect', () => {
      console.log('Disconnected:', socket.id);
   });
})
```