原文位址:https://blog.zengrong.net/post/2199.html
去年光棍節的時候,我寫過一篇 quick-cocos2d-x 中的 socket 技術選擇:LuaSocket 和 WebSocket 。這篇文章介紹了我為何決定在項目中使用 LuaSocket 。
現在想起來,當時對 WebSocket 是很感興趣的,但由于服務端的限制,最終依然選擇了 LuaSocket。我後來對 LuaSocket 進行了封裝,使其更好用。
現在,面對一個全新的項目,我自然而然地選擇了 WebSocket。
是以,我需要了解下面這些問題:
- Socket 和 WebSocket 有哪些差別和聯系?
- WebSocket 和 HTML5 是什麼關系?
- 必須在浏覽器中才能使用 WebSocket 嗎?
- WebSocket 能和 Socket 一樣傳輸 raw 資料麼?
- WebSocket 和 Socket 相比會多耗費流量麼?
但是,目前網上全面介紹這兩種協定的中文文章并不多,或者說不夠全面。我無法找到一篇文章能解決上面的所有問題。是以,我寫了本文,把找到的 Socket 和 WebSocket 的相關資料做一個梳理,以友善了解。
本文并不能直接完整回答上面提出的幾個問題,但讀完本文,要了解上面的那些問題,是很容易的事。
由于能力有限,本文不可能很長。而且,技術細節并非所有人都願意仔細了解。本文包含了大量的外部連結,跟随這些連結,可以找到足夠多的細節,滿足你/我的求知欲。
1. 概述
選擇了 WebSocket 技術之後,不可避免的,我要将它和其他協定以及技術做一下比較。最常見的,就是需要比較 WebSocket 與 HTTP、Socket 技術的異同。
WebSocket 是為了滿足基于 Web 的日益增長的實時通信需求而産生的。在傳統的 Web 中,要實作實時通信,通用的方式是采用 HTTP 協定不斷發送請求。但這種方式即浪費帶寬(HTTP HEAD 是比較大的),又消耗伺服器 CPU 占用(沒有資訊也要接受請求)。(下圖來自 WebSocket.org)
而是用 WebSocket 技術,則會大幅降低上面提到的消耗:(下圖來自 websocket.org)
關于更詳細的描述,尹立的這篇文章講得非常好:WebSocket(2)–為什麼引入WebSocket協定 。
那麼,WebSocket 到底與 HTTP 協定到底是一個什麼樣的關系呢?它和 Socket 又有什麼聯系?這就要講到 OSI 模型和 TCP/IP 協定族。
2. OSI 模型與 TCP/IP
以下是 維基百科 中關于OSI 模型的說明:
開放式系統互聯通信參考模型(英語:Open System Interconnection Reference Model,ISO/IEC 7498-1),簡稱為OSI模型(OSI model),一種概念模型,由國際标準化組織(ISO)提出,一個試圖使各種計算機在世界範圍内互連為網絡的标準架構。
而 TCP/IP 協定可以看做是對 OSI 模型的一種簡化(以下内容來自 維基百科):
它将軟體通信過程抽象化為四個抽象層,采取協定堆疊的方式,分别實作出不同通信協定。協定套組下的各種協定,依其功能不同,被分别歸屬到這四個階層之中7,常被視為是簡化的七層OSI模型。
這裡有一張圖詳細介紹了 TCP/IP 協定族中的各個協定在 OSI模型 中的分布,一圖勝千言(下圖來自 科來):
這裡是 PDF 版:
下載下傳
TCP/IP 協定和 OSI 模型的内容,在網際網路上有很多。我沒有必要再次介紹它們。在這裡,我們隻需要知道,HTTP、WebSocket 等協定都是處于 OSI 模型的最高層: 應用層 。而 IP 協定工作在網絡層(第3層),TCP 協定工作在傳輸層(第4層)。
至于 OSI 模型的各個層次都有什麼系統和它們對應,這裡有篇很好的文章可以滿足大家的求知欲:OSI七層模型詳解 。
3. WebSocket、HTTP 與 TCP
從上面的圖中可以看出,HTTP、WebSocket 等應用層協定,都是基于 TCP 協定來傳輸資料的。我們可以把這些進階協定了解成對 TCP 的封裝。
既然大家都使用 TCP 協定,那麼大家的連接配接和斷開,都要遵循 TCP 協定中的三次握手和四次握手 ,隻是在連接配接之後發送的内容不同,或者是斷開的時間不同。
更詳細内容可閱讀:wireshark抓包圖解 TCP三向交握/四次揮手詳解
對于 WebSocket 來說,它必須依賴 HTTP 協定進行一次握手 ,握手成功後,資料就直接從 TCP 通道傳輸,與 HTTP 無關了。
4. Socket 與 WebScoket
Socket 其實并不是一個協定。它工作在 OSI 模型會話層(第5層),是為了友善大家直接使用更底層協定(一般是 TCP 或 UDP )而存在的一個抽象層。
最早的一套 Socket API 是 Berkeley sockets ,采用 C 語言實作。它是 Socket 的事實标準,POSIX sockets 是基于它建構的,多種程式設計語言都遵循這套 API,在 JAVA、Python 中都能看到這套 API 的影子。
下面摘錄一段更容易了解的文字(來自 http和socket之長連接配接和短連接配接差別):
Socket是應用層與TCP/IP協定族通信的中間軟體抽象層,它是一組接口。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協定族隐藏在Socket接口後面,對使用者來說,一組簡單的接口就是全部,讓Socket去組織資料,以符合指定的協定。
主機 A 的應用程式要能和主機 B 的應用程式通信,必須通過 Socket 建立連接配接,而建立 Socket 連接配接必須需要底層 TCP/IP 協定來建立 TCP 連接配接。建立 TCP 連接配接需要底層 IP 協定來尋址網絡中的主機。我們知道網絡層使用的 IP 協定可以幫助我們根據 IP 位址來找到目标主機,但是一台主機上可能運作着多個應用程式,如何才能與指定的應用程式通信就要通過 TCP 或 UPD 的位址也就是端口号來指定。這樣就可以通過一個 Socket 執行個體唯一代表一個主機上的一個應用程式的通信鍊路了。
而 WebSocket 則不同,它是一個完整的 應用層協定,包含一套标準的 API 。
是以,從使用上來說,WebSocket 更易用,而 Socket 更靈活。
5. HTML5 與 WebSocket
WebSocket API 是 HTML5 标準的一部分, 但這并不代表 WebSocket 一定要用在 HTML 中,或者隻能在基于浏覽器的應用程式中使用。
實際上,許多語言、架構和伺服器都提供了 WebSocket 支援,例如:
- 基于 C 的 libwebsocket.org
- 基于 Node.js 的 Socket.io
- 基于 Python 的 ws4py
- 基于 C++ 的 WebSocket++
- Apache 對 WebSocket 的支援: Apache Module mod_proxy_wstunnel
- Nginx 對 WebSockets 的支援: NGINX as a WebSockets Proxy 、 NGINX Announces Support for WebSocket Protocol 、WebSocket proxying
- lighttpd 對 WebSocket 的支援:mod_websocket