socket.io是一個跨瀏覽器支持WebSocket的實時通信的JS。php
http://socket.io/docs/express
因爲HTTP是無狀態的協議,要實現即時通信很是困難。由於當對方發送一條消息時,服務器並不知道當前有哪些用戶等着接收消息,當前實現即時通信功能最爲廣泛的方式就是輪詢機制。即客戶端按期發起一個請求,看看有沒有人發送消息到服務器,若是有服務端就將消息發給客戶端。這種作法的缺點顯而易見,那麼多的請求將消耗大量資源,大量的請求實際上是浪費的。npm
如今,咱們有了WebSocket,它是HTML5的新API。WebSocket鏈接本質上就是創建一個TCP鏈接,WebSocket會經過HTTP請求創建,創建後的WebSocket會在客戶端和服務端創建一個持久的鏈接,直到有一方主動關閉該鏈接。因此,如今服務器就知道有哪些用戶正在鏈接了,這樣通信就變得相對容易了。編程
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中那些通訊機制呢?app
socket.io提供了基於事件的實時雙向通信,它同時提供了服務端和客戶端的API。框架
服務端dom
服務端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
,經過實例化時傳入端口或者在實例化後調用listen
或attach
函數進行隱式綁定。
// 實例化時傳入端口 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);
創建鏈接
當服務端和客戶端鏈接成功時,服務端會監聽到connection
和connect
事件,客戶端會監聽到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); } }); });