精品伊人久久大香线蕉,开心久久婷婷综合中文字幕,杏田冲梨,人妻无码aⅴ不卡中文字幕

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Socket.io

Socket.io提供了基于事件的實時雙向通訊

Browser和WebServer間的實時數據傳輸是一個很重要的需求,但最早只能通過AJAX輪詢方式實現。在WebSocket標準沒有推出之前,AJAX輪詢是一種可行的方案。

AJAX輪詢原理是設置定時器,定時通過AJAX同步服務端數據。這種方式存在延時且對服務端造成很大負載。直至2011年,IETF才標準化WebSocket - 一種基于TCP套接字進行收發數據的協議。

Socket.io將數據傳輸部分獨立出來形成engine.io,engine.io對WebSocket和AJAX輪詢進行了封裝,形成了一套API,屏蔽了細節差異和兼容性問題,實現了跨瀏覽器/跨設備進行雙向數據通信。

WebSocket 協議

WebSocket是HTML5新增的一種通信協議,其特點是服務端可以主動向客戶端推送信息,客戶端也可以主動向服務端發送信息,是真正的雙向平等對話,屬于服務器推送技術的一種。

在WebSocket API中,瀏覽器和服務器只需要做一個握手的動作,然后瀏覽器和服務端之間就形成了一條快速通道,兩者之間就直接可以數據相互傳送,帶來的好處是

  1. 相互溝通的Header很小,大概只有2Bytes。
  2. 服務器不再被動的接收到瀏覽器的請求之后才返回數據,而是在有新數據時就主動推送給瀏覽器。

為了建立一個WebSocket連接,瀏覽器首先要向服務器發起一個HTTP請求,這個請求和通常的HTTP請求不同,包含了一些附加頭信息,其中附加頭信息Upgrade: WebSocket表明這是一個申請協議升級的HTTP請求。服務端解析這些頭信息,然后產生應答信息返回給客戶端,客戶端和服務端的WebSocket連接就建立起來了。雙方就可以通過這個連接通道自由的傳遞信息,并且這個連接會持續直到客戶端或者服務端的某一方主動關閉連接。

為什么要使用WebSocket呢?

Browser已經支持HTTP協議,為什么還要開發一種新的WebSocket協議呢?

我們知道HTTP協議是一種單向的網絡協議,在建立連接后,僅允許Browser/UserAgent向WebServer發出請求資源后,WebServer才能返回對應的數據,而WebServer不能主動的推送數據給Browser/UserAgent。

最初這么設計HTTP協議的原因是,假設WebServer能主動的推送數據給Browser/UserAgent,那么Browser/UserAgent就太容易受到攻擊了,一些廣告商也會主動把廣告在不經意間強行的傳輸給客戶端,這不能不說是一個災難。那么單向的HTTP協議給Web應用開發帶哪些問題呢?

現在假設我們要開發一個基于Web的應用去獲取當前WebServer的實時數據。例如股票實時行情、火車票剩余票數等。這就需要Browser/UserAgent與WebServer之間反復進行HTTP通信,Browser/UserAgent不斷的發送請求去獲取當前的實時數據。

常見的方式

  • Polling

Polling輪詢是通過Browser/UserAgent定時向WebServer發送HTTP請求,WebServer收到請求后把最新的數據發回給Browser/UserAgent,Browser/UserAgent得到數據后將其顯示,然后再定期重復此過程。

雖然這樣可以滿足需求,但仍存在問題,例如某段時間內WebServer沒有更新的數據,但Browser/UserAgent仍然會定時發送請求過來詢問,WebServer可以把以前的老數據再傳送過去,Browser/UserAgent把這些沒有變化的數據再顯示出來。這樣既浪費網絡帶寬,有浪費CPU利用率。

如果說把Browser/UserAgent發送請求的周期調大一些,就可以緩解這個問題,但如果WebServer的數據更新很快時,這樣又不能保證Web應用獲取數據的實時性。

  • LongPolling

LongPolling是對Polling的一種改進。

Browser/UserAgent發送HTTP請求到WebServer,此時WebServer可以做2件事情:

  1. 如果WebServer有新的數據需要傳送,就立即把數據發回給Browser/UserAgent,Browser/UserAgent收到數據后,立即再發送HTTP請求給WebServer。

  2. 如果WebServer沒有新數據需要傳送,這里與Polling的方式不同的是,WebServer不是立即發送回應給Browser/UserAgent,而是將這個請求保持住,等待有新的數據來到,再去響應這個請求。當然,如果WebServer的數據長期沒有更新,一段時間后,這個HTTP請求就會超時,Browser/UserAgent收到超時信息后,在立即發送一個新的HTTP請求給服務器,然后依次循環這個過程。

LongPolling的方式雖然在某種程度上減少了網絡帶寬和CPU利用率等問題,但仍存在缺陷。

例如WebServer的數據更新速度較快,WebServer在傳送一個數據包給Browser/UserAgent后必須等待Browser的下一個HTTP請求到來,才能傳遞第二個更新的數據包給Browser。這樣的話,Browser顯示實時數據最快的時間為2 xRTT(往返時間)。另外在網絡擁堵的情況下,這個應該是不能讓用戶接受的。另外,由于HTTP數據包的頭部數據量很大(通常有400多個字節),但真正被服務器需要的數據卻很少(有時只有10個字節左右),這樣的數據包在網絡上周期性傳輸,難免對網絡帶寬是一種浪費。

綜上所述,要是在Browser有一種新的網路一些,能支持客戶端和服務端的雙向通信,而且協議的頭部又不那么龐大就very nice了。WebSocket正是肩負這樣的使命登上了Web的舞臺。

WebSocket 原理

WebSocket是一種雙向通信協議,它建立在TCP之上,同HTTP一樣通過TCP來傳輸數據,但與HTTP最大不同的是:

  1. WebSocket是一種雙向通信協議,在建立連接后,WebSocket服務器和Browser/UserAgent都能主動的向對象發送或接收數據,就像Socket一樣,不同的是WebSocket是一種建立在Web基礎上的簡單模擬Socket的協議。

  2. WebSocket需要通過握手連接,類似TCP也需要客戶端和服務端進行握手連接,連接成功后才能相互通信。

建立握手的時序圖

簡單說明下WebSocket握手的過程

當Web應用端調用new WebSocket(url)接口時,Browser就開始了與地址為URL的WebServer建立握手連接的過程。

  1. Browser與WebSocket服務器通過TCP三次握手建立連接,如果這個建立連接失敗,那么后面的過程就不會執行,Web應用將收到錯誤消息通知。

  2. 在TCP建立連接成功后,Browser/UserAgent通過HTTP協議傳送WebSocket支持的版本號、協議的字版本號、原始地址、主機地址等一系列字段給服務端。

  3. WebSocket服務器收到Browser/UserAgent發送來的握手請求后,如果數據包數據和格式正確,客戶端和服務端的協議版本匹配等,就接受本次握手連接,并給出對應的數據回復,同樣回復的數據包也是采用HTTP協議傳輸。

  4. Browser收到服務器回復的數據包后,如果數據包內容、格式都沒有問題的話,就表示本次連接成功,觸發onopen消息,此時Web開發者就可以在此時通過send接口向服務器發送數據。否則,握手連接失敗,Web應用會收到onerror消息,并且能知道連接失敗的原因。

WebSocket與TCP、HTTP的關系

WebSocket與HTTP協議一樣都是基于TCP的,所以它們都是可靠的協議,Web開發者調用的WebSocketsend函數在Browser的實現中最終都是通過TCP的系統接口進行傳輸的。

WebSocket和HTTP協議樣都屬于應用層協議,那么它們之間有沒有什么關系呢?

答案是肯定的,WebSocket在建立握手連接時,數據是通過HTTP協議傳輸的。但在建立連接之后,真正的數據傳輸階段是不需要HTTP參與的。

WebSocket與TCP和HTTP的關系

WebSocket Server

如果要搭建一個WebServer,我們會有很多選擇,市場上也有很多成熟的產品供我們是使用。例如開源的Apache,安裝配置后即可工作。但如果想要搭建一個WebSocket服務器就沒有那么輕松,因為WebSocket是一種新的通信協議,目前還是草案,沒有成為標準,市場上也沒有成熟的WebSocket服務器或Library實現WebSocket協議,我們必須自己手動編碼去解析和組裝WebSocket的數據包。要完成一個WebSocket服務器,估計所有的人都想放棄,不過市場上有幾款比較好的開源Library可供使用。例如PyWebSocket、WebSocket-Node、LibWebSockets等,這些Library已經實現了WebSocket數據包的封裝和解析,我們可以調用這些接口,這在很大程度上減少了我們的工作量。

Socket.io

socket.io是一個跨瀏覽器支持WebSocket的實時通訊的JS。

http://socket.io/docs/

由于HTTP是無狀態的協議,要實現即時通訊非常困難。因為當對方發送一條消息時,服務器并不知道當前有哪些用戶等著接收消息,當前實現即時通訊功能最為普遍的方式就是輪詢機制。即客戶端定期發起一個請求,看看有沒有人發送消息到服務器,如果有服務端就將消息發給客戶端。這種做法的缺點顯而易見,那么多的請求將消耗大量資源,大量的請求其實是浪費的。

現在,我們有了WebSocket,它是HTML5的新API。WebSocket連接本質上就是建立一個TCP連接,WebSocket會通過HTTP請求建立,建立后的WebSocket會在客戶端和服務端建立一個持久的連接,直到有一方主動關閉該連接。所以,現在服務器就知道有哪些用戶正在連接了,這樣通訊就變得相對容易了。

Socket.io支持及時、雙向、基于事件的交流,可在不同平臺、瀏覽器、設備上工作,可靠性和速度穩定。最典型的應用場景如:

  • 實時分析:將數據推送到客戶端,客戶端表現為實時計數器、圖表、日志客戶。
  • 實時通訊:聊天應用
  • 二進制流傳輸:socket.io支持任何形式的二進制文件傳輸,例如圖片、視頻、音頻等。
  • 文檔合并:允許多個用戶同時編輯一個文檔,并能夠看到每個用戶做出的修改。

Socket.io實際上是WebSocket的父集,Socket.io封裝了WebSocket和輪詢等方法,會根據情況選擇方法來進行通訊。

Node.js提供了高效的服務端運行環境,但由于Browser對HTML5的支持不一,為了兼容所有瀏覽器,提供實時的用戶體驗,并為開發者提供客戶端與服務端一致的編程體驗,于是Socket.io誕生了。

# npm安裝socket.op$ npm install --save socket.io

Socket.io將WebSocket和Polling機制以及其它的實時通信方式封裝成通用的接口,并在服務端實現了這些實時機制相應代碼。這就是說,WebSocket僅僅是Socket.io實現實時通信的一個子集,那么Socket.io都實現了Polling中那些通信機制呢?

  • Adobe Flash Socket
    大部分PC瀏覽器都支持的Socket模式,不過是通過第三方嵌入到瀏覽器,不在W3C規范內,可能將逐步被淘汰。況且,大部分手機瀏覽器并不支持此種模式。
  • AJAX Long Polling
    定時向服務端發送請求,缺點是給服務端帶來壓力并出現信息更新不及時的現象。
  • AJAX multipart streaming
    在XMLHttpRequest對象上使用某些瀏覽器支持的multi-part標志,AJAX請求被發送給服務端并保持打開狀態(掛起狀態),每次需要向客戶端發送信息,就尋找一個掛起的HTTP請求響應給客戶端,并且所有的響應都會通過統一連接來寫入。
  • Forever Iframem
    永存的Iframe設計了一個置于頁面中隱藏的iframe標簽,該標簽的src屬性指向返回服務端時間的Servlet路徑。每次在事件到達時,Servlet寫入并刷新一個新的Script標簽,該標簽內部帶有JS代碼,iframe的內容被附加上script標簽,標簽中的內容就會得到執行。這種方式的缺點是接收數據都是由瀏覽器通過HTML標簽來處理的,因此無法知道連接何時在哪一端被斷開,而且iframe標簽在瀏覽器中將被逐步取消。
  • JSONP Polling
    JSONP輪詢基本與HTTP輪詢一樣,不同之處則是JSONP可發出跨域請求。

Socket.io 基本應用

socket.io提供了基于事件的實時雙向通訊,它同時提供了服務端和客戶端的API。

服務端

服務端socket.io必須綁定一個http.Server實例,因為WebSocket協議是構建在HTTP協議之上的,所以在創建WebSocket服務時需調用HTTP模塊并調用其下createServer()方法,將生成的server作為參數傳入socket.io。

var httpServer = require('http').createServer();var io = require('socket.io')(httpServer);httpServer.listen(3000);

綁定http.Server可使用隱式綁定和顯式綁定

  • 隱式綁定

socket.io內部實例化并監聽http.Server,通過實例化時傳入端口或者在實例化后調用listenattach函數進行隱式綁定。

// 實例化時傳入端口require('socket.io')(3000)// 通過listen或attach函數綁定let io = require('socket.io')io.listen(3000);// io.attach(3000);
  • 顯式綁定
// 實例化時綁定let httpServer = require('http').Server();let io = require('socket.io')(httpServer);httpServer.listen(3000);//通過listen或attach綁定let httpServer = require('http').Server();let io = require('socket.io')();io.listen(httpServer);// io.attach(httpServer);httpServer.listen(3000);

Express框架中使用

let app = require('express');let httpServer= require('http').Server(app);let io = require('socket.io')(httpServer);app.listen(3000);

KOA框架中使用

let app = require('koa')();let httpServer = require('http').Server(app.callback());let io = require('socket.io')(httpServer);app.listen(3000);

建立連接

當服務端和客戶端連接成功時,服務端會監聽到connectionconnect事件,客戶端會監聽到connect事件,斷開連接時服務端對應到客戶端的socket與客戶端均會監聽到disconcect事件。

/*客戶端*/<script src='http://cdn.socket.io/stable/socket.io.js'></script><script>// socket.io引入成功后,可通過io()生成客戶端所需的socket對象。let socket = io('http://127.0.0.0:3000');// socket.emmit()用戶客戶端向服務端發送消息,服務端與之對應的是socket.on()來接收信息。socket.emmit('client message', {msg:'hi, server'});// socket.on()用于接收服務端發來的消息socket.on('connect', ()=>{ console.log('client connect server');});socket.on('disconnect', ()=>{ console.log('client disconnect');});</script>/*服務端*/// 服務端綁定HTTP服務器實例let httpServer = require('http').Server();let io = require('socket.io')(httpServer);httpServer.listen(3000);// 服務端監聽連接狀態:io的connection事件表示客戶端與服務端成功建立連接,它接收一個回調函數,回調函數會接收一個socket參數。io.on('connection', (socket)=>{ console.log('client connect server, ok!'); // io.emit()方法用于向服務端發送消息,參數1表示自定義的數據名,參數2表示需要配合事件傳入的參數 io.emmit('server message', {msg:'client connect server success'}); // socket.broadcast.emmit()表示向除了自己以外的客戶端發送消息 socket.broadcast.emmit('server message', {msg:'broadcast'}); // 監聽斷開連接狀態:socket的disconnect事件表示客戶端與服務端斷開連接 socket.on('disconnect', ()=>{ console.log('connect disconnect'); }); // 與客戶端對應的接收指定的消息 socket.on('client message', (data)=>{ cosnole.log(data);// hi server }); socket.disconnect();});

傳輸數據

服務端和客戶端的socket是一個關聯的EventEmitter對象,客戶端socket派發的事件可以通過被服務端的socket接收,服務端socket派發的事件也可以被客戶端接收。基于這種機制,可以實現雙向交流。

# 模擬:客戶端不斷發送隨機數,當隨機數大于0.95時,服務端延遲1s后向客戶端發送警告以及警告次數。/*客戶端*/<script src='http://cdn.socket.io/stable/socket.io.js'></script><script>let socket = io('http://127.0.0.1:3000');let interval = setTimeInterval(()=>{  socket.emit('random', Math.random());}, 500);socket.on('warn', count=>{  console.log('warning count : ' count);});socket.on('disconnect', ()=>{  clearInterval(interval);});</script>/*服務端*/let httpServer = require('http').Server();let io = require('socket.io')(httpServer);httpServer.listen(3000);io.on('connection', socket=>{  socket.on('random', value=>{    console.log(value);    if(value>0.95){      if(typeof socket.warnign==='undefined'){        socket.warning = 0;// socket對象可用來存儲狀態和自定義數據      }      setTimeout(()=>{        socket.emit('warn',   socket.warning);      }, 1000);    }  });});
本站僅提供存儲服務,所有內容均由用戶發布,如發現有害或侵權內容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
(轉載)使用node.js + socket.io + redis實現基本的聊天室場景
WebSocket
Netty4實戰第十一章:WebSockets
AndroidAsync :一個基于nio的異步socket ,http(客戶端服務器端),websocket,socket.io庫
搭建即時通訊服務器WebSocket,挺容易嘛
關于 WebSocket 和 HTTP 區別的思考以及一個最簡單的 WebSocket 的客戶端和服務器實現
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯系客服!

聯系客服

主站蜘蛛池模板: 旺苍县| 同仁县| 茌平县| 剑阁县| 碌曲县| 鱼台县| 阜新市| 高清| 商水县| 桃园市| 聊城市| 拉孜县| 东宁县| 揭阳市| 喀喇| 江阴市| 沅陵县| 尼玛县| 岢岚县| 德化县| 潮安县| 怀集县| 遵化市| 伊春市| 灌云县| 鱼台县| 松溪县| 沭阳县| 玉环县| 晋江市| 漳州市| 土默特左旗| 新泰市| 大庆市| 洮南市| 正蓝旗| 乌拉特前旗| 枣强县| 娱乐| 合川市| 大埔县|