本文借助wireshark抓包詳細的講解常用的網(wǎng)絡(luò)協(xié)議贯被。涉及的主要協(xié)議包括但不限于http協(xié)議
西采、tcp協(xié)議
、ip協(xié)議
妓布。為了表述的準(zhǔn)確性棚唆,嚴重的參考了參考了謝希仁的《計算機網(wǎng)絡(luò)》這本教程熏矿。
一绘趋、http請求抓包
通過如下命令請求一次百度的首頁炒事。
curl -v -i www.baidu.com
通過wireshark抓包如下:
其中
紅色框:tcp三次握手
藍色框:http請求與應(yīng)答
綠色框:tcp四次揮手
本文會以上文的數(shù)據(jù)包來展開分析
在正式介紹之前,我們現(xiàn)在一張圖娃圆,請求是如何一步一步封裝的汽久。以http請求為例
在數(shù)據(jù)鏈路層中有一個MTU的東西,表示上層payload最大的大杏徊汀(單位byte) 有了這個東西就意味著如果上層的報文太大,必須要分割臀稚。在ip協(xié)議里叫分片
吝岭;在tcp協(xié)議里叫分段
,同時會涉及到tcp建立連接時(三次握手中的前兩次握手)窜管,客戶端和服務(wù)端會協(xié)商tcp header中MSS(最大數(shù)據(jù)報文段長度)字段散劫。具體的我們后面會說道。
二幕帆、IP協(xié)議(RFC 791)
IP數(shù)據(jù)報的格式如下圖二
Ip數(shù)據(jù)報分為首部和數(shù)據(jù)部分兩個部分获搏。其中IP首部又分為固定首部
+可變部分
,固定部分長度固定為20個字節(jié)失乾。
wireshark抓包如下:
2.1 IP header 固定部分
- 版本(4位):IP協(xié)議的版本常熙,目前的IP協(xié)議版本號為4,下一代IP協(xié)議版本號為6碱茁。
- 首部長度(4位):IP報頭的長度裸卫,注意
單位為4個字節(jié)
。固定部分的長度(20字節(jié))和可變部分的長度之和纽竣。共占4位墓贿。最大為1111,即10進制的15蜓氨,代表IP報頭的最大長度可以為15*4=60字節(jié)聋袋,除去固定部分的長度20字節(jié),可變部分的長度最大為40字節(jié)穴吹。 - 區(qū)分服務(wù)(8位): 用來獲得更好的服務(wù)幽勒,現(xiàn)在基本不用,可以忽略
- 總長度(16位):IP報文的總長度刀荒。報頭的長度和數(shù)據(jù)部分的長度之和代嗤。所以一個IP報文的的最大長度為65535個字節(jié)。受MTU限制缠借,最大只能為1500字節(jié)
- 標(biāo)識(16位):唯一的標(biāo)識主機發(fā)送的每一分數(shù)據(jù)報干毅。通常每發(fā)送一個報文,它的值加一泼返。當(dāng)IP報文長度超過傳輸網(wǎng)絡(luò)的MTU(最大傳輸單元)時必須分片硝逢,這個標(biāo)識字段的值被復(fù)制到所有數(shù)據(jù)分片的標(biāo)識字段中,使得這些分片在達到最終目的地時可以依照標(biāo)識字段的內(nèi)容重新組成原先的數(shù)據(jù)绅喉。
- 標(biāo)志(3位):共3位渠鸽。R、DF柴罐、MF三位徽缚。目前只有后兩位有效,DF位:為1表示不分片革屠,為0表示分片凿试。MF:為1表示“更多的片”排宰,為0表示這是最后一片。
- 片位移(13位):
單位為8字節(jié)
那婉,指當(dāng)前分片在原數(shù)據(jù)報(分片前的數(shù)據(jù)報)中相對于用戶數(shù)據(jù)字段的偏移量板甘,即在原數(shù)據(jù)報中的相對位置。(需要再乘以8) - 生存時間(8位):TTL(Time to Live)详炬。該字段表明當(dāng)前報文還能生存多久盐类,現(xiàn)在指跳數(shù)。每經(jīng)過一個網(wǎng)關(guān)呛谜,TTL的值自動減1在跳,當(dāng)生存時間為0時,報文將被認為目的主機不可到達而丟棄呻率。TTL 字段是由發(fā)送端初始設(shè)置一個 8 bit字段.推薦的初始值由分配數(shù)字 RFC 指定硬毕,當(dāng)前值為 64。發(fā)送 ICMP 回顯應(yīng)答時經(jīng)常把 TTL 設(shè)為最大值 255礼仗。
- 協(xié)議(8位):指出IP報文攜帶的數(shù)據(jù)使用的是那種協(xié)議吐咳,以便目的主機的IP層能知道要將數(shù)據(jù)報上交到哪個進程(不同的協(xié)議有專門不同的進程處理)。和端口號類似元践,此處采用協(xié)議號韭脊,TCP的協(xié)議號為6,UDP的協(xié)議號為17单旁。ICMP的協(xié)議號為1沪羔,IGMP的協(xié)議號為2.
- 首部校驗和(16位):用于檢驗IP
報文頭部
(不包含數(shù)據(jù)部分)在傳播的過程中是否出錯,檢查IP報頭的完整性象浑。 - 源IP地址(32位):源ip地址
- 目的IP地址(32位):目標(biāo)ip地址
2.2 IP header 不固定部分
就因為ip header存在不固定部分蔫饰,所以在固定部分才需要字段首部長度
。ip header中不固定部分主要是用來增加ip數(shù)據(jù)報的功能的(1-40字節(jié))愉豺。但是該部分很少使用篓吁,所以IPv6中沒有該部分。所以可以忽略這部分的內(nèi)容蚪拦。
2.3 關(guān)于IP數(shù)據(jù)報分片
前面有提到過杖剪,在數(shù)據(jù)鏈路層有MTU限制即IP數(shù)據(jù)報的最大報文長度為1500字節(jié),那么當(dāng)ip數(shù)據(jù)長度超過1500時候驰贷,就需要分片
盛嘿。舉例如下:
假設(shè)一個數(shù)據(jù)報總長度為3820字節(jié),其中數(shù)據(jù)部分為3800字節(jié)(使用固定首都20字節(jié)括袒,無可變部分)次兆。顯然3820超過MTU,需要分片锹锰。假設(shè)分片長度不超1420字節(jié)芥炭,出去20字節(jié)首都狈邑,那每個分片數(shù)據(jù)部分最長為1400。所以需要將數(shù)據(jù)部分分為三個數(shù)據(jù)報片(1400蚤认、1400、1000)糕伐。那么分片后砰琢,如何重新組裝回一個完整的IP數(shù)據(jù)報呢?就需要上面提到的標(biāo)識
和片位移
兩個字段良瞧。分成3個數(shù)據(jù)報片的標(biāo)識字段是一樣的陪汽。再加上片位移字段就能計算出該分片在原數(shù)據(jù)報中的位置。上面三個分片的片位移分別為(0/8=0; 1400/8=175; 2800/8=350)褥蚯。注意片位移單位為8字節(jié)
三挚冤、TCP協(xié)議(RFC 793)
TCP協(xié)議是比較復(fù)雜的,要是搞明白TCP協(xié)議赞庶,就需要回答三個問題训挡。(1)TCP如何保證可靠性傳輸
;(2)TCP如何做流量控制
歧强;(3)TCP如何做擁塞控制
澜薄。我們先從簡單的TCP報文段格式開始介紹。
TCP報文段的格式如下圖三
3.1 TCP header固定首部
- 源端口和目的端口(16位):見名知意
- 序號(32位):序號范圍
摊册, 當(dāng)序號到達最大值
后, 下一個序號就是0肤京。TCP是面向
字節(jié)流
的,在一個TCP鏈接中傳送的每一個字節(jié)都是按循序編號茅特。整個要傳送的字節(jié)流的起始序號必須在建立連接的時候設(shè)置忘分。首部中的序號字段值指的本報文段所發(fā)送數(shù)據(jù)的第一個字節(jié)的序號。 - 確認號(32位):期望收到對方下一個報文段的第一個數(shù)據(jù)字節(jié)的序號白修。比如B收到A發(fā)過來的一個報文段妒峦,其序號字段值為500,數(shù)據(jù)長度為200字節(jié)熬荆,即序501-700(注意是A的數(shù)據(jù)長度舟山,不包括TCP頭的長度)。那B發(fā)給A的報文段中確認號為701卤恳。這表明B已經(jīng)正確收到了A發(fā)送的序號到700的數(shù)據(jù)累盗。因此B希望收到A下一個數(shù)據(jù)序號為701。
- 數(shù)據(jù)偏移(4位):指的是數(shù)據(jù)部分距離報文段起始處的偏移量突琳,實際上指的是首部的長度若债。
- 保留(6位):保留今后使用,但目前全部為0
- 緊急URG(1位):當(dāng)URG為1時拆融,表明該報文段有緊急數(shù)據(jù)蠢琳。需要優(yōu)先傳送啊终,而不要按原來的排隊順序來傳送。
- 確認ACK(1位):僅當(dāng)ACK位為1時傲须,
確認號
字段才有效蓝牲。 - 推送PSH(1位):當(dāng)兩個應(yīng)用進程進行交互式通信時候,有時候在一端的應(yīng)用進程信息網(wǎng)當(dāng)鍵入一個命令后立即就能收到對方的響應(yīng)泰讽。在這種情況下例衍,TCP就可以使用推送(push)操作。這時已卸,發(fā)送方TCP把PSH置為1佛玄,并立即創(chuàng)建一個報文段發(fā)送過去。接收方收到PSH=1的報文段累澡,就盡快的交付給結(jié)束應(yīng)用進程梦抢,而不是等整個緩存都填滿了以后再向上交付。
- 復(fù)位RST(1位):當(dāng)RST=1時愧哟,表明TCP連接中出現(xiàn)嚴重差錯(如主機崩潰或者其他原因)奥吩,必須釋放連接,然后再重新建立連接翅雏。RST=1時還用來拒絕一個非法的報文或者拒絕打開一個連接圈驼。
- 同步SYN(1位):建立連接時用來同步序號。當(dāng)SYN=1而ACK=0時望几,表明這是一個連接請求報文段绩脆。若對方同意建立連接,則在響應(yīng)報文段中使SYN=1和ACK=1.
- 終止FIN(1位):用來釋放連接橄抹。當(dāng)FIN=1時靴迫,表明此報文段的發(fā)送方的數(shù)據(jù)已經(jīng)發(fā)送完畢,并要求釋放連接楼誓、
- 窗口(16位):指的接收窗口玉锌。窗口指告訴對方:從本報文段的首部的確認號算起,接收方允許對方發(fā)送的數(shù)據(jù)量疟羹。之所以有這個限制主守,是因為接收方的數(shù)據(jù)緩存空間是有限的¢冢總之参淫,窗口指作為接收方讓發(fā)送方設(shè)置其發(fā)送窗口的依據(jù)
- 檢驗和(16位):檢驗和字段的檢驗范圍包括首部和數(shù)據(jù)兩個部分。IP首部中的檢驗和只檢驗頭部
- 緊急指針(16位):當(dāng)URG=1時才有效愧杯。指出報文段中的緊急數(shù)據(jù)的字節(jié)數(shù)涎才。
3.2 TCP header可變部分
長度可變,最長可達到40個字節(jié)力九。當(dāng)沒有使用選項時耍铜,TCP首部首部長度是20個字節(jié)邑闺。
TCP最初只規(guī)定了一種選項,即報文段最大長度MSS(maximum Segment Size)棕兼。MSS: 指數(shù)據(jù)部分的最大長度陡舅,數(shù)據(jù)字段加上TCP的首部才是整個TCP報文段。還記得文章開頭部分提到MTU嗎伴挚?因為數(shù)據(jù)鏈路層有MTU的限制蹭沛。就會導(dǎo)致在IP層,如果數(shù)據(jù)報對較大章鲤,就會分片。那IP分片就分片唄咆贬,為什么TCP需要MSS用來現(xiàn)在最大報文長度呢败徊?因為TCP層要保證數(shù)據(jù)的可靠性,如果數(shù)據(jù)丟失掏缎,TCP層會重新傳送數(shù)據(jù)皱蹦。如果發(fā)送方數(shù)據(jù)在IP層分片,比如分成3片眷蜈,接收方需要在IP層把3個分片組裝好再交付TCP層沪哺。如果TCP層發(fā)現(xiàn)數(shù)據(jù)少了一個分片,那么3個分片都重傳酌儒,浪費了網(wǎng)絡(luò)的資源辜妓。但是如果在TCP層分片,只要重傳丟失的那個分組就好了忌怎,這就是TCP建立連接時候需要協(xié)商MSS字段值的原因
下面我們結(jié)合抓包看看MSS字段對數(shù)據(jù)傳輸?shù)挠绊懀?br>
圖中Length表示物理層最終發(fā)送出的frame的數(shù)據(jù)大小
- 綠色框表示TCP建立連接(3次握手):請求建立連接請求中的MSS=1460籍滴。確認建立連接中MSS=1440。那么在以后的TCP連接中的報文段數(shù)據(jù)部分的最大長度就是min{1460, 1440}=1440 Bytes榴啸。
- 藍色框表HTTP請求與響應(yīng):具體步驟已在圖中描述孽惰,重點看標(biāo)紅的部分,wireshark出現(xiàn)[TCP sgment of a reassembled PDU]的描述鸥印,表示這里出現(xiàn)分段了勋功。由于百度的http響應(yīng)報文長度超過MTU,所以造成了這里的數(shù)據(jù)段分段了库说。詳細看下這條記錄
TCP數(shù)據(jù)部分的長度確實是1440 bytes狂鞋,與上面的MSS分析一致。
這里還有一個問題璃弄,HTTP的響應(yīng)報文分成了3個報文段要销。那么接受方是這么知道這3個報文段表示一個完整的信息呢?3個報文段是順序又是怎樣的夏块?
我先HTTP請求這條記錄:
其中疏咐,發(fā)送方Seq=1, Len=77纤掸。那么響應(yīng)放下次發(fā)送過來的數(shù)據(jù)段中
確認號
字段的值為1+77 = 78;發(fā)送方的確認號
字段=1浑塞。那么響應(yīng)方下次發(fā)送來的序號
字段值就是1借跪。 下面開始檢驗。響應(yīng)報文段一個分段如下:
響應(yīng)報文段二個分段如下:
響應(yīng)報文段三個分段如下:
我們看到酌壕,三個分段的確認號字段值都是78, 序號字段分別為1(ACK報文段如果不攜帶數(shù)據(jù)掏愁,則不消耗序列號,所以一下個序列號任然為1)卵牍,1果港,1441。所以當(dāng)發(fā)現(xiàn)接受到是數(shù)據(jù)段中確認號字段數(shù)值一樣糊昙,就表明這是一個大段數(shù)據(jù)的分段辛掠。序號的大小表明循序。所以回到我們剛剛的問題释牺,就知道數(shù)據(jù)段是被分成了3個段萝衩,且根據(jù)序號可以再組合會原始的數(shù)據(jù)大段。
3.3 TCP建立連接(3次握手)
TCP三次握手示意圖如下
實際上三次握手指的建立連接需要發(fā)送三個數(shù)據(jù)包没咙。TCP的三次握手的實際意義是確認雙方建立連接的初始序號猩谊。
這里有一個問題請大家思考,如果只是為了確認初始序號祭刚。那么兩次握手就夠了牌捷,第一次客戶端將自已的初始序列號告訴服務(wù)端,第二次服務(wù)端確認客戶端的序列號涡驮,并告訴客戶端自已的序號宜鸯。那么就可以建立連接了。那么為什么還需要第三次的確認呢淋袖?
主要防止已經(jīng)失效的連接請求報文突然又傳送到了服務(wù)器,從而產(chǎn)生錯誤陌凳。
如果使用的是兩次握手建立連接,假設(shè)有這樣一種場景,客戶端發(fā)送了第一個請求連接并且沒有丟失,只是因為在網(wǎng)絡(luò)結(jié)點中滯留的時間太長了,由于TCP的客戶端遲遲沒有收到確認報文,以為服務(wù)器沒有收到,此時重新向服務(wù)器發(fā)送這條報文撒会,此后客戶端和服務(wù)器經(jīng)過兩次握手完成連接怔檩,傳輸數(shù)據(jù),然后關(guān)閉連接介袜。此時此前滯留的那一次請求連接,網(wǎng)絡(luò)通暢了到達了服務(wù)器,這個報文本該是失效的娄琉,但是杏慰,兩次握手的機制將會讓客戶端和服務(wù)器再次建立連接朝扼,這將導(dǎo)致不必要的錯誤和資源的浪費。
如果采用的是三次握手搪柑,就算是那一次失效的報文傳送過來了潮针,服務(wù)端接受到了那條失效報文并且回復(fù)了確認報文,但是客戶端是知道自已并沒有發(fā)出建立連接的請求瓣戚,所以不會再次發(fā)出確認。由于服務(wù)器收不到確認仓技,就知道客戶端并沒有請求連接羡亩。
wireshark抓包分析如下:
- 第一次握手(SYN=1)
其中序號seq=0摩疑,wireshark顯示的相對序號,真實的序號如圖中箭頭所示8f 6c c8 9c
- 第二次握手(SYN=1及志,ACK=1)
- 第三次握手(ACK=1)
注意當(dāng)ACK報文段中數(shù)據(jù)部分長度為0時,是不消耗序號的寨腔。即下一次的序號和上一次的序號是一樣的
3.4 TCP釋放連接(4次揮手)
TCP四次揮手示意圖如下
示意圖已經(jīng)描述的非常清楚了速侈,不再贅述。這里重點說一下為什么客戶端發(fā)送完最后一個ACK報文段后要等2MSL(TIME_WAIT timer, 時間等待計時器)迫卢。一個MSL等于2分鐘倚搬。但是現(xiàn)在網(wǎng)絡(luò)條件比較好,2分鐘通常太長了乾蛤,所以允許TCP不同實現(xiàn)使用更小的MSL值每界。關(guān)于為什么要等2MSL,原因有兩個
- 保證客戶端發(fā)送的最后一個ACK報文能夠到達服務(wù)器家卖,因為這個ACK報文可能丟失眨层,站在服務(wù)器的角度看來,我已經(jīng)發(fā)送了FIN+ACK報文請求斷開了上荡,客戶端還沒有給我回應(yīng)趴樱,應(yīng)該是我發(fā)送的請求斷開報文它沒有收到馒闷,于是服務(wù)器又會重新發(fā)送一次,而客戶端就能在這個2MSL時間段內(nèi)收到這個重傳的報文叁征,接著給出回應(yīng)報文纳账,并且會重啟2MSL計時器。
- 防止類似與“三次握手”中提到了的“已經(jīng)失效的連接請求報文段”出現(xiàn)在本連接中捺疼∈璩妫客戶端發(fā)送完最后一個確認報文后,在這個2MSL時間中啤呼,就可以使本連接持續(xù)的時間內(nèi)所產(chǎn)生的所有報文段都從網(wǎng)絡(luò)中消失卧秘。這樣新的連接中不會出現(xiàn)舊連接的請求報文。
如果已經(jīng)建立了連接媳友,但是客戶端掛了斯议,這么辦?
這種情況如果服務(wù)端一直保持這個連接醇锚,那么白白浪費了網(wǎng)絡(luò)資源哼御,所以TCP設(shè)置有一個保活計時器(keepalive timer)焊唬。注意tcp的keepalive和http的keepalive是不同的恋昼。TCP的保活計時器赶促,當(dāng)服務(wù)端兩個小時沒有收到客戶端的數(shù)據(jù)液肌,就會發(fā)送一個探測報文段,以后每隔75秒發(fā)送一次鸥滨。如果一連發(fā)送10個探測報文段嗦哆,客戶端都沒有響應(yīng),服務(wù)端就會認為客戶端出了故障婿滓,接著就會關(guān)閉這個連接老速。
3.5 TCP的可靠性、流量控制凸主、擁塞控制
TCP的可靠性和流量控制都是通過窗口滑動機制實現(xiàn)的橘券。
實際上沒有窗口滑動TCP協(xié)議也是能夠保證數(shù)據(jù)的可靠性的。TCP報文段中有確認號字段卿吐,如果沒有收到確認旁舰,那么發(fā)送方就認為數(shù)據(jù)丟失,一直重傳數(shù)據(jù)知道收到確認嗡官。但是這種一問一答的方式效率很低箭窜。所以就有了窗口滑動機制。還記得TCP頭中的窗口
字段嗎衍腥?就是用來實現(xiàn)窗口滑動機制的绽快。只要在窗口允許的范圍內(nèi)芥丧,就可以一直發(fā)送數(shù)據(jù)。
窗口滑動機制作用:防止發(fā)送數(shù)據(jù)發(fā)送太快坊罢,接收方來不及處理
關(guān)于擁塞控制续担,注意與流量控制的區(qū)別
流量控制是作用于接收者的,它是控制發(fā)送者的發(fā)送速度從而使接收者來得及接收活孩,防止丟失數(shù)據(jù)包的物遇。
擁塞控制 擁塞控制是作用于網(wǎng)絡(luò)的,它是防止過多的數(shù)據(jù)注入到網(wǎng)絡(luò)中憾儒,避免出現(xiàn)網(wǎng)絡(luò)負載過大的情況
在擁塞控制中询兴,發(fā)送方維持一個叫做擁塞窗口cwnd(congestion window)的狀態(tài)變量。擁塞窗口的大小取決于網(wǎng)絡(luò)的擁塞程度起趾,并且動態(tài)地在變化诗舰。
發(fā)送窗口取擁塞窗口和接收端窗口的最小值,避免發(fā)送接收端窗口還大的數(shù)據(jù)训裆。
擁塞控制使用了兩個重要的算法: 慢啟動算法眶根, 擁塞避免算法。
- 慢啟動算法的思路是边琉,不要一開始就發(fā)送大量的數(shù)據(jù)属百,先試探一下網(wǎng)絡(luò)的擁塞程度,也就是說由小到大逐漸增加擁塞窗口的大小变姨。慢算法中族扰,每個傳輸輪次后將 cwnd 加倍。
- 擁塞避免算法也是逐漸的增大 cwnd 的大小定欧,只是采用的是線性增長 而不是像慢啟動算法那樣的指數(shù)增長渔呵。
四、HTTP協(xié)議(RFC 1495 2068 7540)
HTTP協(xié)議報文分為請求報文和響應(yīng)報文砍鸠。
4.1 請求報文
4.2 響應(yīng)報文
HTTP請求報文和響應(yīng)報文都是由三個部分組成扩氢。兩種報文格式的區(qū)別就是開始行不同。
- 開始行:用于區(qū)分是請求報文還是響應(yīng)報文睦番。在請求報文中開始行叫請求行类茂,在響應(yīng)報文中叫狀態(tài)行耍属。
- 首部行:用來說明瀏覽器托嚣、服務(wù)器或者報文主體的一些信息。注意格式為key:value
- 實體主體: 在請求報文中一般不用這個字段厚骗,在響應(yīng)報文中也可能沒有這個字段示启。
請求方法:
HTTP協(xié)議的請求方法有GET、POST(更新领舰、創(chuàng)建)夫嗓、HEAD迟螺、PUT(創(chuàng)建)、DELETE舍咖、OPTIONS矩父、TRACE、CONNECT排霉。
響應(yīng)狀態(tài)碼:
狀態(tài)代碼由服務(wù)器發(fā)出窍株,以響應(yīng)客戶端對服務(wù)器的請求。
1xx(信息):收到請求攻柠,繼續(xù)處理
2xx(成功):請求已成功接收球订,理解和接受
3xx(重定向):需要采取進一步措施才能完成請求
4xx(客戶端錯誤):請求包含錯誤的語法或無法滿足
5xx(服務(wù)器錯誤):服務(wù)器無法滿足明顯有效的請求
參考文獻
- [計算機網(wǎng)絡(luò)]第五版,謝希仁
- rfc 文檔查詢