在眾多的網路協議中,TCP協議佔據著舉足輕重的地位,你知道什麼是TCP協議嗎?
一、TCP協議
TCP(Transmission Control Protoco)協議屬於計算機網路體系中的運輸層。運輸層的任務是負責向主機中應用層程式之間的通訊提供通用的資料傳輸服務。所以可以通俗理解TCP協議就是程式間資料通訊傳輸協議。根據不同應用,運輸層主要使用TCP和UDP兩種協議之一。如果想要了解計算機網路體系分層概念,可以看我的上一篇博文 計算機網路體系結構劃分
二、TCP協議特點
TCP協議本身是比較複雜的,它包含擁塞控制、可靠傳輸、流量控制、連線管理等功能,主要特點包含以下幾個方面:
- TCP是面向連線的協議,程式在使用TCP協議通訊時,必須要先建立TCP連線。這就好比我要給你打電話,我們倆之間的通訊線路必須是連線狀態的。
- TCP連線是點對點的,每一條TCP連線只能有兩個埠(endpoint)。這個端點就是我們Java網路程式設計所使用的套接字(socket)。由IP地址+埠號組成(IP:埠號)。
- TCP連線提供可靠交付,也就是說使用TCP連線傳輸資料,保證無差錯、不丟失、不重複並且按順序到達
- TCP連線是雙向的通訊,也就是說通訊的兩方,既能傳送資料,也能接收資料。就向我們通話時雙方一樣。
- TCP面向位元組流傳輸資料,就是說TCP傳送資料時,是把程式交付的資料,按照一段段位元組流序列傳遞的,每次傳輸其中一段位元組序列。應用層接收位元組序列後,再將內容還原。
三、TCP報文格式
既然TCP協議屬於運輸層,運輸層職責是為主機應用層提供程式間的資料傳輸,所以我們有必要搞清楚TCP協議運輸資料時的形式。TCP協議規定了TCP傳輸資料的單元為TCP資料包。TCP報文是對應用層程式交付資料的封裝。 TCP資料包由兩部分組成:TCP首部和TCP資料部分
- TCP首部:包含許多控制和描述欄位,是TCP全部功能的體現
- TCP資料部分:對於應用層程式交付的資料,封裝後的位元組流序列 應用層程式交付的資料被封裝TCP報文,然後進行傳輸,TCP連線保證資料傳輸的可靠性,TCP報文傳輸的過程示意圖:
四、TCP報文首部
TCP報文首部定義是TCP協議的精華所在,TCP複雜功能的實現,全部依靠了首部裡各種控制欄位。我們來看下TCP首部都定義了什麼:
TCP報文的首部由20個位元組固定位元組和4n(n取[0~5]整數)個可變的選項位元組組成,其中固定部分的各欄位含義如下:-
源埠和目的埠:各佔2個位元組,分別寫入通訊雙方程式埠號
-
序號seq:佔4個位元組。在TCP連線中,傳送的位元組流中的每一個位元組都是要按順序編號[0~2^32^-1],整個要傳送的位元組流的起始序號在必須連線建立時設定,序號欄位值代表本報文段所傳送的資料的第一個位元組的序號
-
確認號ack:佔4個位元組,是期望收到對方的下一個報文段的第一個資料位元組的序號,即ack=N,就代表了到序號N-1為止的所有資料都被正確接收了。
-
資料偏移:佔4位,表示TCP報文的資料部分起始處距離TCP報文首部的起始處有多遠,資料偏移值的單位是32位字(以4位元組為計算單位),4位二進位制能表示的值[0~15],這就意味著TCP首部最大長度為60位元組,也就是選項部分的最大長度為40位元組。
-
保留位:佔6位,保留為以後使用,目前置為0
-
控制位:佔6位,每個控制欄位佔1位,它們的標識和含義是:
- 緊急URG:URG=1時,告訴系統此報文中有緊急資料,優先傳送,與緊急指標配合使用
- 確認ACK:當ACK=1時,確認號才有效,ACK=0時,確認號無效,TCP連線建立後,所有報文ACK必須都為1
- 推送PSH:傳送方把PSH置為1,接收方收到報文後會儘快交付,不用等快取填滿了再交付
- 復位RST:當RST=1時,表明TCP連線出現了嚴重差錯,必須釋放連線,然後重新建立新運輸連線。RST=1還可以用來拒接一個非法報文段或拒絕開啟一個連線。
- 同步SYN:在連線建立時用來同步序號。當SYN=1而ACK=0時,表明這是一個連線請求報文段,對方若同意建立連線,則需要在響應報文中使SYN=1和ACK=1
- 終止FIN:用來釋放一個連線 。當FIN=1時,表明此報文段的傳送方資料已經傳送完畢,並且要求釋放運輸連線。
-
視窗:佔2位元組,視窗值是[0~2^16^-1]之間的整數。視窗值告訴了對方,從本報文段的確認號算起,允許對方傳送的資料量。
-
檢驗和:佔2位元組,用於接收方檢驗首部和資料部分是否在傳輸中有差錯,類似我們下載檔案時的Md5簽名校驗作用。
-
緊急指標:佔2位元組,URG=1時才起作用,用於指明本報文段中的緊急資料的位元組數,緊急資料結束後就是普通資料,所以緊急指標指出了緊急資料的末尾在報文中位置。
-
選項:長度可變,最小0位元組,最長達40位元組。首部用來動態儲存資料。
五、三次握手過程
TCP是面向連線的,所以每次傳輸資料之前,必須要建立TCP連線,在TCP建立連線時主要解決三個層面問題:
- 使連線的每一方都能確認對方的存在
- 協商連線中引數,比如各方視窗值,時間戳等
- 各方對運輸資源如快取大小、連線表等進行分配
我們都知道TCP連線採用的是C/S模式,主動發起連線的叫客戶端client,被動等待連線的叫伺服器Server。那麼TCP建立連線的過程是什樣的呢?什麼是三次握手呢?
預設情況下客戶端client和服務端sever的TCP程式都處於CLOSED(關閉)狀態。 服務端TCP服務程式先建立傳輸控制塊TCB,然後準備接受客戶端請求,此時服務端進入LISTEN狀態,等待客戶端連線請求,- 第一次握手:客戶端TCP程式也先建立傳輸控制塊TCB,然後向服務端傳送連線請求報文段,此時SYN=1,隨機選定一個初始序號seq=x,,此報文不能攜帶資料,但是要消耗掉一個序號,傳送完畢後,客戶端進入SYN-SENT(同步已傳送)狀態
- 第二次握手:服務端收到客戶端請求連線報文段後,若同意建立連線,則傳送確認報文,確認報文中SYN=1、ACK=1,確認號ack=x+1,同時隨機選定一個自己序號seq=y,確認報文段同樣不能攜帶資料,但是也要消耗掉一個序號,傳送完畢後服務端進入SYN-RCVD(同步收到)狀態
- 第三次握手:客戶端收到確認報文後,檢查ACK=1,ack=x+1是否正確,若正確,則向服務端傳送確認報文,確認報文中ACK=1,ack=y+1,seq=x+1,傳送後進入ESTAB-LISHED狀態,服務端收到確認報文後,也進入ESTAB-LISHED狀態,此時雙方TCP連線正式建立。
上面的連線建立過程就是TCP三次握手。
六、為什麼是三次握手?
為什麼client收到確認報文後,還要再傳送一次確認報文給server呢?這主要是為了防止已失效的連線請求報文段突然又送到了Server端。
假設現在TCP連線是兩次握手機制,如下圖server在收到client的連線請求,確認後就進入ESTAB-LISHED狀態,會存在這樣一種問題:
client傳送連線請求報文,由於網路原因,長時間阻塞在某個網路節點上了,於是client重傳了一次請求連線報文,第二次請求報文正常達到server,連線正常建立,資料傳輸完畢後,釋放連線。
但是假設此時第一次傳送的請求報文並沒有丟失,而是延誤一段時間才到達server,這本是已失效的連線請求報文段,但是server收到後,會以為是client重新傳送的連線請求,於是向client傳送確認報文後,進入ESTAB-LISHED狀態,但是client並沒有發出新建連線的請求,就會忽略server的確認報文,server卻在一直等待client傳送資料,導致server資源浪費嚴重。
總結起來看,TCP三次握手過程就是client與server在相互確認各自傳送和接收是否正常的過程:- 第一次握手:client—>server,server確認了cilent的傳送能力和自己的接收能力是正常的
- 第二次握手:server—>client,client確認了自己的傳送能力和server的接收能力是正常的,但是server此時不清楚自己的傳送能力是否正常
- 第三次握手:client—>server,server確認了自己的傳送能力正常,同時也表明雙方也都確認完畢,可以開始傳輸資料。
那麼為什麼不進行四次握手呢?這個問題留給你們解答。