socket.io 的詳細工作流程是怎樣的?

前端菜鳥一隻,這兩天在學node.js的時候遇到了http://socket.io,國內的文檔不多,且都為英文的,哪位前輩能從client端和server端詳細描述一下http://socket.io的工作流程,包括前後端的信息傳輸、數據交互等等。


http://socket.io 是基於 WebSocket 的 C-S 實時通信庫,我假設題目問的是 http://socket.io 而非 WebSocket 協議的實現。

http://socket.io 底層是 http://engine.io,這個庫實現了跨平台的雙向通信。

http://engine.io 使用了 WebSocket 和 XMLHttprequest(或JSONP) 封裝了一套自己的 Socket 協議(暫時叫 EIO Socket),在低版本瀏覽器裡面使用長輪詢替代 WebSocket。一個完整的 EIO Socket 包括多個 XHR 和 WebSocket 連接.

前端:

EIO Socket 通過一個 XHR (XMLHttprequest) 握手。前端發送一個 XHR,告訴服務端我要開始 XHR 長輪詢了。後端返回的數據裡面包括一個 open 標誌(數字 0 表示), 以及一個 sid 和 upgrades 欄位。

sid 是本次 EIO Socket 的會話 ID,因為一次 EIO Socket 包含了多個請求,而後端又會同時連接多個 EIO Socket,sid 的作用就相當於 SESSION ID。

另一個欄位 upgrades,正常情況下是 [websocket],表示可以把連接方式從長輪詢升級到 WebSocket.

前端在發送第一個 XHR 的時候就開始了 XHR 長輪詢,這個時候如果有收發數據的需求,是通過長輪詢實現的。所謂長輪詢,是指前端發送一個 request,服務端會等到有數據需要返回時再 response. 前端收到 response 後馬上發送下一次 request。這樣就可以實現雙向通信。

前端收到握手的 upgrades 後,EIO 會檢測瀏覽器是否支持 WebSocket,如果支持,就會啟動一個 WebSocket 連接,然後通過這個 WebSocket 往伺服器發一條內容為 probe, 類型為 ping 的數據。如果這時伺服器返回了內容為 probe, 類型為 pong 的數據,前端就會把前面建立的 HTTP 長輪詢停掉,後面只使用 WebSocket 通道進行收發數據。

EIO Socket 生命周期內,會間隔一段時間 ping - pong 一次,用來測試網路是否正常。

這是 WebSocket 幀的結構,綠色是發送,白色是接收。前面的數字是數據包類型,2 是 ping, 3 是 pong, 4 是 message.http://socket.io 在 http://engine.io 的基礎上做了一些封裝,比如 http://socket.io 裡面這樣的代碼:

io.emit(add user, m)

在 engine.io 裡面是這樣:

eio.send(message, 2["add user","m"]) // 2 是 socket.io 定義的包類型

再例如,engine.io-client 需要在 open 之後才能 send,而 http://socket.io 就不需要,open 之前 emit 的數據會在 open 之後再發出。

另外 http://socket.io 還提供了 namespace,復用, 自動重連等特性。

服務端:

服務端使用 ws 庫實現 WebSocket 協議。

http://socket.io 服務啟動時,會先啟動一個 ws 服務。http://socket.io 會監聽 HTTP 伺服器的 upgrade 和 request 事件。

當 upgrade 事件觸發時,說明可能是 WebSocket 握手,先簡單校驗下,然後把請求交給 ws 服務進行處理,拿到 WebSocket 對象。

當 request 事件觸發時,根據 url 路徑判斷是不是 http://socket.io 的 XHR 請求,拿到 res 和 res 對象。

這樣就可以正確接收和返回客戶端數據了,具體處理過程和前端部分是對應的。


最近項目有用到socket做上傳,就我理解的來說說,如有問題請指正並原諒俺~

流程大致是這樣的:

  1. 服務端啟動一個socket服務,並監聽connection事件。
  2. 客戶端(一般指瀏覽器)創建一個websocket,並連接伺服器端的socket,並綁定接收socket事件的方法。
  3. 客戶連接後,服務端socket就可以向客戶端發消息了。

socket通訊可以簡單的理解為一個真正意義上的長鏈接,不主動斷開的話該通道一直存在,並且通道的兩端可以互相喊話。

普通的請求比如httpxhr這類的,是一個一次性的通訊,當通訊完成後,通道會關閉。

socket一次通訊後並不會關閉通道,這就是他們的區別所在。

當然不同的通訊有不同的協議,此處就不展開了(其實是我沒怎麼了解...)。

Socket.IO a€」 Docs 官網給的demo很明白了。

服務端

var app = require(http).createServer(handler)
var io = require(socket.io)(app);
var fs = require(fs);

app.listen(80);

// 創建socket,監聽連接
io.on(connection, function (socket) {
// 收到連接後,觸發 news 事件
socket.emit(news, { hello: world });
// 接收客戶端事件
socket.on(my other event, function (data) {
console.log(data);
});
});

客戶端

var socket = io(http://localhost);
// 自定義一個news事件
socket.on(news, function (data) {
console.log(data);
// 發送事件到服務端
socket.emit(my other event, { my: data });
});

當然實際應用中遠遠不止如此簡單,以我目前的知識儲備,可以推薦的是將socket當作一個類http服務,不同的請求可以當成router+handle的方法來處理,這樣就不會有一堆亂七八糟的的onemit了。

http://socket.io官方也推薦使用namespace來區分多個處理服務。


代表廣大有愛心人士問一下:題主回心轉意了沒有?


把這邊書通讀一遍吧,聊其他的都是扯淡。


最近也碰到這個問題,找問題每次查到知乎和segmentfalt上的時候總是有一堆人冷嘲熱諷。不懂或者不想說就閉嘴好了,為什麼非要說一堆沒用的廢話。反觀stackoverflow,誠意滿滿,裝逼人員極少。


無他,唯協議爾


我想說下我鬱悶的事,我們後端使用的socketio,我是ios客戶端,ios有swift版的socketio,不過我需要支持ios7,所以不能夠去使用這個現成的swift版的,我也沒找到oc版的,找了好多都是oc版的websocket,我嘗試著用websocket去連伺服器,伺服器返回101,表示協議升級成功,然後socket打開了,但是伺服器推的onConnect事件我怎麼都收不到,流程走到這裡停了……

我要去看swift代碼寫個oc版的出來嗎?

有人遇到同樣問題的嗎?


// sending to sender-client only
socket.emit(message, "this is a test");

// sending to all clients, include sender
io.emit(message, "this is a test");

// sending to all clients except sender
socket.broadcast.emit(message, "this is a test");

// sending to all clients in game room(channel) except sender
socket.broadcast.to(game).emit(message, nice game);

// sending to all clients in game room(channel), include sender
io.in(game).emit(message, cool game);

// sending to sender client, only if they are in game room(channel)
socket.to(game).emit(message, enjoy the game);

// sending to all clients in namespace myNamespace, include sender
io.of(myNamespace).emit(message, gg);

// sending to individual socketid
socket.broadcast.to(socketid).emit(message, for your eyes only);

來源 Send response to all clients except sender (Socket.io)


這個主要需要了解TCP,Socket,全雙工通信這些基礎,就能理解http://socket.io的工作方式了,無非就是對webSocket的庫!


評論什麼鬼


推薦閱讀:

Vue.js 和 MVVM 的小細節
如何理解楊博老師對 DOM 操作複雜度的評論?
面試系列之四:你真的了解React嗎(下)Flux與Vuex的差異以及Webpack的工作原理
【譯】也許你不必使用 Redux
推薦閱讀-第4期

TAG:前端開發 | 後端技術 | Nodejs | socketio |