網頁端收消息的三種方式
場景描述
在網頁端登錄的用戶A,有兩類發送給他的消息:
- 系統發給A的“系統通知”;
- 用戶發給A的“聊天消息”;
系統側,一般來說,對每一個接受消息的用戶都有一個“待收消息”的隊列,里面存放了需要給這個用戶的所有消息。
用戶A,如果是在網頁端登錄,有幾種常見的收取消息的方式呢?
常見的方案有3種。
方案一、輪詢拉取
輪詢拉取,這是最容易想到的實現方式:
- 網頁端起一個timer,每個一段時間(例如10秒),發起一個輪詢請求,拉取隊列里的消息;
- 如果隊列里有消息,就返回消息;
- 如果隊列里無消息,就10秒后再次輪詢;
這種方式的優勢是:實現簡單,直觀且,容易理解,互聯網興起時,人數不多的聊天室就是這么玩的。
畫外音:我最早玩的聊天室,是創辦于1996年的互聯網老站碧海銀沙,大家聽過嗎?
缺點也很明顯:
- 實時性差:最壞的情況下,1條消息進入隊列后,10s之后才會收到;
- 效率低下:發消息是一個低頻動作,如果10次輪詢才收到1條消息,請求有效性只有10%,浪費了大量服務器資源;
方案二、建立長連接
如果要兼顧實時性和效率,長連接是最佳之選,PC端聊天軟件基本都是使用長連接。
網頁端常見的實現長連接的方式有兩種:
- WebSocket;
- FlashSocket;
這兩種方案的細節不再展開。
方案三、HTTP長輪詢
長輪詢,是通過拼裝HTTP短連接來達到長連接的效果,即保證了消息100%實時,又最大化的系統效率。
HTTP長輪詢的核心在于,瀏覽器與服務端之間建立了一條“通知連接”,它的特點是:
- 這是一條browser發往web-server的HTTP連接;
- 這條連接只用來收取推送通知;
- 不像普通的“請求-響應”式HTTP請求,這個HTTP會被服務端夯住,直到有推送通知到達,或者超過約定的時間;
更具體的,對于這條“夯住”與“只收推送通知”的“通知連接”,是怎么玩的呢?
場景1,發起通知連接時,隊列里正好有消息,則:
- 發起通知連接,正好隊列里有消息;
- 實時把隊列里的消息帶回;
- 立馬再發起通知連接;
場景二,發起通知連接時,隊列里無消息,則:
- 發起通知連接時,隊列里無消息;
- 一直等待,直到觸發“時間閾值”,返回無消息;
- 立馬再發起通知連接;
場景三,新消息來時,正好有通知連接在,則:
- 新消息來時,正好有通知連接在;
- 通知連接實時將消息帶回;
- 立馬再發起通知連接;
上面三個場景的最終狀態,都是“一定,永遠,會有一條通知連接,連接在瀏覽器與服務器之間”,這樣就能夠保證消息的實時性。
總結
網頁端收消息,一般有三種模式:
(1) 最容易想到的是拉,但實時性和效率是一對無法調和的矛盾;
(2) 最佳的方式是推:
- WebSocket和FlashSocket是建立TCP長鏈接
- 也可以長輪詢,通過HTTP短連接拼裝長連接,具體是通過“夯住”“只收推送通知”的“通知連接”來實現的,能夠做到消息的實時性到達
知其然,知其所以然。
思路比結論更重要。