# WebSocket / socket.io 筆記
## 什麼是 WebSocket?
WebSocket是HTML5提供的一種網路協定,只需要進行一次Handshake(交握),就可以讓Client端與Server端保持連線,並且是**雙向**的溝通,Client可向Server用AJAX的方式請求資料,Server也可向Client主動傳輸資料。

參考資料/圖片來源: https://hackmd.io/@Heidi-Liu/javascript-websocket
## 為何使用 WebSocket?
* WebSocket是建立在TCP之上的協議,所有瀏覽器都支援使用
* 為了解決輪詢(Polling)不停消耗效能的問題,節省伺服器的資源
* 格式輕量,且可以傳輸text或binary
* 沒有同源問題,實現Client與Server雙向溝通
* 協議標識是ws,若加密為wss

參考資料/圖片來源: https://www.ruanyifeng.com/blog/2017/05/websocket.html
## Socket / WebSocket / Socket.io 三種差異在哪裡?
分為三個部分
- **軟體抽象層** -- Socket
- **HTML應用層** -- WebSocket 和 Socket.io
其中WebSocket屬於一種「協定」,而Socket.io是封裝WebSocket的框架
PS: `ws` 也是webSocket的套件之一,目前以`Socket.io`為主流(核心是 `Engine.io`)
參考資料(淺顯易懂很詳細!): https://leesonhsu.blogspot.com/2018/07/socketwebsocketsocketio.html
## WebSocket 實作範例
#### Server 端 (後端使用Express)
先安裝express和ws的套件
```
npm i express
npm i ws
```
#### 新建一個server.js的檔案
``` javascript=
// server.js
const express = require('express')
const SocketServer = require('ws').Server
const PORT = 3000
//創建 express 物件,綁定監聽 port , 設定開啟後在 console 中提示
const server = express().listen(PORT, () => {
console.log(`Listening on ${PORT}`)
})
//將 express 交給 SocketServer 開啟 WebSocket 的服務
const wss = new SocketServer({ server })
//當有 client 連線成功時
wss.on('connection', ws => {
console.log('Client connected')
ws.on('message', data => {
data = data.toString() // 收回來是 Buffer 格式、需轉成字串
console.log(data) // 可在 terminal 看收到的訊息
/// 發送給所有client:
let clients = wss.clients //取得所有連接中的 client
clients.forEach(client => {
client.send(`All: ${data}`) // 發送至每個 client
})
})
// 當連線關閉
ws.on('close', () => {
console.log('Close connected')
})
})
```
建好Server後
在終端機輸入 `node server.js` 即可啟動
#### Client 端 (原生JS)
建立 index.html 和 client.js 的檔案
``` html=
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebSocket Server Test</title>
</head>
<body>
<textarea id="txtShow" rows="30" disabled></textarea>
<input id="txtInput" type="text">
<button id="btnSend">送出</button>
<script src="client.js"></script>
</body>
</html>
```
``` javascript =
// client.js
document.addEventListener("DOMContentLoaded", event => {
let keyinDom = document.querySelector('#txtInput')
let showDom = document.querySelector('#txtShow')
document.querySelector("#btnSend").addEventListener('click',() => {
let datetime = new Date()
let txt = `${datetime.toLocaleString() }: ` + keyinDom.value;
ws.send(txt);
})
// 建立 WebSocket
let url = 'ws://localhost:3000'
let ws = new WebSocket(url)
// 監聽連線狀態
ws.onopen = () => {
console.log('open connection')
}
ws.onclose = () => {
console.log('close connection');
}
// 接收 Server 發送的訊息
ws.onmessage = event => {
let txt = event.data
if (!showDom.value) showDom.value = txt
else showDom.value = showDom.value + "\n" + txt
keyinDom.value = ""
}
});
```
## WebSocket API
`new WebSocket()`:建立 WebSocket 的連線
```
var ws = new WebSocket(url, [protocol]);
```
- url 為必填,就是要填 WS Server URL,像範例 ws://localhost:3000/
- protocol 為選填,有多個的話可以寫成陣列
### WebSocket Events
建立好WebSocket的連線後,可以使用這些events觸發事件:
* open:成功和 Server 建立連線時觸發
* message:接收到 Server 端訊息時觸發
* close:關閉連線時觸發
* error:連線發生錯誤時觸發
### WebSocket Methods
* send():發送訊息
* close():關閉連線