html5 新增 websocket(2) 原理

我們在上篇文章中說道websocket是一個 客戶端服務器端之間進行的非HTTP的通信機制,是雙向的、實時的、永久的。

http的工作原理

(1)http協議是在應用層的協議,是基於TCP的,http連接的建立需要3次握手才能發送消息。
這篇文章詳細的介紹了握手的過程。
這篇文章列舉了http的Header的信息。

WebSocket是HTML5出的協議。是一個新的協議,和HTTP是沒有太多的關係的。是爲了兼容現有瀏覽器的握手規範而已。

(2)http鏈接分爲短鏈接,長鏈接。

短鏈接:每次請求都要三次握手才能發送自己的信息。HTTP的生命週期通過Request來界定,也就是一個Request一個Response。那麼HTTP1.0,這次HTTP請求就結束了。下次再次鏈接就需要再次請求。

長鏈接:是在一定的期限內保持鏈接。保持TCP連接不斷開。客戶端與服務器通信,必須要有客戶端發起然後服務器返回結果。客戶端是主動的,服務器是被動的。
在HTTP1.1中進行了改進,使得有一個keep-alive,也就是說,在一個HTTP連接中,可以發送多個Request,接收多個Response。

但是請記住 Request = Response ,在HTTP中永遠是這樣,也就是說一個request只能有一個response。而且這個response也是被動的,不能主動發起。

(3)websocket的握手。

websocket也是基於HTTP協議的,不過是他只需經歷一次握手就可以,建立連接,並且這個鏈接是雙向的是永久了,除非顯示的斷開。
上一篇文章中其實也用圖片展示了這次握手的表現。


看過了上面關於HTTP請求頭的鏈接文章後,你會發先,這個websocket的請求多了一些東西。
connection:Upgrade
Upgrade:websocket.
上一篇中提到了,這個就是websocket的核心了。就是告訴服務器我發起的是一個websocket協議。
Sec_WebSocket_Key:是一個Base64encode的值,是由瀏覽器隨機生成的。用來驗證鏈接到的是不是WebSocket.
Sec-WebSocket-Version 是告訴服務器所使用的Websocket Draft(協議版本)



這裏服務器給了返回值了。
Upgrade: websocketConnection: Upgrade
這就是告訴客戶我這裏已經切換成功了。升級爲WebSocket
Sec-WebSocket-Accept這個則是經過服務器確認,並且加密過後的 Sec-WebSocket-Key。
總結:
經過這個的握手,客戶端和服務器端就握手成功了。建立起來了websocket的鏈接了。

(4)在沒有websocket時時如何處理的

我們看到了websocket是雙向的,實時的,永久的。便捷的地方就是服務器可以主動的給客戶端發送消息。

場景:推送,服務器有一條新的消息,需要通知到客戶端,可是客戶端還沒有來請求,那麼這條新消息就不能發送出去。

這種場景在websocket中是很容易實現的,因爲連接是一直存在的,服務器可以主動的發送消息。

在沒有websocket的時候,我們使用的方法就是,long poll 或者 ajax輪詢。

首先 ajax輪詢的實現原理
參考了知乎上的一篇文章

場景再現:
客戶端:啦啦啦,有沒有新信息(Request)
服務端:沒有(Response)
客戶端:啦啦啦,有沒有新信息(Request)
服務端:沒有。。(Response)
客戶端:啦啦啦,有沒有新信息(Request)
服務端:你好煩啊,沒有啊。。(Response)
客戶端:啦啦啦,有沒有新消息(Request)
服務端:好啦好啦,有啦給你。(Response)
客戶端:啦啦啦,有沒有新消息(Request)
服務端:。。。。。沒。。。。沒。。。沒有(Response) ---- loop

很形象的描述了ajax輪詢的場景。每隔幾秒就會向服務器發起請求,詢問服務器是否有新的消息。不過http的請求是無狀態的,所以服務器是不會記住,所以他也不會煩的。

long poll

場景再現
客戶端:啦啦啦,有沒有新信息,沒有的話就等有了才返回給我吧(Request)
服務端:額。。 等待到有消息的時候。。來 給你(Response)
客戶端:啦啦啦,有沒有新信息,沒有的話就等有了才返回給我吧(Request) -loop

這個的原理和 ajax差不多,不過,這裏是阻塞的,就是發起了詢問的請求之後,如果沒有就一直等在哪裏。

這兩種形式就是在表示 http請求的一個“被動性”的特點。就是服務器不會主動聯繫客戶端的。

綜上:可以看出來了,這種情況很浪費資源。

那麼WebSocket是如何做的
所以上面的情景可以做如下修改。
客戶端:啦啦啦,我要建立Websocket協議,需要的服務:chat,Websocket協議版本:17(HTTP Request)
服務端:ok,確認,已升級爲Websocket協議(HTTP Protocols Switched)
客戶端:麻煩你有信息的時候推送給我噢。。
服務端:ok,有的時候會告訴你的。
服務端:balabalabalabala
服務端:balabalabalabala
服務端:哈哈哈哈哈啊哈哈哈哈
服務端:笑死我了哈哈哈哈哈哈哈

只需要一次的請求,然後就是源源不斷的信息傳遞了。

此外還有 multiplexing 功能,幾個不同的 URI 可以複用同一個 WebSocket 連接。這些都是原來的 HTTP 不能做到的。

下面是在知乎上看到的,拿到這裏和大家分享一下

鏈接:https://www.zhihu.com/question/20215561/answer/40250050

另外說一點技術細節,因爲看到有人提問 WebSocket 可能進入某種半死不活的狀態。這實際上也是原有網絡世界的一些缺陷性設計。上面所說的 WebSocket 真.長連接雖然解決了服務器和客戶端兩邊的問題,但坑爹的是網絡應用除了服務器和客戶端之外,另一個巨大的存在是中間的網絡鏈路。一個 HTTP/WebSocket 連接往往要經過無數的路由,防火牆。你以爲你的數據是在一個“連接”中發送的,實際上它要跨越千山萬水,經過無數次轉發,過濾,才能最終抵達終點。在這過程中,中間節點的處理方法很可能會讓你意想不到。

比如說,這些坑爹的中間節點可能會認爲一份連接在一段時間內沒有數據發送就等於失效,它們會自作主張的切斷這些連接。在這種情況下,不論服務器還是客戶端都不會收到任何提示,它們只會一廂情願的以爲彼此間的紅線還在,徒勞地一邊又一邊地發送抵達不了彼岸的信息。而計算機網絡協議棧的實現中又會有一層套一層的緩存,除非填滿這些緩存,你的程序根本不會發現任何錯誤。這樣,本來一個美好的 WebSocket 長連接,就可能在毫不知情的情況下進入了半死不活狀態。

而解決方案,WebSocket 的設計者們也早已想過。就是讓服務器和客戶端能夠發送 Ping/Pong Frame(RFC 6455 - The WebSocket Protocol)。這種 Frame 是一種特殊的數據包,它只包含一些元數據而不需要真正的 Data Payload,可以在不影響 Application 的情況下維持住中間網絡的連接狀態。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章