有關(IM)即時通訊的基本概念

初涉IM,首先我有這么幾個問題需要弄明白:

  1. Socket 和 WebSocket 有哪些區別和聯系?
  2. WebSocket 和 HTTP 有什么關系?
  3. WebSocket 和 HTML5 是什么關系?
  4. 什么是 長連接/短連接、長輪詢/短輪詢?
  5. WebSocket在哪些場景下使用?
  6. 如果想做IOS的即時通訊,是使用Socket還是WebSocket?

通過google查找了大量資料,覺得有必要把相關內容做一個整理,上面幾個問題也會在敘述中逐漸清晰。

1. Socket 和 WebSocket 有哪些區別和聯系?

就像JavaJavaScript北大北大青鳥雷鋒雷峰塔一樣,沒有什么關系,除了在名字上沾親帶故的以外,就是兩個完全不同的東西。

WebSocket

WebSocket一種在單個TCP連接上進行全雙工通訊的協議。WebSocket通信協議于2011年被IETF定為標準RFC 6455,并被RFC7936所補充規范。WebSocket API也被W3C定為標準。——維基百科


背景
現在,很多網站為了實現推送技術,所用的技術都是輪詢。輪詢是在特定的時間間隔(如每1秒)由客戶端對服務器發出HTTP請求,然后由服務器返回最新的數據給客戶端。這種傳統的模式帶來很明顯的缺點,即客戶端需要不斷的向服務器發出請求,然而HTTP請求可能包含較長的頭部,其中真正有效的數據可能只是很小的一部分,顯然這樣會浪費很多的帶寬等資源。

而比較新的技術去做輪詢的效果是Comet。這種技術雖然可以雙向通信,但依然需要反復發出請求。而且在Comet中,普遍采用的長鏈接,也會消耗服務器資源。
在這種情況下,HTML5定義了WebSocket協議,能更好的節省服務器資源和帶寬,并且能夠更實時地進行通訊。
Websocket使用ws或wss的統一資源標志符,類似于HTTPS,其中wss表示在TLS之上的Websocket。如:

ws://example.com/wsapi
wss://secure.example.com/

Websocket使用和 HTTP 相同的 TCP 端口,可以繞過大多數防火墻的限制。默認情況下,Websocket協議使用80端口;運行在TLS之上時,默認使用443端口。

WebSocket出現的目的:即時通訊,替代HTTP輪詢

WebSocket 使得客戶端和服務器之間的數據交換變得更加簡單,允許服務端主動向客戶端推送數據。在 WebSocket API 中,瀏覽器和服務器只需要完成一次握手,兩者之間就直接可以創建持久性的連接,并進行雙向數據傳輸。

(1)最初的輪詢(polling)階段

Polling.png

上圖表明,客戶端發送一個request,服務器不管有沒有新消息,都會立即返回一個response,然后關閉連接,這次HTTP請求結束。請記住 Request = Response , 在HTTP1.0和HTTP1.1中都是這樣,也就是說一個request只能有一個response對應。客戶端需要不斷執行這個請求過程(也就是輪詢),查詢服務端有沒有新的消息(數據)。

輪詢場景:

Client:親親,有沒有新消息(Request)
Server:木有(Response)
Client:親親,有沒有新消息(Request)
Server:木有。。(Response)
Client:親親,有沒有新消息(Request)
Server:好煩,沒有。。(Response)
Client:那個。。有沒有新消息(Request)
Server: 有啦,給你(Response)
Client:親親,有沒有新消息(Request)
Server:。。沒。。。沒有(Response)
...
...

從上面可以看出來,客戶端不斷的建立HTTP連接,然后等待服務端處理,可以提現HTTP協議的另一個缺陷:被動性,也就是服務端不能主動聯系客戶端,只能有客戶端發起。而且,HTTP request的Header是很長的,為了傳輸一個很小的數據卻占用了很多的帶寬流量去傳輸Header。可見,輪詢需要服務器有很快的處理速度,且非常消耗資源,也不具備即時性。

(2)長輪詢 (Long polling) 階段

Long Polling.png

Long Polling 是對 Polling 的改進,原理跟 Polling 相似,都是采用輪詢的方式,不過Long Polling 采取的是阻塞模型:客戶端發起連接后,如果服務端沒有新消息,就一直不返回Response給客戶端。直到有新消息或者超時才返回給客戶端,返回之后這次請求結束。客戶端再次建立連接,重復這個過程。。。。

情景:
Client:親親,有沒有新消息? 沒有的話,等有了再給我吧 (Request)
Server:額。。。~~~ (1小時后) ~~~ 有新消息了,給你 (Response)
...
...

相比于 Polling ,Long Polling 在某種程度上減小了對網絡寬帶的消耗等問題,但缺陷也很明顯:假設服務器端的數據更新速度很快,服務器在傳送一個數據包給客戶端后必須等待客戶端的下一個Get請求到來,才能傳遞第二個更新的數據包給客戶端,那么這樣的話,客戶端顯示實時數據最快的時間為2×RTT(往返時間),而且如果在網絡擁塞的情況下,這個時間用戶是不能接受的,比如在股市的的報價上;另外,由于http數據包的頭部數據量往往很大(通常有400多個字節),但是真正被服務器需要的數據卻很少(有時只有10個字節左右),這樣的數據包在網絡上周期性的傳輸,難免對網絡帶寬是一種浪費;而且 Long Polling 要求服務器具有高并發性,也就是同時接待大量客戶端的能力。

(3) WebSocket
從上面分析可以看出,Polling ,Long Polling 不是最好的方式,Polling 需要服務端更快的處理速度,Long Polling 需要高并發性。在這種情況下,WebSocket出現,解決了上面提到的 HTTP 協議存在的幾個缺陷。

下面三張圖,是WebSocket建立連接、傳輸數據以及關閉連接的模型,至于為什么放三張相似的圖,因為。。。我覺得這三張圖都挺好看的

1.png
2.jpg
3.png
情景:
Client:親親,我要建立WebSocket協議,需要的服務:chat,WebSocket協議版本:17 (HTTP Request)
Server:ok,確認,已升級為WebSocket協議 (HTTP Protocols Switched)
Client:麻煩你有新消息的時候推送給我哦。。
Server:ok,有的時候會告訴你的。
Server:balabalabalabala
Server:balabalabalabala
Server:我看到一個笑話,哈哈哈
Server:哈哈哈哈哈哈哈。。。。。

Websocket是應用層第七層上的一個應用層協議,它必須依賴 HTTP 協議進行一次握手 ,握手成功后,數據就直接從 TCP 通道傳輸,與 HTTP 無關了。
Websocket的數據傳輸是以 frame (幀) 形式傳輸的,比如會將一條消息分為幾個 frame,按照先后順序傳輸出去。這樣做會有幾個好處:

  1. 大數據的傳輸可以分片傳輸,不用考慮到數據大小導致的長度標志位不足夠的情況。
  2. 和 HTTP 的chunk一樣,可以邊生成數據邊傳遞消息,即提高傳輸效率。

一個典型的Websocket握手請求如下:

客戶端請求
GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==
Sec-WebSocket-Version: 13
服務器回應
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=
Sec-WebSocket-Location: ws://example.com/

字段說明:

  1. Connection必須設置Upgrade,表示客戶端希望連接升級。
  2. Upgrade字段必須設置Websocket,表示希望升級到Websocket協議。
  3. Sec-WebSocket-Key是隨機的字符串,服務器端會用這些數據來構造出一個SHA-1的信息摘要。把“Sec-WebSocket-Key”加上一個特殊字符串“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”,然后計算SHA-1摘要,之后進行BASE-64編碼,將結果做為“Sec-WebSocket-Accept”頭的值,返回給客戶端。如此操作,可以盡量避免普通HTTP請求被誤認為Websocket協議。
  4. Sec-WebSocket-Version 表示支持的Websocket版本。RFC6455要求使用的版本是13,之前草案的版本均應當被棄用。
  5. Origin字段是可選的,通常用來表示在瀏覽器中發起此Websocket連接所在的頁面,類似于Referer。但是,于Referer不同的是,Origin只包含了協議和主機名稱。
  6. 其他一些定義在HTTP協議中的字段,如Cookie等,也可以在Websocket中使用。
Socket

Socket并不是一個協議,而是為了方便使用TCP或UDP而抽象出來的一層,是位于應用層和傳輸控制層之間的一組接口。如果你要使用HTTP來構建服務,那么就不需要關心Socket,如果你想基于TCP/IP來構建服務,那么Socket可能就是你會接觸到的API。


網絡上的兩個程序通過一個雙向的通信連接實現數據的交換,這個連接的一端稱為一個socket。
建立網絡通信連接至少要一對端口號(socket)。socket本質是編程接口(API),對TCP/IP的封裝,
TCP/IP也要提供可供程序員做網絡開發所用的接口,這就是Socket編程接口;
HTTP是轎車,提供了封裝或者顯示數據的具體形式;Socket是發動機,提供了網絡通信的能力。—— 百度百科



Socket是應用層與TCP/IP協議族通信的中間軟件抽象層,它是一組接口。
在設計模式中,Socket其實就是一個門面模式,它把復雜的TCP/IP協議族隱藏在Socket接口后面,
對用戶來說,一組簡單的接口就是全部,讓Socket去組織數據,以符合指定的協議。 —— XX百科


Paste_Image.png

當兩臺主機通信時,必須通過Socket連接,Socket則利用TCP/IP協議建立TCP連接。
TCP連接則更依靠于底層的IP協議,IP協議的連接則依賴于鏈路層等更低層次。
WebSocket則是一個典型的應用層協議。

2. WebSocket 和 HTTP 有什么關系?

先看一下這兩個概念在維基百科中的解釋:


WebSocket is a computer communications protocol, providing full-duplex communication channels over a single TCP connection. The WebSocket protocol was standardized by the IETF as RFC 6455 in 2011, and the WebSocket API in Web IDL is being standardized by the W3C.
WebSocket is designed to be implemented in web browsers and web servers, but it can be used by any client or server application. The WebSocket Protocol is an independent TCP-based protocol. Its only relationship to HTTP is that its handshake is interpreted by HTTP servers as an Upgrade request.[1]
The WebSocket protocol enables interaction between a browser and a web server with lower overheads, facilitating real-time data transfer from and to the server. This is made possible by providing a standardized way for the server to send content to the browser without being solicited by the client, and allowing for messages to be passed back and forth while keeping the connection open. In this way, a two-way (bi-directional) ongoing conversation can take place between a browser and the server. The communications are done over TCP port number 80 (or 443 in the case of TLS-encrypted connections), which is of benefit for those environments which block non-web Internet connections using a firewall.

—— From Wikipedia, the free encyclopedia


The Hypertext Transfer Protocol (HTTP) is an application protocol for distributed, collaborative, and hypermedia information systems.
HTTP is the foundation of data communication for the World Wide Web.
Hypertext is structured text that uses logical links (hyperlinks) between nodes containing text. HTTP is the protocol to exchange or transfer hypertext.
Development of HTTP was initiated by Tim Berners-Lee at CERN in 1989. Standards development of HTTP was coordinated by the Internet Engineering Task Force (IETF) and the World Wide Web Consortium (W3C), culminating in the publication of a series of Requests for Comments (RFCs). The first definition of HTTP/1.1, the version of HTTP in common use, occurred in RFC 2068 in 1997, although this was obsoleted by RFC 2616 in 1999 and then again by RFC 7230 and family in 2014.
A later version, the successor HTTP/2, was standardized in 2015, and is now supported by major web servers.

—— From Wikipedia, the free encyclopedia


相同點:
WebSocket 和 HTTP 都是基于TCP的應用層協議,都是可靠性傳輸協議。

不同點:

  1. 本來就是兩種完全不同的協議。。。
  2. WebSocket 是全雙工協議,可以雙向發送或接受信息,連接建立之后,通信雙方都可以在任何時刻向另一方發送數據。HTTP請求需要等待客戶端發起請求服務端才能響應。
  3. 與 HTTP 不同的是,Websocket 需要先創建連接,這就使得其成為一種有狀態的協議,之后通信時可以省略部分狀態信息。而HTTP請求可能需要在每個請求都攜帶狀態信息(如身份認證等)
  4. Websocket定義了二進制幀,相對HTTP,可以更輕松地處理二進制內容。
  5. HTTP 協議要不斷的建立,關閉Request,由于HTTP是無狀態協議,每一次發送都是一次新的開始,所以每次都要重新傳輸identity info (鑒別信息),來告訴服務端你是誰。Websocket 只需要一次HTTP握手,所以說整個通訊過程是建立在一次連接狀態中,也就避免了HTTP的非狀態性,服務端會一直知道你的信息,直到你關閉請求,這樣就可以避免反復解析HTTP協議,還要查看identity info(鑒別信息)。

聯系:
Websocket 通過 HTTP/1.1 協議的101狀態碼進行握手。
為了創建Websocket連接,需要通過客戶端發出請求,之后服務器進行回應,這個過程通常稱為“握手”(handshaking)。

雖然WebSocket在握手的時候是通過 HTTP 進行的(為了兼容性考慮,也許以后WebSocket會有自己的握手方式),但也僅僅是這樣而已,它們就是兩種不同的應用層協議。

3. WebSocket 和 HTML5 是什么關系?

HTML5是指的一系列新的API,或者說新規范,新技術。而WebSocket就是HTML5中出的的一種協議。

4. 什么是 長連接/短連接、長輪詢/短輪詢?

查了許多資料,于是總結一下自己的理解:

長連接/短連接,長輪詢/短輪詢 本身就是不通層次的概念。

長/短連接 是針對TCP傳輸層的概念,也就是,TCP連接才有長/短連接之說。

短連接是指通訊雙方有數據交互時,就建立一個TCP連接,數據發送完成后,則斷開此連接,即每次連接只完成一項業務的發送。

長連接指在一個TCP連接上可以連續發送多個數據包,在連接保持期間,如果沒有數據包發送,需要TCP keep alive。TCP keep alive 的兩種方式:

  1. 應用層面的心跳機制
    自定義心跳消息頭 : 一般客戶端主動發送, 服務器接收后進行回應(也可以不回應).
  2. TCP協議自帶的 keep alive:打開keep-alive功能即可. 具體屬性也可以通過API設定.

TCP KeepAlive 是用于檢測TCP連接的狀態,而心跳機制有兩個作用:一是檢測TCP的狀態,二是檢測通訊雙方的狀體。

考慮一種情況,某臺服務器因為某些原因導致負載超高,CPU 100%,無法響應任何業務請求,但是使用 TCP 探針則仍舊能夠確定連接狀態,這就是典型的連接活著但業務提供方已死的狀態,對客戶端而言,這時的最好選擇就是斷線后重新連接其他服務器,而不是一直認為當前服務器是可用狀態,一直向當前服務器發送些必然會失敗的請求。

從上面我們可以知道,KeepAlive 并不適用于檢測雙方存活的場景,這種場景還得依賴于應用層的心跳。應用層心跳有著更大的靈活性,可以控制檢測時機,間隔和處理流程,甚至可以在心跳包上附帶額外信息。從這個角度而言,應用層的心跳的確是最佳實踐。

寫到這順便說一下 HTTP Keep Alive 和 TCP keep alive 這兩個看上去肯定有點兒啥關系的概念。事實上,HTTP keep-alive與TCP keep-alive 是兩個完全沒有關系的東西。

HTTP keep-alive是HTTP協議的一個特性,目的是為了讓TCP連接保持的更久一點,以便客戶端/服務端在同一個TCP連接上可以發送多個HTTP request/response。

TCP keep-alive是一種檢測連接狀況的保活機制。It keeps TCP connection opened by sending small packets. 當網絡兩端建立了TCP連接之后,閑置idle(雙方沒有任何數據流發送往來)了tcp_keepalive_time后,服務器內核就會嘗試向客戶端發送偵測包,來判斷TCP連接狀況(有可能客戶端崩潰、強制關閉了應用、主機不可達等等)。如果沒有收到對方的回答(ack包),則會在 tcp_keepalive_intvl后再次嘗試發送偵測包,直到收到對對方的ack,如果一直沒有收到對方的ack,一共會嘗試 tcp_keepalive_probes次,每次的間隔時間在這里分別是15s, 30s, 45s, 60s, 75s。如果嘗試tcp_keepalive_probes,依然沒有收到對方的ack包,則會丟棄該TCP連接。TCP連接默認閑置時間是2小時,一般設置為30分鐘足夠了。

既然長/短連接是針對TCP的概念,但是我們卻經常看到HTTP 長連接(HTTP persistent connection)這樣的說法,到底什么鬼?憋急,先看一段解釋:


HTTP persistent connection, also called HTTP keep-alive, or HTTP connection reuse, is the idea of using a single TCP connection to send and receive multiple HTTP requests/responses, as opposed to opening a new connection for every single request/response pair. The newer HTTP/2 protocol uses the same idea and takes it further to allow multiple concurrent requests/responses to be multiplexed over a single connection.

—— From Wikipedia, the free encyclopedia


可以發現,HTTP persistent connection就是上面我們解釋的HTTP Keep Alive。其實很簡單,TCP長連接是針對TCP層的概念,就是讓一個TCP連接長時間保持不要斷開。HTTP的長連接(keep alive)是HTTP協議的一個特性,也是希望保持住長時間的TCP連接,才能在這個TCP通道上發送多個HTTP請求,而不必每次請求都打開一個新的TCP連接。

長輪詢/短輪詢 在上文已經介紹了,它是服務器的實現方式!由服務端編寫的代碼決定。

5. WebSocket在哪些場景下使用?

1.社交聊天

最著名的就是微信,QQ,這一類社交聊天的app。這一類聊天app的特點是低延遲,高即時。即時是這里面要求最高的,如果有一個緊急的事情,通過IM軟件通知你,假設網絡環境良好的情況下,這條message還無法立即送達到你的客戶端上,緊急的事情都結束了,你才收到消息,那么這個軟件肯定是失敗的。

2.彈幕

說到這里,大家一定里面想到了A站和B站了。確實,他們的彈幕一直是一種特色。而且彈幕對于一個視頻來說,很可能彈幕才是精華。發彈幕需要實時顯示,也需要和聊天一樣,需要即時。

3.多玩家游戲

4.協同編輯

現在很多開源項目都是分散在世界各地的開發者一起協同開發,此時就會用到版本控制系統,比如Git,SVN去合并沖突。但是如果有一份文檔,支持多人實時在線協同編輯,那么此時就會用到比如WebSocket了,它可以保證各個編輯者都在編輯同一個文檔,此時不需要用到Git,SVN這些版本控制,因為在協同編輯界面就會實時看到對方編輯了什么,誰在修改哪些段落和文字。

5.股票基金實時報價

金融界瞬息萬變——幾乎是每毫秒都在變化。如果采用的網絡架構無法滿足實時性,那么就會給客戶帶來巨大的損失。幾毫秒錢股票開始大跌,幾秒以后才刷新數據,一秒鐘的時間內,很可能用戶就已經損失巨大財產了。

6.體育實況更新

全世界的球迷,體育愛好者特別多,當然大家在關心自己喜歡的體育活動的時候,比賽實時的賽況是他們最最關心的事情。這類新聞中最好的體驗就是利用Websocket達到實時的更新!

7.視頻會議/聊天

視頻會議并不能代替和真人相見,但是他能讓分布在全球天涯海角的人聚在電腦前一起開會。既能節省大家聚在一起路上花費的時間,討論聚會地點的糾結,還能隨時隨地,只要有網絡就可以開會。

8.基于位置的應用

越來越多的開發者借用移動設備的GPS功能來實現他們基于位置的網絡應用。如果你一直記錄用戶的位置(比如運行應用來記錄運動軌跡),你可以收集到更加細致化的數據。

9.在線教育

在線教育近幾年也發展迅速。優點很多,免去了場地的限制,能讓名師的資源合理的分配給全國各地想要學習知識的同學手上,Websocket是個不錯的選擇,可以視頻聊天、即時聊天以及其與別人合作一起在網上討論問題…

10.智能家居

這也是我一畢業加入的一個偉大的物聯網智能家居的公司。考慮到家里的智能設備的狀態必須需要實時的展現在手機app客戶端上,毫無疑問選擇了Websocket。

從上面我列舉的這些場景來看,一個共同點就是,高實時性!

6. 如果想做IOS的即時通訊,是使用Socket還是WebSocket?

使用 Socket 和 WebSocket 都可以做即時通訊。具體怎么做呢?公司項目IOS端使用了第三方庫 CocoaAsynSocket ,它是對socket的OC封裝,支持TCP、UDP連接。CocoaAsynSocket 的使用非常簡單,也有官方和其他資料可以查找,這里就不啰嗦了。這篇文章只是對即時通訊涉及的一些基本概念,根據我自己的理解,做一個總結,如果有不對的地方還請不吝指正,感激不盡!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容