1. 程式人生 > >TCP傳送資料流程詳解

TCP傳送資料流程詳解

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

B/S通訊簡述

整個計算機網路的實現體現為協議的實現,TCP/IP協議是Internet的核心協議,HTTP協議是比TCP更高層次的應用層協議。

HTTPHyperText Transfer Protocol

,超文字傳輸協議)是網際網路上應用最為廣泛的一種網路協議。所有的WWW檔案都必須遵守這個標準。設計HTTP的初衷是為了提供一種釋出和接收HTML頁面的方法。

瀏覽器(Web Browser)負責與伺服器建立連線下載網頁(包括資原始檔及JS指令碼檔案)到本地,並最終渲染出頁面。JS指令碼檔案執行在客戶端,負責客戶端一些行為響應或預處理,例如提交表單前的資料校驗、滑鼠事件處理等互動。由此可見,瀏覽器(Browser)一方面充當了C/S通訊架構中C角色,另一方面它是HTML/JavaScript解析渲染引擎Analyze Render Engine)。

在瀏覽器位址列敲入“http://www.baidu.com/”,按下回車鍵,瀏覽器中呈現出百度首頁。這樣一種情景我們再熟悉不過,本文通過wireshark抓取這一過程的TCP/IP資料包,結合TCP協議分析HTTP通訊的基本流程。

MTU和MSS

本文用到的抓包工具為wireshark,它的前身是赫赫有名的Ethereal。wireshark乙太網幀的封包格式為:

Frame = Ethernet Header + IP Header + TCP Header + TCP Segment Data

(1)Ethernet Header =14 Byte = Dst Physical Address(6 Byte)+ Src Physical Address(6 Byte)+ Type(2 Byte),乙太網幀頭以下稱之為資料幀。

(2)IP Header =20 Byte(without options field),資料在IP層稱為Datagram,分片稱為Fragment。

(3)TCP Header = 20 Byte(without options field),資料在TCP層稱為Stream,分段稱為Segment(UDP中稱為Message)。

(4)54個位元組後為TCP資料負載部分(Data Portion),即應用層使用者資料。

Ethernet Header以下的IP資料報最大傳輸單位為MTU(Maximum Transmission Unit,Effect of short board),對於大多數使用乙太網的區域網來說,MTU=1500。

TCP資料包每次能夠傳輸的最大資料分段為MSS為了達到最佳的傳輸效能,在建立TCP連線時雙方協商MSS值,雙方提供的MSS值的最小值為這次連線的最大MSS值。MSS往往基於MTU計算出來,通常MSS=MTU-sizeof(IP Header)-sizeof(TCP Header)=1500-20-20=1460。

這樣,資料經過本地TCP層分段後,交給本地IP層,在本地IP層就不需要分片了。但是在下一跳路由(Next Hop)的鄰居路由器上可能發生IP分片!因為路由器的網絡卡的MTU可能小於需要轉發的IP資料報的大小。這時候,在路由器上可能發生兩種情況:

(1).如果源傳送端設定了這個IP資料包可以分片(May Fragment,DF=0),路由器將IP資料報分片後轉發。

(2).如果源傳送端設定了這個IP資料報不可以分片(Don’t Fragment,DF=1),路由器將IP資料報丟棄,併發送ICMP分片錯誤訊息給源傳送端。

關於MTU的探測,參考《Path MTU discovery》。我們可以通過基於ICMP協議的ping命令來探測從本機出發到目標機器上路由上的MTU,詳見下文。

TCP和UDP

在基於傳輸層(TCP/UDP)的應用開發中,為了最後的程式優化,應避免端到端的任何一個節點上出現IP分片。TCP的MSS協商機制加上序列號確認機制,基本上能夠保證資料的可靠傳輸。

UDP協議在IP協議的基礎上,只增加了傳輸層的埠(Source Port+Destination Port)、UDP資料包長(Length = Header+Data)以及檢驗和(Checksum)。因此,基於UDP開發應用程式時,資料包需要結合IP分片情況考慮。對於以太區域網,往往取UDP資料包長Length<=MTU-sizeof(IP Header)=1480,故UDP資料負載量小於或等於1472(Length-UDP Header);對於公網,ipv4最小MTU為576,UDP資料負載量小於或等於536。

“向外”NAT在內網和公網之間提供了一個“不對稱”橋的對映。“向外”NAT在預設情況下只允許向外的session穿越NAT:從外向內的的資料包都會被丟棄掉,除非NAT裝置事先已經定義了這些從外向內的資料包是已存在的內網session的一部分。對於一方在LAN,一方在WAN的UDP通訊,鑑於UDP通訊不事先建立虛擬鏈路,NAT後面的LAN通訊方需先發送訊息給WAN通訊方以洞穿NAT,然後才可以進行雙向通訊,這即是常提到的“UDP打洞(Hole Punching)”問題。

TCP連線百度過程解析

下文對百度的完整抓包建立在不使用快取的基礎上。如若主機存有百度站點的cookie和離線快取(Offline Cache),則不會再請求位址列圖示favicon.ico;請求/js/bdsug.js?v=1.0.3.0可能迴應“HTTP/1.1 304 Not Modified”。可在瀏覽器開啟百度首頁後,Ctrl+F5強制重新整理,不使用快取,也可參考《瀏覽器清除快取方法》。

以下為訪問百度過程,wireshark抓包資料。對於直接通過Ethernet聯網的機器,Wireshark Capture Filter為"host www.baidu.com";對於通過PPP over Ethernet(PPPoE)聯網的機器,Wireshark Capture Filter為"pppoes and hostwww.baidu.com"。以下抓包示例直接通過Ethernet聯網訪問百度的過程。可點選圖片超連結下載pcap檔案,使用wireshark軟體檢視。

為方便起見,以下將客戶端(瀏覽器)簡稱為C,將伺服器(百度)簡稱為S。

 

1.TCP三次握手建立連線

“http://”標識WWW訪問協議為HTTP,根據規則,只有底層協議建立連線之後才能進行更高層協議的連線。在瀏覽器位址列輸入地址後按下回車鍵的瞬間,C建立與S(機器名為www.baidu.com,DNS解析出來的IP為220.181.6.175)的TCP 80連線(HTTP預設使用TCP 80埠)。

以下為三次握手建立TCP連線的資料包(Packet1-Packet3)。

1  192.168.89.125:5672→ 220.181.6.175:80   TCP(協議) 62(乙太網幀長)

amqp > http [SYN] Seq=0 Win=65535 Len=0 MSS=1460SACK_PERM=1

2  220.181.6.175:80→ 192.168.89.125:5672 TCP 62

http > amqp [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1460 SACK_PERM=1

3  192.168.89.125:5672→ 220.181.6.175:80   TCP 54

amqp > http [ACK] Seq=1 Ack=1 Win=65535 Len=0

三次握手建立TCP連線的流程如下:

    C(Browser)                                    S(www.baidu.com)

 1. CLOSED                                             LISTEN

 2. SYN-SENT     <SEQ=0><CTL=SYN>               SYN-RECEIVED

 3. ESTABLISHED <SEQ=0><ACK=1><CTL=SYN,ACK>  SYN-RECEIVED

 4. ESTABLISHED <SEQ=1><ACK=1><CTL=ACK>       ESTABLISHED

3-Way Handshake for Connection Synchronization

三次握手的socket層執行邏輯

S呼叫socketlisten函式進入監聽狀態;C呼叫connect函式連線S[SYN]S呼叫accept函式接受C的連線併發起與C方向上的連線:[SYN,ACK]C傳送[ACK]完成三次握手,connect函式返回;S收到C傳送的[ACK]後,accept函式返回。

關於Seq和Ack

SeqSequence Number為源端source傳送序列號AckAcknowledgment Number為目的端destination接收確認序列號。在Wireshark Display Filter中,可使用tcp.seqtcp.ack過濾。

在Packet1中,C:5672向S:80傳送SYN握手包,Seq=0(relative sequence number);在Packet2中,S:80向C:5672傳送ACK握手迴應包,Ack=1(relative sequence number),同時傳送SYN握手包,Seq=0(relative sequence number);在Packet3中,C:5672向S:80傳送ACK握手迴應包,Seq=1,Ack=1。

至此,Seq=1為C的Initial Sequence Number(ISN),後期某一時刻的Seq=ISN+累計傳送量(cumulative sent);Ack=1為C的Initial Acknowledge Number(IAN),後期某一時刻的Ack=IAN+累計接收量(cumulative received)。對於S而言,Seq和Ack情同此理。

參考:《TCP Analyze Sequence Numbers》、《Understanding TCP Sequence and Acknowledgement Numbers》

2.TCP獲取網站資料流程

連線建立後,下一步傳送(“GET / HTTP/1.1”)請求(Request)HTML頁面,這裡“/”表示S的預設首頁,“GET”為HTTP Request Method;“/”為Request-URI,這裡為相對地址;HTTP/1.1表示使用的HTTP協議版本號為1.1。

以下為HTTP GET請求資料包(Packet4)。

4  192.168.89.125:5672220.181.6.175:80 HTTP 417

GET / HTTP/1.1

HTTP GET報文長=417-54=363個位元組,其中Next sequence number: 364(relative sequence number)表示,若在規定的時間內收到S響應Ack=364,表明該報文傳送成功,可以傳送下一個報文(Seq=364);否則重傳(TCP Retransmitssion)。序列號確認機制是TCP可靠性傳輸的保障。

Shttp)收到HTTP GET報文(共363個位元組),向Camqp)傳送TCP確認報文(Packet5)。

5  220.181.6.175:80 192.168.89.125:5672 TCP 60

http > amqp [ACK] Seq=1 Ack=364 Win=6432 Len=0

這裡Seq=1,SISN,意為已傳送過SYNPacket2中,Ack=1SIAN。這裡的Ack-IAN=364-1=363表示S已經從C接收到363個位元組,即HTTP GET報文。同時,Ack=364也是S期待C傳送的下一個TCP報文序列號(上面分析的Next sequence number)

接下來,SC傳送Http Response,根據HTTP協議,先發響應頭(Response Header),再發百度首頁HTML檔案。

Http Response Header報文(Packet6)如下

6  220.181.6.175:80 192.168.89.125:5672 TCP 465

[TCP segment of a reassembled PDU]

其部分內容如下:

======================================

HTTP/1.1 200 OK

……

Content-Length: 2139

Content-Type: text/html;charset=gb2312

Content-Encoding: gzip

======================================

S響應C“GET / HTTP/1.1”請求,先發送帶[PSH]標識的411個位元組的Http Response HeaderPacket 6)。

TCP頭部[PSH]標識置位,敦促C將快取的資料推送給應用程式,即先處理Http Response Header,實際上是一種截流通知。相應Csocket呼叫sendIPPROTO_TCP選項級別設定TCP_NODELAYTRUE禁用Nagle演算法可以“保留髮送邊界”,以防粘連

儘管握手協商的MSS1460,但伺服器或者代理平衡伺服器,每次傳送過來的TCP資料最多隻有1420個位元組可以使用ping -f -l size target_name命令向指定目標target_name傳送指定位元組量的ICMP報文,其中-l size指定傳送緩衝區的大小;-f則表示在IP資料報中設定不分片DFDon’t Fragment),這樣便可探測出到目標路徑上的MTU

執行“ping -f -l 1452www.baidu.com”的結果如下:

220.181.6.18 Ping統計資訊:

   資料包:已傳送 = 4,已接收 = 4,丟失 = 0 (0%丟失)

執行“ping -f -l 1453www.baidu.com”的結果如下:

需要拆分資料包但是設定 DF

220.181.6.18 Ping統計資訊:

   資料包:已傳送 = 4,已接收 = 0,丟失 = 4 (100%丟失)

從以上ping結果可知,在不分片時,從本機出發到百度的路由上能通過的最大資料量為1452,由此推算出MTU{local,baidu}=sizeof(IP Header)+ sizeof(ICMP Header)+sizeof(ICMP Data Portion)=20+8+1452=1480

S呼叫socketsend函式傳送2139個位元組的Http Response ContentPacket 7Packet 9),在TCP層將分解為兩段(segment)後再發出去。

7  220.181.6.175:80 192.168.89.125:5672 TCP 1474

[TCP segment of a reassembled PDU]

“Content-Length: 2139”可知,HTML檔案還有2139-(1474-54)=719個位元組。但此時,C已經發送了確認報文(Packet8)

8  192.168.89.125:5672  220.181.6.175:80 TCP 54

amqp > http [ACK] Seq=364 Ack=1832 Win=65535 Len=0

Seq-ISN=364-1=363,表示C已經發出了363個位元組,上邊已經收到了S的確認。Ack-IAN=1832-1=(465-54)+(1474-54),表示C至此已經接收到S發來的1831個位元組。

接下來,C收到HTML檔案剩餘的719個位元組,報文(Packet9)如下。

9  220.181.6.175:80 192.168.89.125:5672 HTTP   773

HTTP/1.1 200 OK

至此,C收到S傳送過來的全部HTTP響應報文,即百度首頁HTML內容(text/html)

Packet6Packet7Packet9ACK都是364,這是因為這三個segment都是針對Packet4TCP響應。S將百度首頁HTML檔案(一個完整的HTTP報文)按照MSS分段提交給TCP層。Wireshark中可以看到Packet9的報文中有以下reassemble資訊:

[Reassembled TCP segments (2555 bytes): #6(411),#7(1420),#9(719)]

[Frame: 6, payload: 0-410(411 bytes)]

[Frame: 7, payload: 411-1830(1420 bytes)]

[Frame: 9, payload: 1831-2549(719 bytes)]

Camqp)接收到百度首頁的HTML檔案後,開始解析渲染。在解析過程中,發現頁面中含有百度的logo資源baidu_logo.gif,並且需要bdsug.js指令碼

<img src="http://www.baidu.com/img/baidu_logo.gif" width="270" height="129" usemap="#mp">

{d.write('<script src=http://www.baidu.com/js/bdsug.js?v=1.0.3.0><//script>')}

於是上面那個連線(C:5672)繼續向S請求logo圖示資源,報文(Packet10)如下。

10 192.168.89.125:5672  220.181.6.175:80 HTTP 492

GET /img/baidu_logo.gif HTTP/1.1

與此同時,Cjms)新建一個連線(TCP 5673)向S請求js指令碼檔案。報文(Packet11)如下。

11 192.168.89.125:5673  220.181.6.175:80 TCP 62

jms > http [SYN] Seq=0 Win=65535 Len=0 MSS=1460 SACK_PERM=1

(Packet12)Packet13、Packet14、Packet16和Packet17為對Packet10的TCP響應(它們的Ack=802),在邏輯上它們是一個完整的TCP報文。其Http Response Content為圖片檔案baidu_logo.gif。我們在Wireshark中可以看到Packet17的報文中有以下reassemble資訊:

[Reassembled TCP segments (1801 bytes): #13(312),#14(1420),#16(28) ,#17(41)]

[Frame: 13, payload: 0-311(312 bytes)]

[Frame: 14, payload: 312-1731(1420 bytes)]

[Frame: 16, payload: 1732-1759(28 bytes)]

[Frame: 17, payload: 1760-1800(41 bytes)]

Packet11-Packet19-Packet20完成新連線的三次握手。然後,C(jms)傳送“GET /js/bdsug.js?v=1.0.3.0 HTTP/1.1”報文(Packet21),以獲取bdsug.js指令碼檔案。

21 192.168.89.125:5673  220.181.6.175:80 HTTP 465

GET /js/bdsug.js?v=1.0.3.0 HTTP/1.1

(Packet22)Packet23、Packet24、Packet26和Packet27為對Packet21的TCP響應(它們的Ack=412),在邏輯上它們是一個完整的TCP報文。其Http Response Content為指令碼檔案bdsug.js。我們在Wireshark中可以看到Packet27的報文中有以下reassemble資訊:

[Reassembled TCP segments (3897 bytes): #23(310),#24(1420),#26(1420) ,#27(747)]

[Frame: 23, payload: 0-309(310 bytes)]

[Frame: 24, payload: 310-1729(1420 bytes)]

[Frame: 26, payload: 1730-3149(1420 bytes)]

[Frame: 27, payload: 3150-3896(747 bytes)]

通常,瀏覽器會自動的搜尋網站的根目錄,只要它發現了favicon.ico這個檔案,就把它下載下來作為網站位址列圖示。於是,Camqp)還將發起GET /favicon.ico HTTP/1.1請求網站位址列圖示,見報文Packet29。

3.TCP四次揮手關閉連線

Packet28確認收到了完整的japplication/javascript檔案後,鏈路1(本地埠5673)使命結束,S關閉該鏈路,進入四次揮手關閉雙向連線。

(Packet30)Packet31和Packet32為對Packet29的TCP響應(它們的Ack=1201)。Packet33確認收到了完整的image/x-icon檔案後,鏈路2(本地埠5672)使命結束,S關閉該鏈路,進入四次揮手關閉雙向連線。

   為什麼握手是三次,而揮手是四次呢?這是因為握手時,伺服器往往在答應建立連線時,也建立與客戶端的連線,即所謂的雙向連線。所以,在Packet2中,伺服器將ACKSYN打包發出。揮手,即關閉連線,往往只是表明揮手方不再發送資料(無資料可發),而接收通道依然有效(依然可以接受資料)。當對方也揮手時,則表明對方也無資料可發了,此時雙向連線真正關閉。

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述