WebSocket是一種在單個TCP鏈接上進行全雙工通訊的協議。這裏咱們發現了一個有趣的詞:」全雙工」,那咱們就來簡單瞭解下通訊方式有哪些!javascript
通訊雙方中,一方固定爲發送端,一方則固定爲接收端。信息只能沿一個方向傳輸。 例如計算機與打印機之間的通訊是單工模式html
說的簡單些就是:我打你你只能忍着!前端
容許數據在兩個方向上傳輸,可是同一時間數據只能在一個方向上傳輸,其其實是切換的單工。 例如HTTP協議:客戶端向服務器發送請求(單向的),而後服務器響應請求(單向的)java
說的簡單些就是:我打你,你忍完後能夠打我,我忍着…node
容許數據在兩個方向上同時傳輸。 例如手機通話,WebSocket就是這個樣子!web
說的簡單些就是:兩我的同時能夠互相打對方ajax
說了這麼多其實目的就是讓你們知道,WebSocket是支持雙向通訊的!express
爲何要支持雙向通訊?單向通訊有什麼問題?仍是從HTTP提及,咱們知道HTTP協議是半雙工的,並且服務器不能主動推送消息給瀏覽器!這個就是他的缺陷。倘若我但願實現一個股票交易系統,可能股價每秒鐘都有變化,可是價格變化了如何通知咱們的客戶端?跨域
我們來看看之前是怎麼實現的!瀏覽器
什麼叫輪詢?就是不停的輪番詢問!說的直白些就是客戶端按期發送請求給服務端。
配段代碼,Talk is cheap,show me your code.
const express = require("express");
const app = express();
// express 靜態服務中間件用來返回靜態文件
app.use(express.static(__dirname));
// 當前價格是100元
let currentPrice = 100;
// 獲取最新價格接口
app.get("/getPrice", (req, res, next) => {
res.send('¥'+currentPrice * Math.random());
});
app.listen(3000);
複製代碼
客戶端不停的發送請求,去服務端獲取最新價格。
<div>當前交易價格: <span id="price"></span></div>
<script> setInterval(() => { fetch('/getPrice'). then(res=>res.text()). then(data=>price.innerHTML = data) }, 1000); </script>
複製代碼
很快咱們就看出了這樣編寫代碼的缺陷!若是數據變化的不快呢,那就會發送不少無心義的請求。每次發送請求都會有HTTP的Header會消耗大量流量,同時也會消耗CPU的利用率!
長輪詢是對短輪詢的改進版,就是當第一個請求回來時再發送下一個請求!
(function poll(){
fetch('/getPrice').
then(res=>res.text()).
then(data=>{price.innerHTML = data;poll()})
})()
複製代碼
問題依舊是顯而易見的!若是服務端數據變化很快,那麼請求數目會更多;若是變化很慢,可能ajax會出現超時的問題。
咱們並不但願每次都建立一個新的請求,此時就可使用Iframe來實現長鏈接
app.get("/getPrice", (req, res, next) => {
setInterval(()=>{
// 不能使用end 不然會中斷請求,咱們要實現的是長鏈接
res.write(` <script> parent.document.getElementById('price').innerHTML = ${currentPrice * Math.random()} </script> `);
},1000);
});
複製代碼
<body>
<div>當前交易價格: <span id="price"></span></div>
<iframe src="/getPrice" frameborder="0"></iframe>
</body>
複製代碼
如今確實能夠利用Iframe實現了長鏈接通訊,可是頁面的狀態一直是加載態!
EventSource 接口用於接收服務器發送的事件。它經過HTTP鏈接到一個服務器,以text/event-stream 格式接收事件, 不關閉鏈接。
<div>當前交易價格: <span id="price"></span></div>
<script> const eventSource = new EventSource('/getPrice'); eventSource.onmessage = function(e){ // 拿到接受到的數據 price.innerHTML = e.data; } </script>
複製代碼
app.get("/getPrice", (req, res, next) => {
res.header('Content-Type','text/event-stream',);
timer = setInterval(()=>{
res.write( // 發送message事件 \n\n表示當前的event-stream通訊結束
`event:message\nid:${id++}\ndata:${currentPrice*Math.random()}\n\n`
);
},1000);
res.on('close',()=>{
clearInterval(timer);
});
});
複製代碼
固然這種方式依舊是單向的,主要是服務端向客戶端推送數據。而且兼容性也不是很美麗~
終於等到你! 雙向通訊的WebSocket讓你欲罷不能!
WebSocket讓客戶端和服務器保有一個持久的鏈接,兩邊能夠在任意時間開始發送數據!它是基於TCP協議的:先來聊聊WebSocket的優點!
ws: a Node.js WebSocket library,ok就是在node中可使用的WebSocket庫!
安裝ws模塊
yarn add ws
複製代碼
服務端開啓WebSocket服務
const WebSocketServer = require('ws').Server;
const ws = new WebSocketServer({port:8888});
ws.on('connection',(socket)=>{ // socket連接個人那我的
console.log('服務端:有人連接我!');
socket.on('message',(data)=>{
console.log(data); // 收到客戶端發來的消息
socket.send('我是服務端'); // 給客戶端發消息
});
});
複製代碼
客戶端連接8888端口的ws服務!
const socket = new WebSocket('ws://localhost:8888');
socket.onopen = function(){ // 連接成功後,發送消息
console.log('客戶端:連接成功');
socket.send('我是客戶端');
}
socket.onmessage = function(e){ // 監聽客戶端發來的信息
console.log(e.data);
}
複製代碼
客戶端和服務端能夠開心的互相通訊啦!
socket.io是一個WebSocket庫,包括了客戶端的js和服務器端的nodejs,剛纔是否是高興的太早了而忘記了兼容性問題?沒錯socket.io就是幫你解決自動根據瀏覽器從WebSocket、AJAX長輪詢、Iframe流等等各類方式中選擇最佳的方式來實現網絡實時應用!
安裝socket.io模塊
yarn add socket.io
複製代碼
經過socket.io創建連接
const express = require("express");
const app = express();
app.use(express.static(__dirname))
const server = require('http').createServer(app); // app自己就是監聽函數
// socket 須要藉助http服務
const io = require('socket.io')(server);
// 劃分路徑 /
io.of('/').on('connection',function(socket){
console.log('連接成功')
socket.on('message',function(msg){
console.log(msg);
socket.send('我是服務端');
});
});
// 監聽3000 端口
server.listen(3000);
複製代碼
// 默認會像瀏覽器中注入socket.io.js腳本
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io.connect('/');
socket.on('connect',()=>{
console.log('連接成功');
socket.send('我是客戶端');
});
// 接收到消息後打印出來
socket.on('message',(data)=>{
console.log(data);
});
</script>
複製代碼
咱們有了socket.io實現雙向通訊是否是很簡單!
以爲本文對你有幫助嗎?請分享給更多人
關注「前端優選」加星標,提高前端技能
關注公衆號,得到更多前端高級技能加我微信:webyouxuan