版權聲明:本文為作者原創文章,可以隨意轉載,但必須在明確位置表明出處!!!
之前有一篇文章介紹了http協議「初識http協議」, http協議協議是基於tcp協議的,所以作者覺得有必要針對tcp協議做一個介紹,希望各位讀者能夠靜下心來認真閱讀,也可以自己去看看TCP/IP協議詳解這本書,一定要讓自己成為那20%的人。
TCP(Transmission Control Protocol 傳輸控制協議)是一種面向連接的、可靠的、基於字節流的傳輸層通信協議,對TCP協議的文章網上已經很成熟了,今天我只是想總結一下知識,加深印象,所謂好記心不如爛筆頭麻。
TCP/IP分層結構
TCP/IP協議棧主要分為4層:應用層,傳輸層,網絡層,數據鏈路層
-
應用層
應用層負責處理特定的應用程序細節,像遠程登陸,FTP傳輸,SMTP郵件傳輸,SNMP簡單網絡管理。
-
傳輸層
運輸層主要提供兩台主機之間端到端的通信,在TCP/IP協議族中,TCP和UPD是兩種截然不同的傳輸協議,TCP(傳輸控制協議)為主機之間提供可靠傳輸,它把從應用層得到的數據分成適當的數據包交給下面的(IP)網絡層,確定接收到的分組,設置發送最后確認分組的超時時鍾等,因運輸層提供了高可靠性的端到端的通信,應用層就不需要再去關注這些細節,而UDP(用戶數據協議)提供的是不可能性的傳輸,它只負責從一台主機發送到另一台主機,並不保證此數據一定到達另一端主機,任何必需的可靠性必須由應用層來提供。
-
網絡層
網絡層主要處理分組在網絡中的活動,網絡層協議包涵IP,ICMP,IGMP協議。
-
鏈路層
鏈路層組要包涵網卡驅動程序,它處理和電纜或者其它傳輸介質的物理接口細節。鏈路層的主要目的有三個
-
為IP模塊接收和發送IP數據報
-
為ARP模塊發送ARP請求和接收ARP應答
-
為RARP模塊接收RARP應答和發送RARP請求
所謂的協議就是通信雙方都需要遵守的規則,這樣才能明白對方要表達什么,就像兩個人打電話一樣,A說的是重慶話,B說的是廣東話,這兩人打電話肯定不知道對方說的是什么,這就叫他們沒有遵守協議,若是都讓他們說普通話這樣倆兒人就都能聽懂對方說的是什么意識了,普通話這里就相當於協議大家都要遵守。下面我將結合Wireshark抓包工具來分析TCP/IP協議
封裝
數據進入協議棧的封裝過程
當經過以太網層的封裝后,就要通過網線或者其它傳輸介質把此封裝好的數據報文發送到另一端去,另一段收到數據報后最先接觸的是以太網層也就是我們的數據鏈路層協議,該層協議復制把以太網首部解析掉,讓后把解析后的數據報上送到IP層,IP層把IP首部解析掉,然后上傳到TCP層,依次類推每層協議解析其首部並判斷其首部中的協議標識以確定接收數據的上層協議,然后上送到他的上一層。這就是封層結構的好處之一,每層協議只做自己的事,不是自己的事就交給別人去做。
TCP報文格式
Wireshark的抓包結果
原端口/目的端口(16bit):
我們都知道網絡之前的通信是不通主機之間的通信,就windows系統而言通過查看任務管理器我們可以知道一台主機有許多進程,當我們發送數據時怎么知道要發送到對方主機那個進程里呢,所以這就是端口號的作用,在TCP報文中包涵了源端口/目的端口,源端口標識了發送進程,目的端口標識了接收方進程。在此報文中我們的源端口號是0x8572 = 34162, 目的端口是0x01bb = 443如下圖所示
序列號(32bit)
Sequence Number這個是發送序列號,用來標識從源端向目的端發送的數據字節流,它表示在這個報文端中的第一個數據字節的順序號,系列好是32位的無符號類型,序號表達達到2^32 - 1后又從0開始, 當建立一個新的連接時,SYN標志為1,系列號將由主機隨機選擇一個順序號ISN(Initial Sequence Number)。此報文中的序列號是0x9e546d6b早已超過了2^32 - 1 所以這里的序列號為0,如下圖
確認號(32bit)
Acknowledgment Number它包涵了發送確認一端所期望收到的下一個順序號。因此確認序列號應當是上次成功接收到數據的順序號加1。只有ACK標志為1時確認序號字段才有效。TCP為應用層提供全雙工服務,這意味着數據能在兩個方向上獨立的進行傳輸,因此連接的兩斷必須要保證每個方向上的傳輸數據順序。
偏移(4bit)
這里的偏移實際指的是TCP首部的長度,它用來表明TCP首部中32bit字的數目,通過它可以知道一個TCP包它的用戶數據從哪里開始,這個字段占4bit,若此字段的值為1000,則說明TCP首部的長度是8 * 4 = 32字節,所以TCP首部的最大長度是該字段的值為1111 = 15, 15 * 4 =60字節。此報文我們的偏移量在0x80中,又因它占4bit,0x80等於二進制的1000 0000 所以我們的偏移量是 1000 = 8,所以我們的TCP報文頭為8 * 4 = 32字節。
Reserved(6bit)
目前沒有使用,它的值都為0
標志(6bit)
在TCP首部中有6個標志比特,他們中的多個可同時被置為1
-
URG(Urgent Pointer Field Significant):緊急指針標志,用來保證TCP連接不被中斷,並且督促中間設備盡快處理這些數據
-
ACK(Acknowledgement Field Signigicant):確認號字段,該字段為1時表示應答字段有效,即TCP應答號將包含在TCP報文中。
-
PSH(Push Function): 推送功能,所謂推送功能指的是接收端在接收到數據后立即推送給應用程序,而不是在緩沖區中排隊。
-
RST(Reset the connection): 重置連接,不過一搬表示斷開一個連接,如下圖,主機192.168.3.27 訪問主機211.150.84.8;但主機84.8並沒有監聽對於端口,這時它會向主機3.27發送一個RST位置的TCP包斷開連接。
-
SYN(Synchronize sequence numbers):同步序列號,用來發起一個連接請求
-
FIN(No more data from sender):表示發送端發送任務已經完成(既斷開連接)
窗口大小(16bit)
表示源主機最大能接收多少字節。
校驗和(16bit)
包含TCP首部和TCP數據段,這是一個強制性的字段,一定是由發送端計算和存儲,由接收端進行驗證
緊急指針(16bit)
只有當URG標志置為1時該字段才有效,緊急指針是一個正的偏移量,和序號字段中的值相加表示緊急數據最后一個字節的序號。TCP的緊急方式是發送端向另一段發送緊急數據的一種方式。
TCP選項
至少1個字節的可變長字段,標識哪個選項有效。Kind=0:選項表結束, Kind=1:無操作, Kind=2:最大報文段長度,Kind=3:窗口擴大因子, Kind=8:時間戳。
TCP的三次握手和四次揮手
整個過程如下圖所示
TCP的三次握手
TCP的三次握手過程如下圖所示,我們通過數據包來分析一下握手過程是不是和圖中所畫一致。
第一次握手
主機192.168.3.27向主機111.13.100.91發起連接請求,可以看在這時的SYN被置為1了,序列號Seq = 0,如下圖
第二次握手
主機111.13.100.91應答主機192.168.3.27,可以看到這個時候的應答包含了SYN,ACK,ACK = Seq + 1 = 1, 這里的Seq是第一次握手發起請求的Seq值,並不是下圖報文中紅框表示的Seq值。
第三次握手
主機192.168.3.27應答主機111.13.100.91,可以看到這個時候的應答包是ACK, ACK = Seq + 1 = 1,這里的Seq是第二次握手主機111.13.100.91產生的序列值
在回頭看看我們的svr4.1037主機和bsdi.discard之前的連接建立是不是和我們的報文分析的一致,第一次握手 SYN Seq = 1415531521; 第二次握手 SYN ack = 1415531521 + 1 = 1415531522 Seq = 1823083521;第三次握手 ack = 1823083521 + 1 = 1823083522;到這里就可以看出此過程和我們的報文分析是一致的。
可以看到三次握手后確定了雙方包的序列號,最大接收數據的大小以及MSS(Maximum Segment Size)最大分片大小 MSS = MTU - IP頭部長度 - TCP頭部長度,MTU最大傳輸單元一班為1500字節,若TCP/IP報文都不帶選項時MSS = 1500 - 20 - 20 = 1460,MSS的意思是最大分片大小,這里若是1460的話,那么若是應用程序發送大於1460個字節那么超過1460個字節數會分片為下一個包,下圖是應用層發送4096個字節。
由於數據大小是4096個字節,所以用了三次進行傳遞(1448 + 1448 + 1200)。細心的人會問為什么每次傳送的最大數據大小不是1460個字節呢?因為這里的TCP攜帶可選項,TCP頭長度 = 20 + 12(可選選項大小) = 32字節。 這樣能傳輸的最大數據為:1500 - 20 - 32 = 1448個字節。
TCP四次揮手
第一次揮手
將設客戶端首先發起斷開連接,那么客戶端回想服務端發送FIN置為1的TCP包,請求斷開連接,意思就是我要斷開和你的連接了,但是如果你還有數據沒有發送完給我你不必立即關閉連接。
第二次揮手
服務端收到客戶端的斷開連接請求立即響應一個ACK報文,意思是告訴客戶端你發起的斷開連接請求我已經收到了,但是我還沒有准備好,你在等一會,這個時候服務器端可能還有數據要發送給客戶端,也可能正在准備釋放資源。這個時候客戶端進入FIN_WAIT狀態,繼續等待服務端的FIN報文。
第三次揮手
服務端確認已經發往客戶端的數據已經發送完成,則向客戶端發送FIN報文,告訴客戶端我已准備好關閉連接了。
第四次揮手
客戶端收到服務端的FIN報文后就知道可以關閉連接了,當時它還是不確定,怕服務端還是不知道我要關閉連接了,所以發送一個ACK包后進入TIME_WAIT狀態,如果服務端沒有收到ACK那么服務端則可以發起重傳,如果收到了ACK報文,客戶端等待2MSL后已然沒有收到回復,則證明服務端已經正常關閉了,那我也就可以關閉連接了。