免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Socket.io

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

Browser和WebServer間的實(shí)時(shí)數(shù)據(jù)傳輸是一個(gè)很重要的需求,但最早只能通過AJAX輪詢方式實(shí)現(xiàn)。在WebSocket標(biāo)準(zhǔn)沒有推出之前,AJAX輪詢是一種可行的方案。

AJAX輪詢?cè)硎窃O(shè)置定時(shí)器,定時(shí)通過AJAX同步服務(wù)端數(shù)據(jù)。這種方式存在延時(shí)且對(duì)服務(wù)端造成很大負(fù)載。直至2011年,IETF才標(biāo)準(zhǔn)化WebSocket - 一種基于TCP套接字進(jìn)行收發(fā)數(shù)據(jù)的協(xié)議。

Socket.io將數(shù)據(jù)傳輸部分獨(dú)立出來形成engine.io,engine.io對(duì)WebSocket和AJAX輪詢進(jìn)行了封裝,形成了一套API,屏蔽了細(xì)節(jié)差異和兼容性問題,實(shí)現(xiàn)了跨瀏覽器/跨設(shè)備進(jìn)行雙向數(shù)據(jù)通信。

WebSocket 協(xié)議

WebSocket是HTML5新增的一種通信協(xié)議,其特點(diǎn)是服務(wù)端可以主動(dòng)向客戶端推送信息,客戶端也可以主動(dòng)向服務(wù)端發(fā)送信息,是真正的雙向平等對(duì)話,屬于服務(wù)器推送技術(shù)的一種。

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

  1. 相互溝通的Header很小,大概只有2Bytes。
  2. 服務(wù)器不再被動(dòng)的接收到瀏覽器的請(qǐng)求之后才返回?cái)?shù)據(jù),而是在有新數(shù)據(jù)時(shí)就主動(dòng)推送給瀏覽器。

為了建立一個(gè)WebSocket連接,瀏覽器首先要向服務(wù)器發(fā)起一個(gè)HTTP請(qǐng)求,這個(gè)請(qǐng)求和通常的HTTP請(qǐng)求不同,包含了一些附加頭信息,其中附加頭信息Upgrade: WebSocket表明這是一個(gè)申請(qǐng)協(xié)議升級(jí)的HTTP請(qǐng)求。服務(wù)端解析這些頭信息,然后產(chǎn)生應(yīng)答信息返回給客戶端,客戶端和服務(wù)端的WebSocket連接就建立起來了。雙方就可以通過這個(gè)連接通道自由的傳遞信息,并且這個(gè)連接會(huì)持續(xù)直到客戶端或者服務(wù)端的某一方主動(dòng)關(guān)閉連接。

為什么要使用WebSocket呢?

Browser已經(jīng)支持HTTP協(xié)議,為什么還要開發(fā)一種新的WebSocket協(xié)議呢?

我們知道HTTP協(xié)議是一種單向的網(wǎng)絡(luò)協(xié)議,在建立連接后,僅允許Browser/UserAgent向WebServer發(fā)出請(qǐng)求資源后,WebServer才能返回對(duì)應(yīng)的數(shù)據(jù),而WebServer不能主動(dòng)的推送數(shù)據(jù)給Browser/UserAgent。

最初這么設(shè)計(jì)HTTP協(xié)議的原因是,假設(shè)WebServer能主動(dòng)的推送數(shù)據(jù)給Browser/UserAgent,那么Browser/UserAgent就太容易受到攻擊了,一些廣告商也會(huì)主動(dòng)把廣告在不經(jīng)意間強(qiáng)行的傳輸給客戶端,這不能不說是一個(gè)災(zāi)難。那么單向的HTTP協(xié)議給Web應(yīng)用開發(fā)帶哪些問題呢?

現(xiàn)在假設(shè)我們要開發(fā)一個(gè)基于Web的應(yīng)用去獲取當(dāng)前WebServer的實(shí)時(shí)數(shù)據(jù)。例如股票實(shí)時(shí)行情、火車票剩余票數(shù)等。這就需要Browser/UserAgent與WebServer之間反復(fù)進(jìn)行HTTP通信,Browser/UserAgent不斷的發(fā)送請(qǐng)求去獲取當(dāng)前的實(shí)時(shí)數(shù)據(jù)。

常見的方式

  • Polling

Polling輪詢是通過Browser/UserAgent定時(shí)向WebServer發(fā)送HTTP請(qǐng)求,WebServer收到請(qǐng)求后把最新的數(shù)據(jù)發(fā)回給Browser/UserAgent,Browser/UserAgent得到數(shù)據(jù)后將其顯示,然后再定期重復(fù)此過程。

雖然這樣可以滿足需求,但仍存在問題,例如某段時(shí)間內(nèi)WebServer沒有更新的數(shù)據(jù),但Browser/UserAgent仍然會(huì)定時(shí)發(fā)送請(qǐng)求過來詢問,WebServer可以把以前的老數(shù)據(jù)再傳送過去,Browser/UserAgent把這些沒有變化的數(shù)據(jù)再顯示出來。這樣既浪費(fèi)網(wǎng)絡(luò)帶寬,有浪費(fèi)CPU利用率。

如果說把Browser/UserAgent發(fā)送請(qǐng)求的周期調(diào)大一些,就可以緩解這個(gè)問題,但如果WebServer的數(shù)據(jù)更新很快時(shí),這樣又不能保證Web應(yīng)用獲取數(shù)據(jù)的實(shí)時(shí)性。

  • LongPolling

LongPolling是對(duì)Polling的一種改進(jìn)。

Browser/UserAgent發(fā)送HTTP請(qǐng)求到WebServer,此時(shí)WebServer可以做2件事情:

  1. 如果WebServer有新的數(shù)據(jù)需要傳送,就立即把數(shù)據(jù)發(fā)回給Browser/UserAgent,Browser/UserAgent收到數(shù)據(jù)后,立即再發(fā)送HTTP請(qǐng)求給WebServer。

  2. 如果WebServer沒有新數(shù)據(jù)需要傳送,這里與Polling的方式不同的是,WebServer不是立即發(fā)送回應(yīng)給Browser/UserAgent,而是將這個(gè)請(qǐng)求保持住,等待有新的數(shù)據(jù)來到,再去響應(yīng)這個(gè)請(qǐng)求。當(dāng)然,如果WebServer的數(shù)據(jù)長(zhǎng)期沒有更新,一段時(shí)間后,這個(gè)HTTP請(qǐng)求就會(huì)超時(shí),Browser/UserAgent收到超時(shí)信息后,在立即發(fā)送一個(gè)新的HTTP請(qǐng)求給服務(wù)器,然后依次循環(huán)這個(gè)過程。

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

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

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

WebSocket 原理

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

  1. WebSocket是一種雙向通信協(xié)議,在建立連接后,WebSocket服務(wù)器和Browser/UserAgent都能主動(dòng)的向?qū)ο蟀l(fā)送或接收數(shù)據(jù),就像Socket一樣,不同的是WebSocket是一種建立在Web基礎(chǔ)上的簡(jiǎn)單模擬Socket的協(xié)議。

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

建立握手的時(shí)序圖

簡(jiǎn)單說明下WebSocket握手的過程

當(dāng)Web應(yīng)用端調(diào)用new WebSocket(url)接口時(shí),Browser就開始了與地址為URL的WebServer建立握手連接的過程。

  1. Browser與WebSocket服務(wù)器通過TCP三次握手建立連接,如果這個(gè)建立連接失敗,那么后面的過程就不會(huì)執(zhí)行,Web應(yīng)用將收到錯(cuò)誤消息通知。

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

  3. WebSocket服務(wù)器收到Browser/UserAgent發(fā)送來的握手請(qǐng)求后,如果數(shù)據(jù)包數(shù)據(jù)和格式正確,客戶端和服務(wù)端的協(xié)議版本匹配等,就接受本次握手連接,并給出對(duì)應(yīng)的數(shù)據(jù)回復(fù),同樣回復(fù)的數(shù)據(jù)包也是采用HTTP協(xié)議傳輸。

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

WebSocket與TCP、HTTP的關(guān)系

WebSocket與HTTP協(xié)議一樣都是基于TCP的,所以它們都是可靠的協(xié)議,Web開發(fā)者調(diào)用的WebSocketsend函數(shù)在Browser的實(shí)現(xiàn)中最終都是通過TCP的系統(tǒng)接口進(jìn)行傳輸?shù)摹?/p>

WebSocket和HTTP協(xié)議樣都屬于應(yīng)用層協(xié)議,那么它們之間有沒有什么關(guān)系呢?

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

WebSocket與TCP和HTTP的關(guān)系

WebSocket Server

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

Socket.io

socket.io是一個(gè)跨瀏覽器支持WebSocket的實(shí)時(shí)通訊的JS。

http://socket.io/docs/

由于HTTP是無狀態(tài)的協(xié)議,要實(shí)現(xiàn)即時(shí)通訊非常困難。因?yàn)楫?dāng)對(duì)方發(fā)送一條消息時(shí),服務(wù)器并不知道當(dāng)前有哪些用戶等著接收消息,當(dāng)前實(shí)現(xiàn)即時(shí)通訊功能最為普遍的方式就是輪詢機(jī)制。即客戶端定期發(fā)起一個(gè)請(qǐng)求,看看有沒有人發(fā)送消息到服務(wù)器,如果有服務(wù)端就將消息發(fā)給客戶端。這種做法的缺點(diǎn)顯而易見,那么多的請(qǐng)求將消耗大量資源,大量的請(qǐng)求其實(shí)是浪費(fèi)的。

現(xiàn)在,我們有了WebSocket,它是HTML5的新API。WebSocket連接本質(zhì)上就是建立一個(gè)TCP連接,WebSocket會(huì)通過HTTP請(qǐng)求建立,建立后的WebSocket會(huì)在客戶端和服務(wù)端建立一個(gè)持久的連接,直到有一方主動(dòng)關(guān)閉該連接。所以,現(xiàn)在服務(wù)器就知道有哪些用戶正在連接了,這樣通訊就變得相對(duì)容易了。

Socket.io支持及時(shí)、雙向、基于事件的交流,可在不同平臺(tái)、瀏覽器、設(shè)備上工作,可靠性和速度穩(wěn)定。最典型的應(yīng)用場(chǎng)景如:

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

Socket.io實(shí)際上是WebSocket的父集,Socket.io封裝了WebSocket和輪詢等方法,會(huì)根據(jù)情況選擇方法來進(jìn)行通訊。

Node.js提供了高效的服務(wù)端運(yùn)行環(huán)境,但由于Browser對(duì)HTML5的支持不一,為了兼容所有瀏覽器,提供實(shí)時(shí)的用戶體驗(yàn),并為開發(fā)者提供客戶端與服務(wù)端一致的編程體驗(yàn),于是Socket.io誕生了。

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

Socket.io將WebSocket和Polling機(jī)制以及其它的實(shí)時(shí)通信方式封裝成通用的接口,并在服務(wù)端實(shí)現(xiàn)了這些實(shí)時(shí)機(jī)制相應(yīng)代碼。這就是說,WebSocket僅僅是Socket.io實(shí)現(xiàn)實(shí)時(shí)通信的一個(gè)子集,那么Socket.io都實(shí)現(xiàn)了Polling中那些通信機(jī)制呢?

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

Socket.io 基本應(yīng)用

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

服務(wù)端

服務(wù)端socket.io必須綁定一個(gè)http.Server實(shí)例,因?yàn)閃ebSocket協(xié)議是構(gòu)建在HTTP協(xié)議之上的,所以在創(chuàng)建WebSocket服務(wù)時(shí)需調(diào)用HTTP模塊并調(diào)用其下createServer()方法,將生成的server作為參數(shù)傳入socket.io。

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

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

  • 隱式綁定

socket.io內(nèi)部實(shí)例化并監(jiān)聽http.Server,通過實(shí)例化時(shí)傳入端口或者在實(shí)例化后調(diào)用listenattach函數(shù)進(jìn)行隱式綁定。

// 實(shí)例化時(shí)傳入端口require('socket.io')(3000)// 通過listen或attach函數(shù)綁定let io = require('socket.io')io.listen(3000);// io.attach(3000);
  • 顯式綁定
// 實(shí)例化時(shí)綁定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);

建立連接

當(dāng)服務(wù)端和客戶端連接成功時(shí),服務(wù)端會(huì)監(jiān)聽到connectionconnect事件,客戶端會(huì)監(jiān)聽到connect事件,斷開連接時(shí)服務(wù)端對(duì)應(yīng)到客戶端的socket與客戶端均會(huì)監(jiān)聽到disconcect事件。

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

傳輸數(shù)據(jù)

服務(wù)端和客戶端的socket是一個(gè)關(guān)聯(lián)的EventEmitter對(duì)象,客戶端socket派發(fā)的事件可以通過被服務(wù)端的socket接收,服務(wù)端socket派發(fā)的事件也可以被客戶端接收?;谶@種機(jī)制,可以實(shí)現(xiàn)雙向交流。

# 模擬:客戶端不斷發(fā)送隨機(jī)數(shù),當(dāng)隨機(jī)數(shù)大于0.95時(shí),服務(wù)端延遲1s后向客戶端發(fā)送警告以及警告次數(shù)。/*客戶端*/<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>/*服務(wù)端*/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對(duì)象可用來存儲(chǔ)狀態(tài)和自定義數(shù)據(jù)      }      setTimeout(()=>{        socket.emit('warn',   socket.warning);      }, 1000);    }  });});
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
(轉(zhuǎn)載)使用node.js + socket.io + redis實(shí)現(xiàn)基本的聊天室場(chǎng)景
WebSocket
Netty4實(shí)戰(zhàn)第十一章:WebSockets
AndroidAsync :一個(gè)基于nio的異步socket ,http(客戶端服務(wù)器端),websocket,socket.io庫(kù)
搭建即時(shí)通訊服務(wù)器WebSocket,挺容易嘛
關(guān)于 WebSocket 和 HTTP 區(qū)別的思考以及一個(gè)最簡(jiǎn)單的 WebSocket 的客戶端和服務(wù)器實(shí)現(xiàn)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服