分析的是hybridconnector,使用的chatofpomelo-websocket(pomelo為0.7.0)

參考:https://github.com/NetEase/pomelo/wiki/Pomelo-通訊協議

http://cnodejs.org/topic/51395fd0df9e9fcc5882576c





client握手:





pomelo在init時候,建立WebSocket連線。並定義onopen onmessage回撥,

連線建立後,onopen被回撥。client首先發送握手包var obj = Package.encode(Package.TYPE_HANDSHAKE, Protocol.strencode(JSON.stringify(handshakeBuffer)));

引數為。假設version在client有快取,將使用快取{

  'sys': {

    'version': '1.1.1',

    'type': 'js-websocket'

  }, 

  'user': {

    // any customized request data

  }

}

這種方法中,package格式為type。length。body。傳入的引數為type和body,





服務端發回message,在onmessage中處理server到client的握手響應,服務端發回的引數

{

  'code': 200,          // result code

  'sys': {

    'heartbeat': 3,     // heartbeat interval in second

    'dict': {},         // route dictionary

    'protos': {}        // protobuf definition data

  }, 

  'user': {

    // any customized response data

  }

}

並分發到handshake處理。首先快取dict和protos,然後發回var obj = Package.encode(Package.TYPE_HANDSHAKE_ACK);握手ack,至此握手完成









client打包:

Package分為header和body兩部分。

Header描寫敘述package包的型別和包的長度。body則是須要傳輸的資料內容。

詳細格式參考https://github.com/NetEase/pomelo/wiki/Pomelo-通訊協議

package的body部分發送的是Message,訊息頭分為三部分,flag,message id,route。

詳細格式參考https://github.com/NetEase/pomelo/wiki/Pomelo-通訊協議





Package.encode,打包函式比較簡單,僅僅是轉換大小端

Message.encode。Message的打包函式,第一步是計算包長度,message id可變,要計算,是否有路由。要計算。加上傳送的內容,就是總長度,然後建立buffer填充內容。

填充內容時候,假設有路由壓縮,則在填充路由的時候。填充替換過的路由。

pomelo.encode 使用者資料打包函式。

這個打包的結果是Message.encode中的msg,這個函式用了處理路由壓縮和protobuf壓縮。

假設clientProtos中配置了路由。將用 protobuf.encode(route, msg);打包內容。假設dict定義了路由,將替換路由





程式執行的順序剛好與以上介紹反過來,先內層後外層





client解包:

Package.decode,解包出型別和長度

Message.decode。解包id,路由。和body,注意id和路由可能不存在

pomelo.decode。假設有id。則說明是request,直接從routeMap中替換路由,然後deCompose,路由有compressRoute,則替換路由。serverProtos中要求打包路由,則用protobuf.decode解包內容





解包剛好是正常的執行順序,先外層後內層













服務端:





使用的hybridconnector中的websocket連結





hybridconnector和hybridsocket是pomelo封裝的server和socket。switch是轉發。

wsprocessor是websocket處理的檔案,commands目錄是握手。心跳處理的邏輯





hybridconnector用 this.tcpServer = net.createServer();接受連線。switch分發tcp和websocket。

到processor處理





對於websocket的連線建立過程:

1:switch中的tcpServer轉發connection到newSocket處理。newSocket將connection轉發給wsprocessor處理

2:Processor.prototype.add中。httpServer分發connection訊息(由於pomelo自己用net接受的連線,所以要自己用httpserver解析http協議),

http.js中用connectionListener函式處理connection訊息。僅僅是為socket加入了一下處理函式(ondata下一步會用到),

3:由於socket.ondata存在,所以直接呼叫,在http.js中看到ondata相應websocket來說,是為了分發upgrade訊息

4:在httpserver的外層還有WebSocketServer,WebSocketServer在建立的時候,會註冊httpserver的upgrade訊息,用於建立websocket連線,同一時候分發connection訊息

5:processor在建立的時候。註冊了websocketserver的connection訊息,並再次分發

6:switch轉發了processor的connection訊息

7:hybridconnector註冊了switch的connection訊息,用socket封裝成hybridsocket。併為hybridsocket註冊handshake heartbeat disconnect closing訊息,同一時候分發connection訊息

8:元件connector在初始化時。註冊了hybridconnector的connection訊息,用bindEvents,為hybridsocket註冊了disconnect  error message訊息。至此連線建立





對於websocket的握手過程:

1:訊息的起源處是,socket分發message訊息。在hybridsocket中,收到訊息,用Package.decode(msg)解包,解包函式與client一致,握手請求分發到handleHandshake。分發傳入的socket為hybridsocket型別

2:handleHandshake將上一步解析出的msg,將body通過JSON.parse(protocol.strdecode(msg.body))轉成json,用handshake訊息分發出去

3:在hybridconnector中,參考【websocket的連線建立過程】7。連線時候已經註冊了handshake處理方法。將轉發給handshake.handle

4:在commands的handshake中。引數heartbeat  dict sys被收集,通過服務端的握手包返回給client





5:但服務端收到握手ack包時。服務端回覆client心跳包,(socket.emit('heartbeat');)。至此握手完畢





服務端心跳邏輯:

1:握手完畢後,hybridsocket分發heartbeat訊息,在commands中的heartbeat處理,在heartbeats字典中。儲存計時器,將在心跳時間後,傳送心跳包。並註冊超時函式





2:當收到client的心跳包後。在hybridsocket處handleHeartbeat中處理。分發heartbeat訊息。

在commands中的heartbeat中。要先清理超時回撥,然後同1









服務端響應request:

1:訊息的起源處是,socket分發message訊息。在hybridsocket中,收到message訊息,用Package.decode(msg)解包,解包函式與client一致,通過hybridsocket分發解析後的msg

2:參考【websocket的連線建立過程】8,在connector處理了解析後的msg,首先呼叫 self.connector.decode(msg);hybridconnector中的decode與client的解包一致,

先呼叫Message.decode(msg.body);然後替換路由。和用protobuf解壓縮

3:然後handleMessage。將解析後的請求,分發到相應的server處理,回撥的結果通過self.send(msg.id, msg.route, resp, [session.id], {isResponse: true}, function() {});返回給client

send中會將傳送的內容通過emsg = this.connector.encode(reqId, route, msg);打包成message,程式碼在hybridconnector中,與client邏輯同樣

4:connector的send方法。通過元件__pushScheduler__傳送,並在下一幀呼叫回撥函式(reqest的回撥為空函式)

5:元件__pushScheduler__傳送,不論是廣播還是推送,都是通過sessionService.sendMessage傳送,然後呼叫session的send方法

6:sessionservice邏輯中。session是在【websocket的連線建立過程】8中的bindevents中生成的。成員變數__socket__是hybridsocket,所以。session的send方法通過hybridsocket的send實現

7:hybridsocket的send中this.sendRaw(Package.encode(Package.TYPE_DATA, msg)); 至此服務端完畢對request的響應





服務端的push不再詳說