Socket.io

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

http://socket.io/docs/

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

現(xiàn)在勤庐,我們有了WebSocket示惊,它是HTML5的新API。WebSocket連接本質(zhì)上就是建立一個TCP連接愉镰,WebSocket會通過HTTP請求建立米罚,建立后的WebSocket會在客戶端和服務(wù)端建立一個持久的連接,直到有一方主動關(guān)閉該連接丈探。所以录择,現(xiàn)在服務(wù)器就知道有哪些用戶正在連接了,這樣通訊就變得相對容易了碗降。

Socket.io支持及時隘竭、雙向、基于事件的交流讼渊,可在不同平臺动看、瀏覽器、設(shè)備上工作爪幻,可靠性和速度穩(wěn)定菱皆。最典型的應(yīng)用場景如:

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

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

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

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

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

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

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

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

服務(wù)端

服務(wù)端socket.io必須綁定一個http.Server實例廊散,因為WebSocket協(xié)議是構(gòu)建在HTTP協(xié)議之上的,所以在創(chuàng)建WebSocket服務(wù)時需調(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)部實例化并監(jiān)聽http.Server,通過實例化時傳入端口或者在實例化后調(diào)用listenattach函數(shù)進(jìn)行隱式綁定幌氮。

// 實例化時傳入端口
require('socket.io')(3000)

// 通過listen或attach函數(shù)綁定
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);

建立連接

當(dāng)服務(wù)端和客戶端連接成功時缭受,服務(wù)端會監(jiān)聽到connectionconnect事件,客戶端會監(jiān)聽到connect事件该互,斷開連接時服務(wù)端對應(yīng)到客戶端的socket與客戶端均會監(jiān)聽到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()用戶客戶端向服務(wù)端發(fā)送消息蔓搞,服務(wù)端與之對應(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ù)器實例
let httpServer = require('http').Server();
let io = require('socket.io')(httpServer);
httpServer.listen(3000);

// 服務(wù)端監(jiān)聽連接狀態(tài):io的connection事件表示客戶端與服務(wù)端成功建立連接,它接收一個回調(diào)函數(shù)喂分,回調(diào)函數(shù)會接收一個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');
  });

  // 與客戶端對應(yīng)的接收指定的消息
  socket.on('client message', (data)=>{
    cosnole.log(data);// hi server
  });

  socket.disconnect();
});

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

服務(wù)端和客戶端的socket是一個關(guān)聯(lián)的EventEmitter對象酸员,客戶端socket派發(fā)的事件可以通過被服務(wù)端的socket接收蜒车,服務(wù)端socket派發(fā)的事件也可以被客戶端接收讳嘱。基于這種機(jī)制酿愧,可以實現(xiàn)雙向交流沥潭。

# 模擬:客戶端不斷發(fā)送隨機(jī)數(shù),當(dāng)隨機(jī)數(shù)大于0.95時嬉挡,服務(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對象可用來存儲狀態(tài)和自定義數(shù)據(jù)
      }
      setTimeout(()=>{
        socket.emit('warn', ++socket.warning);
      }, 1000);
    }
  });
});
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市庞钢,隨后出現(xiàn)的幾起案子拔恰,更是在濱河造成了極大的恐慌,老刑警劉巖基括,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件颜懊,死亡現(xiàn)場離奇詭異,居然都是意外死亡风皿,警方通過查閱死者的電腦和手機(jī)河爹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來桐款,“玉大人咸这,你說我怎么就攤上這事∧д#” “怎么了媳维?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長遏暴。 經(jīng)常有香客問我侨艾,道長,這世上最難降的妖魔是什么拓挥? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任唠梨,我火速辦了婚禮,結(jié)果婚禮上侥啤,老公的妹妹穿的比我還像新娘当叭。我一直安慰自己茬故,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布蚁鳖。 她就那樣靜靜地躺著磺芭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪醉箕。 梳的紋絲不亂的頭發(fā)上钾腺,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天,我揣著相機(jī)與錄音讥裤,去河邊找鬼放棒。 笑死,一個胖子當(dāng)著我的面吹牛己英,可吹牛的內(nèi)容都是我干的间螟。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼损肛,長吁一口氣:“原來是場噩夢啊……” “哼厢破!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起治拿,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤摩泪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后劫谅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體见坑,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年同波,在試婚紗的時候發(fā)現(xiàn)自己被綠了鳄梅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡未檩,死狀恐怖戴尸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情冤狡,我是刑警寧澤孙蒙,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站悲雳,受9級特大地震影響挎峦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜合瓢,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一坦胶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦顿苇、人聲如沸峭咒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽凑队。三九已至,卻和暖如春幔翰,著一層夾襖步出監(jiān)牢的瞬間漩氨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工遗增, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留叫惊,地道東北人。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓贡定,卻偏偏與公主長得像赋访,于是被迫代替她去往敵國和親可都。 傳聞我的和親對象是個殘疾皇子缓待,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容