不折騰的前端,和鹹魚有什麼區別css
目錄 |
---|
一 目錄 |
二 前言 |
三 WebSocket 和 HTTP |
3.1 (短)輪詢(Polling) |
3.2 長輪詢 |
3.3 WebSocket |
3.4 二者比對 |
四 Socket.io |
4.1 服務端代碼 |
4.2 客戶端代碼 |
4.3 小結 |
五 參考文獻 |
返回目錄
WebSocket
是 HTML5
新增的一種全雙工通訊協議,客戶端和服務器基於 TCP 握手鍊接成功後,二者之間就能夠創建持久性的鏈接,實現雙向數據傳輸。html
返回目錄
咱們知道 HTTP
協議是一種單向的網絡協議,在創建鏈接後,它容許客戶端向服務器發送請求資源後,服務器纔會返回相應的數據,而服務器不能主動推送數據給客戶端。前端
當時爲何這樣設計呢?假設一些不良廣告商主動將一些信息強行推送給客戶端,這不得不說是一個災難。node
因此如今咱們要作股票的實時行情,或者獲取火車票的剩餘票數等,就須要客戶端和服務器之間反覆地進行 HTTP
通信,客戶端不斷地發送 GET
請求,去獲取當前的實時數據。git
下面介紹幾種常見的方式。github
返回目錄
短輪詢模式下,客戶端每隔一段時間向服務器發送 HTTP
請求。web
服務器收到請求後,將最新的數據發回給客戶端。面試
這種狀況下的弊端是很是明顯的:某個時間段服務器沒有更新內容,可是客戶端每隔一段時間發送請求來詢問,而這段時間內的請求是無效的。shell
這就致使了網絡帶寬的浪費。express
返回目錄
長輪詢模式下,客戶端向服務器發出請求,服務器並不必定會當即迴應客戶端,而是查看數據是否有更新。
若是數據更新了的話,那就當即發送數據給客戶端;若是沒有更新,那就保持這個請求,等待有新的數據到來,纔將數據返回給客戶端。
若是服務器長時間沒有更新,那麼一段時間後,請求變會超時,客戶端收到消息後,會當即發送一個新的請求給服務器。
固然這種方式也有弊端:當服務器向客戶端發送數據後,必須等待下一次請求才能將新的數據發出,這樣客戶端接收新數據就有一個最短期間隔。
若是服務器更新頻率較快,那麼就會出現問題。
返回目錄
基於前面的狀況,爲了完全解決服務器主動向客戶端發送數據的問題。
W3C
在 HTML5
中提供了一種讓客戶端與服務器之間進行全雙工通信的網絡技術 WebSocket
。
WebSocket
基於 TCP
協議,是一種全新的、獨立的協議,與 HTTP
協議兼容卻不會融入 HTTP
協議,僅僅做爲 HTML5
的一部分。
返回目錄
基於上面,小夥伴們大概瞭解了 WebSocket
的原因了,這裏再總結對比一下 HTTP
和 WebSocket
。
TCP
鏈接HTTP
是單向數據流,客戶端向服務器發送請求,服務器響應並返回數據;WebSocket
鏈接後能夠實現客戶端和服務器雙向數據傳遞,除非某一端斷開鏈接。HTTP
的 url
使用 http//
或者 https//
開頭,而 WebSocket
的 url
使用 ws//
開頭返回目錄
咱們先來看 WebSocket
的一個使用方式:
const ws = new WebSocket("ws//:xxx.xx", [protocol]) ws.onopen = () => { ws.send('hello') console.log('send') } ws.onmessage = (ev) =>{ console.log(ev.data) ws.close() } ws.onclose = (ev) =>{ console.log('close') } ws.onerror = (ev) =>{ console.log('error') }
WebSocket
實例化後,前端能夠經過上面介紹的方法進行對應的操做,看起來仍是蠻簡單的。
可是,若是想徹底搭建一個 WebSocket
服務端比較麻煩,又浪費時間。
因此:Socket.io
基於 WebSocket
,加上輪詢機制以及其餘的實時通信方面的內容,實現的一個庫,它在服務端實現了實時機制的響應代碼。
也就是說,WebSocket
僅僅是 Socket.io
實現通信的一個子集。
所以,WebSocket
客戶端鏈接不上 Socket.io
服務端,Socket.io
客戶端也連不上 WebSocket
服務端。
下面咱們講解下如何實現一個簡單的聊天。
返回目錄package.json
{ "devDependencies": { "express": "^4.15.2", "socket.io": "^2.3.0" } }
index.js
let express = require('express'); let app = express(); let server = require('http').createServer(app); let io = require('socket.io')(server); let path = require('path'); app.use('/', (req, res, next) => { res.status(200).sendFile(path.resolve(__dirname, 'index.html')); }); // 開啓 socket.io io.on('connection', (client) => { // 若是有新客戶端進來,顯示 ID console.log(`客戶端 ID:${client.id}`); // 監聽客戶端的輸入信息 client.on('channel', (data) => { console.log(`客戶端 ${client.id} 發送信息 ${data}`); io.emit('broadcast', data); }); // 判斷客戶端是否關閉 client.on('disconnect', () => { console.log(`客戶端關閉:${client.id}`); }); }); server.listen(3000, () => { console.log('服務監聽 3000 端口'); });
如上,咱們直接經過 npm i
安裝依賴包後,直接經過 node index.js
能夠開啓服務。
固然,若是小夥伴們想手動裝包,執行下面命令便可:
npm i express socket.io express -D
返回目錄
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Socket.io</title> <script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.slim.js"></script> </head> <body> <input type="text" id="input"> <button id="btn">send</button> <div id="content-wrap"></div> <script> window.onload = function () { let inputValue = null; // 鏈接 socket.io let socket = io('http://localhost:3000'); // 將建立的信息以添加 p 標籤的形式展現成列表 socket.on('broadcast', data => { let content = document.createElement('p'); content.innerHTML = data; document.querySelector('#content-wrap').appendChild(content); }) // 設置輸入框的內容 let inputChangeHandle = (ev) => { inputValue = ev.target.value; } // 獲取輸入框並監聽輸入 let inputDom = document.querySelector("#input"); inputDom.addEventListener('input', inputChangeHandle, false); // 當用戶點擊發送信息的時候,進行數據交互 let sendHandle = () => { socket.emit('channel', inputValue); } let btnDom = document.querySelector("#btn"); btnDom.addEventListener('click', sendHandle, false); // 打頁面卸載的時候,通知服務器關閉 window.onunload = () => { btnDom.removeEventListener('click', sendHandle, false); inputDom.removeEventListener('input', inputChangeHandle, false); } }; </script> </body> </html>
返回目錄
Socket.io
不只支持 WebSocket
,還支持許多種輪詢機制以及其餘實時通訊方式,並封裝了通用的接口。
這些方式包含 Adobe Flash Socket
、Ajax
長輪詢、Ajax multipart streaming
、持久 Iframe
、JSONP
輪詢等。
換句話說,當 Socket.io
檢測到當前環境不支持 WebSocket
時,可以自動地選擇最佳的方式來實現網絡的實時通訊。
這樣,咱們就對 WebSocket
有必定的瞭解,面試的時候就不慌了。
返回目錄
jsliang 的文檔庫由 梁峻榮 採用 知識共享 署名-非商業性使用-相同方式共享 4.0 國際 許可協議 進行許可。<br/>基於 https://github.com/LiangJunrong/document-library 上的做品創做。<br/>本許可協議受權以外的使用權限能夠從 https://creativecommons.org/licenses/by-nc-sa/2.5/cn/ 處得到。