在線聊天室的實現(1)--websocket協議和javascript版的api



前言:
  大家剛學socket編程的時候, 往往以聊天室作為學習DEMO, 實現簡單且上手容易. 該Demo被不同語言實現和演繹, 網上相關資料亦不勝枚舉. 以至於很多技術書籍在講解網絡相關的編程時, 不再采用聊天室做為基礎案列, 而采用其他案例. 比如之前火熱一時的"你猜我畫", 以避免顯得很大眾.
  但說實話, 幾乎所有的網絡程序追蹤溯源, 都可以從聊天室中找到影子. 在線聊天室也不局限於簡單的單機服務, 其分布式實現技術含量十足. 猶如達芬奇畫雞蛋, 中間雖枯燥, 但堅持不懈, 精益求精. 終於水滴石穿, 從量變到質變.
  本章將講講, websocket的協議和javascript版的API.

websocket協議:
  websocket基於tcp的雙向通訊協議. 其協議可以分為兩個部分, 握手數據傳輸. 其握手協議構建於http/https, 而數據傳輸協議則脫離於http/https.
  websocket協議歷經了很多版本的修改和升級, 字段和約定的差異, 使得編碼時需要注意版本的兼容性. 當前使用最普遍的是版本13.
  其協議uri可以表示為"ws://{host}:{port}/{path}", 在ssl/tls下是"wss://{host}:{port}/{path}".
  • 握手協議
  在該階段, 其交換為request/response的方式進行.

  
  如簡單的例子為案例, 其http請求頭中包含如下的字段:
  
  Connection: Upgrade
  Upgrade: websocket
  Sec-WebSocket-Key: A2mIDkRXEgl0+79uPwhsOw==
  Sec-WebSocket-Version: 13
  服務端通過識別header中的Upgrade:websocket字段來區分正常的http請求還是websocket協議.
  而Sec-WebSocket-Key則是客戶端生成的一個隨機key, 用於和服務端進行的驗證工作.
  服務端的響應如下所示:
  
  Sec-WebSocket-Accept: hQCy41pGdjZ222NKXfyrxQUHZEQ=
  其http響應碼為101, Sec-WebSocket-Accept為服務端對應於客戶端Sec-WebSocket-Key的驗證值.
  其具體的算法, 可以描述如下:

${Sec-WebSocket-Accept}=base64(sha1(${Sec-WebSocket-Key}+"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))

  • 數據協議
  在該階段, 客戶端和服務器其數據交換格式, 就約定為Frame模式了. 一般一條消息為一個frame, 當然一個消息可以由多個frame組成. 這樣的好處, 就像http的chunk模式一樣, 一邊生成一邊傳輸.
  Frame具體的定義如下所示:
  
  每個字段都有其具體的含義, 這邊就不再具體的展開了.
  其Frame的分類可以大致如下:
  
  Ping/Pong Frame由應用層協議本身完成, 這樣基於websocket開發的網絡應用服務, 就可以少去了死鏈檢測/重連這一環節了.
  Text Frame往往用的比較多, 也有使用Binary Frame的, 比如基於websocket實現的MQTT服務.
  Connection Close Frame是一種友好協商斷掉連接的一種方式.

Javascript版API:
  WebSocket其對應的javascript代碼如下:

// *) websocket鏈接本身的狀態
WebSocket.CONNECTING = 0;
WebSocket.OPEN = 1;
WebSocket.CLOSING = 2;
WebSocket.CLOSED = 3;

// *) websocket實體對象的成員
WebSocket.prototype.url = null;
WebSocket.prototype.readyState = 0;
WebSocket.prototype.bufferedAmount = 0;
WebSocket.prototype.extensions = null;
WebSocket.prototype.protocol = null;

// *) websocket實體對應的回調函數, 需要被繼承實現
WebSocket.prototype.onopen = 0;
WebSocket.prototype.onmessage = 0;
WebSocket.prototype.onerror = 0;
WebSocket.prototype.onclose = 0;

// *) websocket實體的send/close方法
function WebSocket(url,protocols) {}
WebSocket.prototype.send = function(data) {};
WebSocket.prototype.close = function(code,reason) {};

  主要還是websocket對應的回調函數實現, 當然也需知道websocket本身所處的狀態.

總結:
  該篇博文有堆砌之感, 但如果你想實現一個基於websocket實現的聊天室, 對其內部的協議和流程需要有個清晰的了解. 特別是之后的基於Netty開發的服務器, 雖然可以照貓畫虎, 但知其然不知其所以然.
  本文參考了websocket的wiki, 以及rfc說明.

寫在最后:
  
如果你覺得這篇文章對你有幫助, 請小小打賞下. 其實我想試試, 看看寫博客能否給自己帶來一點小小的收益. 無論多少, 都是對樓主一種由衷的肯定.

   

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM