HTTP/TCP/IP協(xié)議詳解

HTTP 1.1 HTTP 2.0

HTTP站在TCP之上

理解http協(xié)議之前一定要對(duì)TCP有一定基礎(chǔ)的了解。HTTP是建立在TCP協(xié)議之上,TCP協(xié)議作為傳輸層協(xié)議其實(shí)離應(yīng)用層并不遠(yuǎn)。HTTP協(xié)議的瓶頸及其優(yōu)化技巧都是基于TCP協(xié)議本身的特性。比如TCP建立連接時(shí)三次握手有1.5個(gè)RTT(round-trip time)的延遲,為了避免每次請(qǐng)求的都經(jīng)歷握手帶來(lái)的延遲,應(yīng)用層會(huì)選擇不同策略的http長(zhǎng)鏈接方案。又比如TCP在建立連接的初期有慢啟動(dòng)(slow start)的特性,所以連接的重用總是比新建連接性能要好。

基于tcp的長(zhǎng)鏈接

http long-polling

http streaming

web socket

移動(dòng)端HTTP現(xiàn)狀

iOS平臺(tái)

iOS系統(tǒng)是從iOS8開(kāi)始才通過(guò)NSURLSession來(lái)支持SPDY的,iOS9+開(kāi)始自動(dòng)支持http2.0。實(shí)際上apple對(duì)http2.0非常有信心,推廣力度也很大。新版本ATS機(jī)制默認(rèn)使用https來(lái)進(jìn)行網(wǎng)絡(luò)傳輸。APN(Apple Push Notifiction)在iOS9上也已經(jīng)是通過(guò)http2.0來(lái)實(shí)現(xiàn)的了。iOS9 sdk里的NSURLSession默認(rèn)使用http2.0,而且對(duì)開(kāi)發(fā)者來(lái)說(shuō)是完全透明的,甚至沒(méi)有api來(lái)知道到底是用的哪個(gè)版本的http協(xié)議。

對(duì)于開(kāi)發(fā)者來(lái)說(shuō)到底怎么去配置最佳的http使用方案呢?在我看來(lái),因app而異,主要從兩方面來(lái)考慮:一是app本身http流量是否大而且密集,二是開(kāi)發(fā)團(tuán)隊(duì)本身的技術(shù)條件。http2.0的部署相對(duì)容易很多,客戶端開(kāi)發(fā)者甚至不用做什么改動(dòng),只需要使用iOS9的SDK編譯即可,但缺點(diǎn)是http2.0只能適用于iOS9的設(shè)備。SPDY的部署相對(duì)麻煩一些,但優(yōu)點(diǎn)是可以兼顧iOS6+的設(shè)備。iOS端的SPDY可以使用twitter開(kāi)發(fā)的CocoaSPDY方案,但有一點(diǎn)需要特別處理:

由于蘋果的TLS實(shí)現(xiàn)不支持NPN,所以通過(guò)NPN協(xié)商使用SPDY就無(wú)法通過(guò)默認(rèn)443端口來(lái)實(shí)現(xiàn)。有兩種做法,一是客戶端和server同時(shí)約定好使用另一個(gè)端口號(hào)來(lái)做NPN協(xié)商,二是server這邊通過(guò)request header智能判斷客戶端是否支持SPDY而越過(guò)NPN協(xié)商過(guò)程。第一種方法會(huì)簡(jiǎn)單一點(diǎn),不過(guò)需要從框架層將所有的http請(qǐng)求都map到另一個(gè)port,url mapping可以參考我之前的一篇文章。twitter自己的網(wǎng)站twitter.com使用的是第二種方法。

瀏覽器端(比如Chrome),server端(比如nginx)都陸續(xù)打算放棄支持spdy了,畢竟google官方都宣布要停止維護(hù)了。spdy會(huì)是一個(gè)過(guò)渡方案,會(huì)隨著iOS9的普及會(huì)逐步消失,所以這部分的技術(shù)投入需要開(kāi)發(fā)團(tuán)隊(duì)自己去衡量。

Android平臺(tái)

android和iOS情況類似,http2.0只能在新系統(tǒng)下支持,spdy作為過(guò)渡方案仍然有存在的必要。

對(duì)于使用webview的app來(lái)說(shuō),需要基于chrome內(nèi)核的webview才能支持spdy和http2.0,而android系統(tǒng)的webview是從android4.4(KitKat)才改成基于chrome內(nèi)核的。

對(duì)于使用native api調(diào)用的http請(qǐng)求來(lái)說(shuō),okhttp是同時(shí)支持spdy和http2.0的可行方案。如果使用ALPN,okhttp要求android系統(tǒng)5.0+(實(shí)際上,android4.4上就有了ALPN的實(shí)現(xiàn),不過(guò)有bug,知道5.0才正式修復(fù)),如果使用NPN,可以從android4.0+開(kāi)始支持,不過(guò)NPN也是屬于將要被淘汰的協(xié)議。

TCP是面向連接的,可靠的字節(jié)流的協(xié)議。連接時(shí)需要三次握手,斷開(kāi)時(shí)需要四次揮手。這是因?yàn)門CP是全雙工的,數(shù)據(jù)可以在兩端傳遞,所以斷開(kāi)時(shí)都需要在每端單獨(dú)進(jìn)行關(guān)閉,一方向的關(guān)閉通常是半關(guān)閉的,所以一端關(guān)閉時(shí)需要發(fā)送FIN來(lái)終止連接,收到后需要確認(rèn)ACK給發(fā)送端。

TCP數(shù)據(jù)在IP數(shù)據(jù)報(bào)中的封裝為20字節(jié)的IP首部加上20字節(jié)TCP首部和TCP數(shù)據(jù)。

TCP/IP協(xié)議族

1.Frame: 物理層 比特流

2.Ethernet II:數(shù)據(jù)鏈路層 以太網(wǎng)幀頭部信息

3.IP網(wǎng)絡(luò)層? IP Packet 頭部信息

4.傳輸層 TCP Data Segment 頭部信息

5.應(yīng)用層 HTTP

網(wǎng)絡(luò)層次劃分為 標(biāo)準(zhǔn)的OSI七層模型,還有 TCP/IP四層協(xié)議 以及 TCP/IP五層協(xié)議。如圖:


Wireshark下

TCP協(xié)議

? TCP是一種面向連接的、可靠的基于字節(jié)流的傳輸層通信協(xié)議。TCP將用戶數(shù)據(jù)打包成報(bào)文段,它發(fā)送后啟動(dòng)一個(gè)定時(shí)器,另一端收到的數(shù)據(jù)進(jìn)行確認(rèn),對(duì)失序的數(shù)據(jù)重新排序、丟棄重復(fù)數(shù)據(jù)。

TCP報(bào)文首部,如下圖所示:

16位源端口號(hào)

16為目的端口號(hào)

Sequence number – 序號(hào)

Acknowledgment number – 確認(rèn)號(hào)

Flags – 標(biāo)志位

—Urgent pointer 緊急指針位

— Acknowledgment 確認(rèn)位

— Push 急迫位

— Reset 重置位

— Syn 同步位

— Fin 終止位


a. 第一次握手標(biāo)志位

localhost Seq=0 -> 博客地址

從標(biāo)志位看出,同步位有值,在做請(qǐng)求(SYN):Syn 同步位為1

b. 第二次握手標(biāo)志位

博客地址 Seq=0 Ack=1 -> localhost

從標(biāo)志位看出,確認(rèn)位、同步位有值,在做應(yīng)答(SYN+ACK):Syn 同步位為 1 、Acknowledgment 確認(rèn)位為 1

c. 第三次握手標(biāo)志位

localhost Seq=1 Ack=1 ->? (注: Seq=Seq+1)

從標(biāo)志位看出,只有確認(rèn)位有值,在做再次確認(rèn)(SYN):Acknowledgment 確認(rèn)位為 1

所以,一個(gè)完整的三次握手就是:請(qǐng)求(SYN) — 應(yīng)答(SYN+ACK) — 再次確認(rèn)(SYN)。

三次握手:


為什么需要“三次握手”

在謝希仁著《計(jì)算機(jī)網(wǎng)絡(luò)》第四版中講“三次握手”的目的是“為了防止已失效的連接請(qǐng)求報(bào)文段突然又傳送到了服務(wù)端,因而產(chǎn)生錯(cuò)誤”。在另一部經(jīng)典的《計(jì)算機(jī)網(wǎng)絡(luò)》一書(shū)中講“三次握手”的目的是為了解決“網(wǎng)絡(luò)中存在延遲的重復(fù)分組”的問(wèn)題。這兩種不同的表述其實(shí)闡明的是同一個(gè)問(wèn)題。

謝希仁版《計(jì)算機(jī)網(wǎng)絡(luò)》中的例子是這樣的,“已失效的連接請(qǐng)求報(bào)文段”的產(chǎn)生在這樣一種情況下:client發(fā)出的第一個(gè)連接請(qǐng)求報(bào)文段并沒(méi)有丟失,而是在某個(gè)網(wǎng)絡(luò)結(jié)點(diǎn)長(zhǎng)時(shí)間的滯留了,以致延誤到連接釋放以后的某個(gè)時(shí)間才到達(dá)server。本來(lái)這是一個(gè)早已失效的報(bào)文段。但server收到此失效的連接請(qǐng)求報(bào)文段后,就誤認(rèn)為是client再次發(fā)出的一個(gè)新的連接請(qǐng)求。于是就向client發(fā)出確認(rèn)報(bào)文段,同意建立連接。假設(shè)不采用“三次握手”,那么只要server發(fā)出確認(rèn),新的連接就建立了。由于現(xiàn)在client并沒(méi)有發(fā)出建立連接的請(qǐng)求,因此不會(huì)理睬server的確認(rèn),也不會(huì)向server發(fā)送數(shù)據(jù)。但server卻以為新的運(yùn)輸連接已經(jīng)建立,并一直等待client發(fā)來(lái)數(shù)據(jù)。這樣,server的很多資源就白白浪費(fèi)掉了。采用“三次握手”的辦法可以防止上述現(xiàn)象發(fā)生。例如剛才那種情況,client不會(huì)向server的確認(rèn)發(fā)出確認(rèn)。server由于收不到確認(rèn),就知道client并沒(méi)有要求建立連接?!薄?主要目的防止server端一直等待,浪費(fèi)資源。

四次揮手:

流量控制(滑動(dòng)窗口協(xié)議)

傳輸數(shù)據(jù)的時(shí)候,如果發(fā)送方傳輸?shù)臄?shù)據(jù)量超過(guò)了接收方的處理能力,那么接收方會(huì)出現(xiàn)丟包。為了避免出現(xiàn)此類問(wèn)題,流量控制要求數(shù)據(jù)傳輸雙方在每次交互時(shí)聲明各自的接收窗口「rwnd」大小,用來(lái)表示自己最大能保存多少數(shù)據(jù),這主要是針對(duì)接收方而言的,通俗點(diǎn)兒說(shuō)就是讓發(fā)送方知道接收方能吃幾碗飯,如果窗口衰減到零,那么就說(shuō)明吃飽了,必須消化消化,如果硬撐的話說(shuō)不定會(huì)大小便失禁,那就是丟包了。

flow control

接收方和發(fā)送方的稱呼是相對(duì)的,如果站在用戶的角度看:當(dāng)瀏覽網(wǎng)頁(yè)時(shí),數(shù)據(jù)以下行為主,此時(shí)客戶端是接收方,服務(wù)端是發(fā)送方;當(dāng)上傳文件時(shí),數(shù)據(jù)以上行為主,此時(shí)客戶端是發(fā)送方,服務(wù)端是接收方。

1、流量控制是管理兩端的流量,以免會(huì)產(chǎn)生發(fā)送過(guò)塊導(dǎo)致收端溢出,或者因收端處理太快而浪費(fèi)時(shí)間的狀態(tài)。用的是:滑動(dòng)窗口,以字節(jié)為單位

2、窗口有3種動(dòng)作:展開(kāi)(右邊向右),合攏(左邊向右),收縮(右邊向左)這三種動(dòng)作受接收端的控制。

合攏:表示已經(jīng)收到相應(yīng)字節(jié)的確認(rèn)了

展開(kāi):表示允許緩存發(fā)送更多的字節(jié)

收縮(非常不希望出現(xiàn)的,某些實(shí)現(xiàn)是禁止的):表示本來(lái)可以發(fā)送的,現(xiàn)在不能發(fā)送;但是如果收縮的是那些已經(jīng)發(fā)出的,就會(huì)有問(wèn)題;為了避免,收端會(huì)等待到緩存中有更多緩存空間時(shí)才進(jìn)行通信。

發(fā)端窗口的大小取決于收端的窗口大小rwnd(TCP報(bào)文的窗口大小字段)和擁塞窗口大小cwnd(見(jiàn)擁塞控制)

發(fā)端窗口大小 = min{ rwnd , cwnd };

3、關(guān)閉窗口:窗口縮回有個(gè)例外,就是發(fā)送rwnd=0表示暫時(shí)不愿意接收數(shù)據(jù)。這種情況下,發(fā)端不是把窗口收縮,二是停止發(fā)送數(shù)據(jù)。(為了比避免死鎖,會(huì)用一些探測(cè)報(bào)定時(shí)發(fā)送試探,見(jiàn)定時(shí)器一節(jié))

4、問(wèn)題:某些時(shí)候,由于發(fā)端或收端的數(shù)據(jù)很慢,會(huì)引起大量的1字節(jié)數(shù)據(jù)痛惜,浪費(fèi)很多資源。

(1)、發(fā)端的進(jìn)程產(chǎn)生數(shù)據(jù)很慢時(shí)候,時(shí)不時(shí)的來(lái)個(gè)1字節(jié)數(shù)據(jù),那么TCP就會(huì)1字節(jié)1字節(jié)的發(fā)送,效率很低。

解決方法(Nagle算法):

a、將第一塊數(shù)據(jù)發(fā)出去

b、然后等到發(fā)送緩存有足夠多的數(shù)據(jù)(最大報(bào)文段長(zhǎng)度),或者等到收端確認(rèn)的ACK時(shí)再發(fā)送數(shù)據(jù)。

c、重復(fù)b的過(guò)程

(2)、收端進(jìn)程由于消耗數(shù)據(jù)很慢,所以可能會(huì)有這么一種情況,收端會(huì)發(fā)送其窗口大小為1的信息,然后有是1字節(jié)的傳輸

解決辦法(2種)

a、Clark方法:在接收緩存的一半變空,或者有足夠空間放最大報(bào)文長(zhǎng)度之前,宣告接收窗口大小為0

b、推遲確認(rèn):在對(duì)收到的報(bào)文段確認(rèn)之前等待到足夠的接收緩存,或者等待到一個(gè)時(shí)間段(現(xiàn)在一般定義500ms)


慢啟動(dòng)

雖然流量控制可以避免發(fā)送方過(guò)載接收方,但是卻無(wú)法避免過(guò)載網(wǎng)絡(luò),這是因?yàn)榻邮沾翱凇竢wnd」只反映了服務(wù)器個(gè)體的情況,卻無(wú)法反映網(wǎng)絡(luò)整體的情況。

為了避免過(guò)載網(wǎng)絡(luò)的問(wèn)題,慢啟動(dòng)引入了擁塞窗口「cwnd」的概念,用來(lái)表示發(fā)送方在得到接收方確認(rèn)前,最大允許傳輸?shù)奈唇?jīng)確認(rèn)的數(shù)據(jù)?!竎wnd」同「rwnd」相比不同的是:它只是發(fā)送方的一個(gè)內(nèi)部參數(shù),無(wú)需通知給接收方,其初始值往往比較小,然后隨著數(shù)據(jù)包被接收方確認(rèn),窗口成倍擴(kuò)大,有點(diǎn)類似于拳擊比賽,開(kāi)始時(shí)不了解敵情,往往是次拳試探,慢慢心里有底了,開(kāi)始逐漸加大重拳進(jìn)攻的力度。

Slow Start

在慢啟動(dòng)的過(guò)程中,隨著「cwnd」的增加,可能會(huì)出現(xiàn)網(wǎng)絡(luò)過(guò)載,其外在表現(xiàn)就是丟包,一旦出現(xiàn)此類問(wèn)題,「cwnd」的大小會(huì)迅速衰減,以便網(wǎng)絡(luò)能夠緩過(guò)來(lái)。

說(shuō)明:網(wǎng)絡(luò)中實(shí)際傳輸?shù)奈唇?jīng)確認(rèn)的數(shù)據(jù)大小取決于「rwnd」和「cwnd」中的小值。

T C P的 流 量 控 制 由 連 接 的 每 一 端 通 過(guò) 聲 明 的 窗 口 大 小 來(lái) 提 供 。 窗 口 大 小 為 字 節(jié) 數(shù) , 起 始于確認(rèn)序號(hào)字段指明的值,這個(gè)值是接收端正期望接收的字節(jié)。窗口大小是一個(gè)16 bit字段,因 而 窗 口 大 小 最 大 為6 5 5 3 5字節(jié)。在2 4 . 4節(jié) 我 們 將 看 到 新 的 窗 口 刻 度 選 項(xiàng) , 它 允 許 這 個(gè) 值 按 比例變化以提供更大的窗口。檢驗(yàn)和覆蓋了整個(gè)的T C P報(bào)文段:T C P首部和T C P數(shù) 據(jù) 。 這 是 一 個(gè) 強(qiáng) 制 性 的 字 段 , 一 定 是由發(fā)端計(jì)算和存儲(chǔ),并由收端進(jìn)行驗(yàn)證。T C P檢驗(yàn)和的計(jì)算和U D P檢 驗(yàn) 和 的 計(jì) 算 相 似 , 使 用一 個(gè) 偽 首 部 。只有當(dāng)U R G標(biāo)志置1時(shí) 緊 急 指 針 才 有 效 。 緊 急 指 針 是 一 個(gè) 正 的 偏 移 量 , 和 序 號(hào) 字 段 中 的 值相加表示緊急數(shù)據(jù)最后一個(gè)字節(jié)的序號(hào)。T C P的 緊 急 方 式 是 發(fā) 送 端 向 另 一 端 發(fā) 送 緊 急 數(shù) 據(jù) 的一種方式。

擁塞避免

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.這篇文章不是本人原創(chuàng)的,只是個(gè)人為了對(duì)這部分知識(shí)做一個(gè)整理和系統(tǒng)的輸出而編輯成的,在此鄭重地向本文所引用文章的...
    SOMCENT閱讀 13,340評(píng)論 6 174
  • 個(gè)人認(rèn)為,Goodboy1881先生的TCP /IP 協(xié)議詳解學(xué)習(xí)博客系列博客是一部非常精彩的學(xué)習(xí)筆記,這雖然只是...
    貳零壹柒_fc10閱讀 5,184評(píng)論 0 8
  • 傳輸層-TCP, TCP頭部結(jié)構(gòu) ,TCP序列號(hào)和確認(rèn)號(hào)詳解 TCP主要解決下面的三個(gè)問(wèn)題 1.數(shù)據(jù)的可靠傳輸...
    抓兔子的貓閱讀 4,621評(píng)論 1 46
  • 1.OkHttp源碼解析(一):OKHttp初階2 OkHttp源碼解析(二):OkHttp連接的"前戲"——HT...
    隔壁老李頭閱讀 21,546評(píng)論 24 176
  • TCP/IP協(xié)議 作者:xinyuans 本文為參考TCP/IP詳解卷一,某些知識(shí)點(diǎn)加上了作者自己的理解,如有錯(cuò)誤...
    xinyuans閱讀 996評(píng)論 0 1

友情鏈接更多精彩內(nèi)容