TCP協議詳解

TCP簡介

TCP,Transmission Control Protocol,傳輸控制協議。

TCP是爲了在不可靠的互聯網絡上提供可靠的端到端字節流而專門設計的一個傳輸協議。即面向連接、可靠、基於字節流的傳輸層通信協議。

TCP協議位於OSI七層模型中的傳輸層,爲下層提供可靠傳輸。
數據鏈路層負責數據交換、網絡層負責路徑選擇、應用層負責業務邏輯,而TCP可以在傳輸層提供可靠的傳輸。

TCP頭部格式

源端口:16位,2字節。
目的端口:16位,2字節。
序號:此報文的序號,用於標識報文和被確認。
確認號:用於確認序號。
數據偏移

  • 意思是數據部分往後偏移
  • 這是TCP的頭部長度字段,代表有多少個32bit,即1代表32bit,2代表64bit。
  • 一共4位最大爲15,15×32=480b=60B。所以頭部最大爲60個字節,最小爲20字節。
  • 此字段與圖中選項字段相關聯。

保留字段:未使用。
通信字段

  1. URG(緊急指針,應加速傳送)
  2. ACK(用於確認)
  3. PSH(緊急位,應立即傳送)
  4. RST(復位,比如拒絕連接)
  5. SYN(請求連接)
  6. FIN(請求斷開連接)

這6位用於TCP通信,相應位置1表示特殊的信號。
比如典型的SYN、FIN用於三次握手和四次揮手。

窗口:用於擁塞控制,接收方可以控制發送方發送數據報文的吞吐量,防止自己太忙來不及接收。
校驗和:此字段用來校驗數據是否出錯。
緊急指針:用於發送緊急數據的情況。
選項與填充:

  • TCP頭部的長度可以變化,因此可以承載更多的數據。

注意這裏必須使用32位的數據,這樣就可以快速定位數據部分的位置,所以沒有那麼多數據的話需要在後面進行填充。
這裏與數據偏移字段相關聯,這樣就可以知道頭部的長度以及數據部分的準確位置。

TCP的實現邏輯

爲滿足TCP協議的這些特點,TCP協議做了如下的規定:

1.到達確認

接收端接收到報文時,根據報文序號向發送端發送一個確認;

  • 確認號=需要確認的報文的序列號Seq+需要確認的報文的數據長度Len

三次握手時:

  1. 客戶端向服務器發送一個同步數據包請求建立連接,該數據包中,初始序列號(ISN)是客戶端隨機產生的一個值,確認號是0;

  2. 服務器收到這個同步請求數據包後,會對客戶端進行一個同步確認。這個數據包中,序列號(ISN)是服務器隨機產生的一個值,確認號是客戶端的初始序列號+1;

  3. 客戶端收到這個同步確認數據包後,再對服務器進行一個確認。該數據包中,序列號是第2步中,也就是同步請求確認數據包中的確認號值,確認號是服務器的初始序列號+1。

傳輸數據時:

  1. 初始序列號隨機產生,後續序列號爲上一個數據包(對方發送的數據包)的確認號。

  2. 確認號爲上一個對方發送過來的數據包中的序列號+長度Len

  3. 如果連續發送多個數據包:確認號同樣是2中的ACK號,不變;

2.超時重傳

發送方在發送報文後啓動超時定時器,如果在定時器超時之後沒有收到相應的確認ACK,重發報文;

3.重複處理

作爲IP數據報來傳輸的TCP報文會發生重複,TCP的接收端必須丟棄重複的數據;

4.數據校驗

TCP將保持它首部和數據的檢驗和,這是一個端到端的檢驗和,目的是檢測數據在傳輸過程中的任何變化。如果收到分片的檢驗和有差錯,TCP將丟棄這個報文,並不確認收到此報文段導致對端超時並重發。

5.滑動窗口

TCP連接每一方的接收緩衝空間大小都固定,接收端只允許另一端發送接收端緩衝區所能接納的數據,TCP在滑動窗口的基礎上提供流量控制,防止較快主機致使較慢主機的緩衝區溢出。

UTOOLS1577100400754.png

滑動窗口是指可發送報文的數量,比如上圖是51-31=20。
只有在窗口中的報文才允許發送。
收到35的ACK後,就認爲之前的報文也已收到。(發送一個ACK就行了)
收到35的ACK後,滑動窗口向前滑動到36-55,多出來的52-55=4個報文可以發送給對方。

這樣的機制可以防止緩衝區溢出。
因爲未確認的話,窗口就不會滑動,就不會發送新的報文。

6.擁塞控制

發送方維持一個叫做擁塞窗口cwnd(congestion window)的狀態變量。

UTOOLS1577351411314.png UTOOLS1577351504005.png

當cwnd < ssthresh時,使用慢開始算法。
當cwnd ≥ ssthresh時,改用擁塞避免算法。

ssthresh初始值爲16,後期ssthresh=max( cwnd/2 , 2 )

慢啓動階段

cwnd初始值爲1,收到確認ACK後,按指數增長增加cwnd。

擁塞避免階段

收到確認ACK後,swnd+1。

7.快速重傳

重傳存在的問題:

當一個報文段丟失時,會等待一定的超時週期然後才重傳分組,增加了端到端的時延。

當一個報文段丟失時,在其等待超時的過程中,可能會出現這種情況:其後的報文段已經被接收端接收但卻遲遲得不到確認,發送端會認爲也丟失了,從而引起不必要的重傳,既浪費資源也浪費時間。

快重傳算法規定:

發送方只要一連收到三個重複確認就應當立即重傳對方尚未收到的報文段,而不必繼續等待設置的重傳計時器時間到期。

UTOOLS1577351311960.png

爲什麼是三次ACK?

首先要明白一點,即使發送端是按序發送,由於TCP包是封裝在IP包內,IP包在傳輸時亂序,意味着TCP包到達接收端也是亂序的,亂序的話也會造成接收端發送冗餘ACK。那發送冗餘ACK是由於亂序造成的還是包丟失造成的,這裏便需要好好權衡一番,因爲把3次冗餘ACK作爲判定丟失的準則其本身就是估計值。

8.快速恢復

當發送端收到連續三個重複的確認時,由於發送發現在認爲網絡很可能沒有發生擁塞,因此現在不執行慢開始算法而是執行快恢復算法。

  • 慢開始門限 ssthresh = 當前擁塞窗口 / 2
  • 新擁塞窗口 cwnd = 慢開始門限 ssthresh
  • 開始執行擁塞避免算法,是擁塞窗口緩慢地線性增大
UTOOLS1577352489240.png

TCP協議過程

1.三次握手

建立連接有三步:
1.Client發送SYN至Server
2.Server收到SYN之後,對此SYN進行迴應:發送包含ACK和SYN的數據包至Client。
3.Client也對此SYN進行迴應,發送ACK至Server。

2.四次揮手

釋放連接有四步:
1.客戶端發送FIN至Server。
2.Server對此FIN進行迴應:發送ACK給Client。
3.Server也請求關閉連接,發送FIN給Client。(這時FIN和ACK分開,而三次握手中SYN和ACK爲同一個包)
4.Client對FIN進行迴應:發送ACK至Server。

3.seq和ack設置原則

起初seq爲隨機值。之後發送的seq爲上一個發送的數據包seq值+1
ack對上一個收到的數據包進行迴應,爲上一個收到的數據包seq值+1。
若連續發送多個包,則ack不變,依然爲上一個收到的數據包seq值+1。seq每一次都自增。

Linux中的TCP

1.netstat命令

netstat
    -t	#顯示TCP的連接情況
    -u	#顯示UDP的連接情況
    -a	#顯示所有連接情況
    -l	#只顯示Listening狀態的連接
    -n	#顯示IP而不是域名
    -p	#顯示PID和程序名

2.nc命令

舉例
    監聽
        nc -l 10086		#監聽TCP端口10086
        nc -ul 10086	#監聽UDP端口10086
    掃描
        nc -zv 192.168.191.128 10088
參數
    監聽
        -l		#監聽端口(默認監聽TCP)
        -u		#配合-l監聽UDP端口
    發送數據
        -z		#掃描端口,但不發送任何信息
        -s		#指定發送數據的源地址
        -v		#輸出調試信息
        -w		#超時時間(秒)
echo hello > /dev/tcp/192.168.191.128/10086 #使用TCP發送數據到192.168.191.128:10086
exec 8>/dev/tcp/192.168.191.128/10086       #監聽TCP的10086端口(接收數據e後TCP不斷開)	

3.網絡優化

vim /etc/sysctl.conf
    net.ipv4.tcp_syn_retries=2		#最多發起2次SYN請求(默認爲5)
    net.ipv4.tcp_fin_timeout=30		#FIN_WAIT_2時間
    net.ipv4.tcp_max_syn_backlog = 4096		#SYN隊列長度(默認爲1024),增加以容納更多等待連接數
    net.ipv4.tcp_tw_reuse = 1		#開啓TIME-WAIT sockets重用機制(默認爲0,即關閉),可重新用於新的TCP連接
    net.ipv4.tcp_tw_recycle = 1		#開啓TIME-WAIT sockets快速回收(默認爲0,即關閉)
    net.ipv4.tcp_syncookies = 1		#當SYN等待隊列溢出時,啓用cookies來處理(默認爲0,即關閉),可以防範少量SYN攻擊
    net.core.netdev_max_backlog=3000	#每個網絡接口接收數據包的速率比內核處理這些包的速率快時,允許送到隊列的數據包的最大數目
    net.ipv4.ip_forward = 1				#開啓內核轉發
sysctl -p   #查看內核參數

發佈了100 篇原創文章 · 獲贊 47 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章