Socket.io詳解

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

http://socket.io/docs/express

因爲HTTP是無狀態的協議,要實現即時通信很是困難。由於當對方發送一條消息時,服務器並不知道當前有哪些用戶等着接收消息,當前實現即時通信功能最爲廣泛的方式就是輪詢機制。即客戶端按期發起一個請求,看看有沒有人發送消息到服務器,若是有服務端就將消息發給客戶端。這種作法的缺點顯而易見,那麼多的請求將消耗大量資源,大量的請求實際上是浪費的。npm

如今,咱們有了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中那些通訊機制呢?app

  • 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。框架

服務端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,經過實例化時傳入端口或者在實例化後調用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);
    }
  });
});
相關文章
相關標籤/搜索