目錄
一、何為TCP協議
二、對于TCP協議來說,UDP它與UDP協議不同之處在于:
三、TCP首部各個欄位的作用分別是什么
四、TCP的連接建立
1、關于TCP連接的建立,首先要清楚TCP的連接特點
2、TCP連接建立中的三次握手(先上圖:)
3、詳細程序
4、關于三次握手
5、為什么不用兩次握手呢
五、TCP連接的釋放
1、大致程序示意圖
2、程序詳細說明
3、為什么客戶端最后要等待 2*MSL時間呢
4、保活計時器
一、何為TCP協議
TCP協議,大名叫:傳輸控制協議,看名字就知道,它是負責對資料報文的傳輸進行一定控制作用的,簡單看看它作業的地方:

由圖可知,它和它的好哥們UDP作業在運輸層(也稱傳輸層),這一層當然是至關重要的,所謂運輸層,它主要是提供端到端的介面,為它上面的應用層提供通信服務,屬于是面向通信的最高部分,當我們網路中兩臺邊緣主機要進行通信時,必須就要用到TCP/IP協議堆疊的運輸層,關于傳輸層的知識其它文章會詳細講解,這里就不再過多的贅述了,
二、對于TCP協議來說,UDP它與UDP協議不同之處在于:
1、TCP提供的是面向連接的服務,
何為面向連接的服務?面向連接的服務與無連接的服務區別就在于進行通信前是否需要提前建立好連接,對于TCP協議來說,既然它屬于是面向連接的服務,所以使用TCP協議進行通信前,就必須要事先建立好連接,在傳輸完成之后,還要釋放所建立的連接,這就好比應用行程之間的通信好像是在“打電話”,通話之前需要先撥號,建立通話連接;通話結束后,掛斷電話,所連接的通信鏈路就被斷開,
2、提供的是全雙工通信,
全雙工通信,就是指通信的任意一端既可以接收資料,也可以發送資料,且允許同時進行,這一點是十分重要的,就好比我們打電話,要是只允許電話兩頭的人都只能聽完再說,或者說完再聽,這豈不是很難受……所以TCP協議就很好的滿足了這一點,它在建立連接的兩端都設定有發送快取和接收快取,作用就是臨時存放雙向通信的資料,接收端所受到的資料都要先放在接收快取,所以上層應用行程也是對快取中的資料進行讀取,但是設定快取的好處并不止這一點,可以思考還有什么作用?
3、面向位元組流,
“位元組”都能理解,“流”是啥子?所謂“流”,就是指流入到行程或行程流出的位元組序列,對于我們的TCP協議來說,應用行程給到它的資料是一塊一塊的,但是我TCP只負責百分百將所有資料完好的送到對面行程,并不會管資料到底有幾塊,而是把所有資料看成一連串的無結構的位元組流,然后給每個位元組打上序列號,再送走,
4、提供可靠的交付,
可靠的交付,是TCP相對于UDP協議來說,最大的一個優勢,所謂可靠的交付,就是通過TCP協議控制的資料報文傳輸,整個程序是無差錯、不丟失、不重復的、并且按序到達的,
TCP與UDP的其它不同之處見下圖:
既然我們看到TCP相對于UDP的優點這么多,那么都是怎樣實作的呢?實際上,TCP協議的全部功能,都體現在它的首部各個欄位的作用上,所以接下來就來研究TCP報文的首部欄位是怎么回事,
注意看這是UDP的首部報文格式:

再對比TCP的首部報文格式:

可以明顯看出,TCP協議的首部報文明顯比UDP協議欄位格式要復雜得多,這也正是為什么TCP協議能夠做到UDP協議做不到的很多功能,
三、TCP首部各個欄位的作用分別是什么
1、源埠和目的埠:這兩個欄位分別占了2個位元組,顧名思義,就是標記了報文發送方以及接收方的這條TCP通信埠,
2、序號:序號欄位占4個位元組,因為TCP是面向位元組流的,所以在一個TCP連接中傳送的位元組流中的每一個位元組都要按順序編號,整個要傳送的位元組流的起始序號必須在連接建立時設定,且首部中的序號欄位值是指的是本報文段所發送的資料的第一個位元組的序號,比如說一段序列號為100的報文,它一次傳輸200位元組的資料,則它的下一次報文的序號就應該等于400,
3、確認號:同樣也是占了4個位元組,確認號顧名思義也就是對收到的報文進確認,它主要是讓通信對方知道自己對哪一個報文進行的確認,所以通過序號來區別,但是它的數值并不是確認的那段報文的序列號,而是回傳的是期望下一次收到的報文的第一個位元組的序號,挺起來不好理解,比如發送方發送100位元組的資料給接收方,第一個位元組序號等于200,那么接收方回給發送方的報文中,確認號就等于發送方下一次傳送100位元組的第一個位元組的序號,即301,
4、資料偏移:這個欄位只占了1/2個位元組,即4位,它指明了TCP報文段的資料起始處到TCP報文段的起始處的距離,實際上就是TCP報文段的首部長度,由于首部中還有長度不確定的選項欄位,因此資料偏移欄位是必要的,但應注意,“資料偏移”的單位是32位字(即以4位元組的字為計算單位),由于4位二進制數能表示的最大十進制數字是15,因此資料偏移的最大值是60位元組,這也是TCP首部的最大位元組(即選項長度不能超過40位元組),
5、保留:保留欄位只占6位,通常置為0,留作以后使用,
然后就是6個控制位,用于標識該報文段的一些性質
6、URG:緊急URG(URGent),當URG等于1的時候,僅表明緊急指標欄位此時有效,它告訴系統此報文段中有緊急資料,應盡快發送(相當于高優先級的資料),而不要按原來的排隊順序來傳送,例如,已經發送了很長的一個程式要在遠地的主機上運行,但后來發現了一些問題,需要取消該程式的運行,因此用戶從鍵盤發出中斷命令,如果不使用緊急資料,那么這兩個字符將存盤在接收TCP的快取末尾,只有在所有的資料被處理完畢后這兩個字符才被交付接收方的應用行程,這樣做就浪費了很多時間,
當URG置為1時,發送應用行程就告訴發送方的TCP有緊急資料要傳送,于是發送方TCP就把緊急資料插入到本報文段資料的最前面,而在緊急資料后面的資料仍然是普通資料,這時要與首部中緊急指標(Urgent Pointer)欄位配合使用,
7、ACK:確認ACK(ACKnowledgment),僅當ACK等于1時確認欄位才有效,當ACK等于0時,確認號是無效的,TCP規定,在連接建立后,所以TCP通信中的報文ACK都必須置為1,
8、PSH:推送PSH(PuSH),當兩個應用行程雙方進行互動通信時,有時一段的行程希望在鍵入一個指令后馬上得對方的回應,在這種情況下,TCP就可以使用push操作,即發送方將PSH置為1,并且立即創建一個報文發送出去,接受端接收到以后,發現PSH被置為1,所以就將此報文盡快地交付給行程,而不再等待緩沖區填滿后再等行程來取資料,
盡管行程可以使用這個操作,但是很少有行程使用,
9、RST:復位RST(ReSet),當RST等于1的時候,表示TCP連接出現了嚴重差錯,此時必須釋放該條連接,然后再重新建立運輸連接,還可以將RST置為1用來拒絕一個非法的報文段或者是拒絕打開一個連接,所以它又稱為重置位或重建位,
10、SYN:同步SYN(SYNchronization),在建立連接時用于同步序列號,當SYN等于1而ACK等于0的時候,表明這是一個連接請求報文,如果對方同意建立連接,那么在回給發送方的回應報文中SYN以及ACK置為1,所以,SYN等于1就表示這是一個連接請求或者連接同意報文,
11、FIN:終止FIN(FINish),用于釋放一個連接,當FIN置為1的時候,表示發送此報文的一端資料已全部發送完畢,請求斷開運輸連接,
12、視窗:占2個位元組,視窗指的是發送本報文段的一方的接受視窗,而不是自己的發送視窗,它表明了接受方從本報文段的確認號算起,目前可以接受的發送方發送的資料量大小(以位元組為單位),這是因為接受方的快取空間是有限的,簡單來說,目的就是控制對方的發送速率,不要超過了自己的接收能力,總之,視窗值作為接收方讓發送方設定自己發送視窗大小的依據,視窗欄位值指明了接收方允許發送方發送的資料量,且這個值是動態變化的,
13、檢驗和:此欄位占2個位元組,檢驗和欄位檢驗的范圍包括首部以及資料這兩個部分,同UDP一樣,在計算檢驗和時,要在報文段前面加上12個位元組的偽首部,偽首部的格式UDP中的格式是一樣的,如下圖:


但是應該把偽首部第四個欄位的17改為6,因為TCP的協議號為6,把第五欄位中的UDP長度改為TCP長度,接受方收到此報文段后,仍要加上這個偽首部來計算校驗和,若使用ipv6,則相應的偽首部也要改變,
14、緊急指標:占了2個位元組,前面講到過,緊急指標只有當URG等于1的時候才有效,它指出的是本報文緊急資料的位元組數,而緊急資料之后就是普通資料,所以緊急指標指出了緊急資料的末尾在報文段中的位置,當所有緊急資料處理完成后,TCO就告訴應用行程恢復到正常操作,特別注意的是,當視窗值等于0的時候,緊急指標也會發揮作用,即也能發送緊急資料,
15、選項:這個欄位長度是可變的,最長的時候可以達到40個位元組,當沒有使用“選項”時,TCP首部長度只用固定20個位元組,
16、填充:這個欄位僅僅是為了使整個TCP首部長度是4位元組的整數倍,
對于選項欄位,這里再特別指出:TCP最初只規定了一種選項,即最大報文段長度MSS(Maximum Segment Szie),MSS是每一個TCP報文段中的資料欄位的最大長度,資料欄位加上TCP首部才等于整個的TCP報文段,所以MSS并不是整個TCP報文段的最大長度,而是“TCP報文段長度減去TCP首部長度”,我們知道,TCP報文段的資料部分,至少要加上40位元組的首部(TCP首部20位元組和IP首部20位元組,這里還沒有考慮首部中的可選部分)才能組裝成一個IP資料報,若選擇較小的MSS長度,網路的利用率就降低, 因此,MSS應盡可能大些,只要在IP層傳輸時不需要分片就行,然而最佳的MSS是很難確定的,在連接程序中,雙方都把自己能夠支持的MSS寫入這一欄位,以后就按照這個數值傳輸資料,兩個傳送方向可以有不同的MSS值,S若主機未填寫這一項,則MSS的默認值是536位元組長,因此,所有在互聯網上的主機都應該接受的報文段長度是536+20(固定首部長度)=556位元組,后來又增加了幾個選項如視窗擴大選項、時間戳選項等,視窗擴大選項是為了擴大視窗,我們知道,TCP首部中視窗欄位長度是16位,因此最大的視窗大小為64K位元組,雖然這對早期的網路是足夠用的,但對于包含衛星信道的網路,傳播時延和寬帶都很大,要獲得高吞吐量需要更大的視窗大小,視窗擴大選項占3位元組,其中有一個位元組表示移位值S,新的視窗值等于TCP首部中的視窗位數從16增大到(16+S),移位值允許使用的最大值是14,相當于視窗最大值增大到2^(16+14)-1=2^30-1,
時間戳選項占10位元組,其中最主要的欄位是時間戳欄位(4位元組)和時間戳回送回答欄位(4位元組),主要作用是用來計算往返時間RTT以及用于處理TCP序號超過2^32的情況,這又稱為防止序號繞回PAWS,
四、TCP的連接建立
1、關于TCP連接的建立,首先要清楚TCP的連接特點
每一條TCP的連接有兩個端點,我們習慣上稱TCP的連接雙方客戶端和服務器,但是實際上作為TCP連接的兩個端點,既不是主機、IP地址,也不是應用行程和協議埠,而是一個新名詞“套接字”,每條TCP連接的端點就叫做套接字或者插口,何為套接字?根據RFC973的定義,埠號拼接到IP地址就構成了套接字,即套接字是由IP地址+埠號組成的,
即總有: 套接字=(IP地址:埠號)
所以,兩個通信終端的套接字唯一地標識了一條TCP連接,下面即是TCP與套接字連接示意圖:

同時要注意,同一個IP地址可以有多個不同的TCP連接,同一個埠號也可以出現在多個不同TCP連接中,
2、TCP連接建立中的三次握手(先上圖:)

3、詳細程序
剛開始, 客戶端和服務器都處于 CLOSE 狀態,
此時,,客戶端向服務器主動發出連接請求,服務器被動接受連接請求,,,,,1)TCP服務器行程先創建傳輸控制塊TCB, 時刻準備接受客戶端行程的連接請求,,此時服務器就進入了 LISTEN(監聽)狀態,
2)TCP客戶端行程也是先創建傳輸控制塊TCB,,然后向服務器發出連接請求報文,此時報文首部中的同步標志位SYN=1,,同時選擇一個初始序列號 seq = x,此時,TCP客戶端行程進入了 SYN-SENT(同步已發送狀態)狀態,TCP規定, SYN報文段(SYN=1的報文段)不能攜帶資料,但需要消耗掉一個序號,
3)TCP服務器收到請求報文后, 如果同意連接,,則發出確認報文,ACK=1, SYN=1, 確認序號ack=x+1,,同時也要為自己初始化一個序列號 seq = y,此時,,TCP服務器行程進入了SYN-RCVD(同步收到)狀態,這個報文也不能攜帶資料,但是同樣要消耗一個序號,
4)TCP客戶端行程收到確認后還要向服務器給出確認,確認報文的ACK=1,確認序號是 y+1,自己的序列號是 seq=x+1,
5)此后,TCP連接建立,客戶端進入ESTABLISHED(已建立連接)狀態,當服務器收到客戶端的確認后也進入ESTABLISHED狀態,此后雙方就可以開始通信了,
4、關于三次握手
這實際上是在一次握手中交換了三次報文,并不是進行了三次握手,但是結合日常,兩個人見面時互相問好握手,上下搖晃三次,所以用“三次握手”來形容TCP連接建立是比較恰當的,
5、為什么不用兩次握手呢
實際上,看似兩次握手簡單,但是這樣會導致一些問題,比如A主動向B發起連接,A率先發起第一次連接請求, 但是由于一些問題,導致第一次請求訊息滯留在半路未能及時到達B端,所以A未能受到B的確認報文,此后A又發起第二次連接請求,到達B端后,B端回復連接確認報文,并開始準備接收A端的資料;當資料傳輸完畢后,AB之間斷開這條連接,而恰巧過后A第一發出的請求報文到達了B端,B段就回復確認報文,誤認為A端是在請求連接,然后又打開連接通道,等待A端發送資料,但是A端此時已經沒有資料發送,所以B端就會一直等待,導致資源浪費;這就是基于兩次握手導致的問題,所以才有三次握手,即B端回復確認報文后,還要等待A端的確認報文發過來以后,才正式確認建立連接,
五、TCP連接的釋放
1、大致程序示意圖

2、程序詳細說明
此時客戶端和服務器都是處于ESTABLISHED狀態,然后客戶端主動斷開連接,服務器被動斷開連接.
1) 客戶端行程發出連接釋放報文,并且停止發送資料,釋放資料報文首部,FIN=1,其序列號為seq=u(等于前面已經傳送過來的資料的最后一個位元組的序號加1),此時客戶端進入FIN-WAIT-1(終止等待1)狀態, TCP規定,FIN報文段即使不攜帶資料,也要消耗一個序號,
2)服務器收到連接釋放報文,發出確認報文,ACK=1,確認序號為 u+1,并且帶上自己的序列號seq=v,此時服務端就進入了CLOSE-WAIT(關閉等待)狀態,TCP服務器通知高層的應用行程,客戶端向服務器的方向就釋放了,這時候處于半關閉狀態,即客戶端已經沒有資料要發送了,但是服務器若發送資料,客戶端依然要接受,這個狀態還要持續一段時間,也就是整個CLOSE-WAIT狀態持續的時間,
3)客戶端收到服務器的確認請求后,此時客戶端就進入FIN-WAIT-2(終止等待2)狀態,等待服務器發送連接釋放報文(在這之前還需要接受服務器發送的最終資料)
4) 服務器將最后的資料發送完畢后,就向客戶端發送連接釋放報文,FIN=1,確認序號為v+1,由于在半關閉狀態,服務器很可能又發送了一些資料,假定此時的序列號為seq=w,此時,服務器就進入了LAST-ACK(最后確認)狀態,等待客戶端的確認,
5)客戶端收到服務器的連接釋放報文后,必須發出確認,ACK=1,確認序號為w+1,而自己的序列號是u+1,此時,客戶端就進入了TIME-WAIT(時間等待)狀態,注意此時TCP連接還沒有釋放,必須經過2?MSL(最長報文段壽命)的時間后,當客戶端撤銷相應的TCB后,才進入CLOSED狀態,
6)服務器只要收到了客戶端發出的確認,立即進入CLOSED狀態,同樣,撤銷TCB后,就結束了這次的TCP連接,可以看到,服務器結束TCP連接的時間要比客戶端早一些,
3、為什么客戶端最后要等待 2*MSL時間呢
這樣的設計有兩個用處:第一保證客戶端最后發送的ACK報文能夠到達服務器,如果不等待這個時間,而是直接釋放連接,導致服務器不能收到ACK報文,那么服務器就不能正常進入CLOSED狀態;如果等待的2*MSL時間內,B服務器沒有收到ACK報文,那么服務器就會發送超時重傳FIN+ACK報文,客戶端收到后就會重發ACK報文,確定服務器能夠收到,第二個作用就是避免前面提到的滯留請求報文問題,在等待的2*MSL時間內,能確保所有這次TCP連接互動的報文從網路中消失,確保下一次新的連接中不會出現舊的請求報文,
4、保活計時器
實際上,除了時間等待計時器,TCP還設有保活計時器,顧名思義,就是確保TCP連接都是“活著的”,因為實際情況中,免不了客戶端建立連接后出現客戶端故障現象,此時服務器收不到客戶端的資料,也不可能一直等待,浪費服務器資源,所以保活計時器就起作用了,服務器每次收到資料,就會重置保活計時器,通常時間為2個小時,若兩個小時內服務器沒有收到客戶端的資料,就發送一個探測報文,之后每隔75s發送一次,連續發送超過10次后,依舊沒有收到客戶端回應,服務器就認為客戶端故障,并釋放此次連接,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/387840.html
標籤:其他
下一篇:學習Osharp及解決問題【二】
