12.20 TCP/IP協議

這篇主要介紹TCP/IP協議。
TCP/IP協議其實是一個協議簇,其中比較重要的有SLIP協議、PPP協議、IP協議、ICMP協議、ARP協議、TCP協議、UDP協議、FTP協議、DNS協議、SMTP協議等。這裡我們主要介紹幾個常見的協議。

一、IP協議

IP協議(Internet Protocol),又叫網際協議,它解決了多個局域網互通的問題,提供不可靠、無連接的數據報傳送服務。

  • 不可靠:它不能保證IP數據報能成功到達目的地。IP協議會盡最大的努力,把數據包發送到目的地,但如果期間出現問題,則發送失敗。比如路由器暫時用完了緩衝區。
  • 無連接:IP並不維護任何關於後續數據報的狀態信息,可以不按發送順序接收。比如先後發送A、B兩條數據報。A、B是相互獨立的,可能會有不同的路由選擇,選擇不同的路線,所以並不能判定A、B誰先到達。

1.IP首部

網絡編程 - TCP/IP協議

現在是看圖說話時間(撿重要的說)。

  • 普通的IP首部長為20個字節,除非含有選項字段。最高位在左面,記0bit,最低位在右面,記31bit。傳輸次序是大端序(Big Endian)。先傳0~7bit,其次8~15 bit,然後16~23 bit,最後是24~31 bit。
    關於大端序小端序可以看這篇
  • 目前通用的版本號是4,所以也叫IPv4。
  • 首部長度指的是首部佔32 bit字的數目,包括任何選項。
  • 總長度字段是指整個IP數據報的長度,最長可達65535字節。
  • 標識字段唯一地標識主機發送的每一份數據報。
  • 生存時間字段設置了數據報可以經過的最多路由器數,初始值由源主機設置(通常為32或64),一旦經過一個處理它的路由器,它的值就減去1。當該字段的值為0時,數據報就被丟棄,併發送ICMP報文通知源主機。
  • 通過首部中的協議確定接收數據的上層協議(TCP/UDP/ICMP等)。
  • 首部檢驗和字段是根據IP首部計算的檢驗和碼。它可以判斷首部在傳輸過程中有沒有發生任何差錯。如果發生差錯就丟棄收到的數據報。
  • 源IP地址和目的IP地址在上篇提到。
  • 選項,是數據報中的一個可變長的可選信息。

二、ICMP協議

ICMP(Internet Control Message Protocol),Internet控制報文協議,從技術角度來說,ICMP就是一個“錯誤偵測與回報機制”,其目的就是讓我們能夠檢測網路的連線狀況﹐也能確保連線的準確性﹐其主要功能包括,確認 IP 包是否成功送達目標地址,通知在發送過程當中 IP 包被廢棄的具體原因,改善網絡設置等。

三、TCP協議

TCP協議(Transmission Control Protocol),傳輸控制協議,位於傳輸層。它提供一種面向連接的、可靠的字節流服務。

  • 面向連接:兩個使用TCP的應用(通常是一個客戶和一個服務器)在彼此交換數據之前必須先建立一個TCP連接。廣播和多播不能用於TCP。
  • 可靠的:TCP協議將會通過以下幾個方法提供可靠性 應用數據被分割成TCP認為最適合發送的數據塊。 當TCP發出一個段後,它啟動一個定時器,等待目的端確認收到這個報文段。如果不能及時收到一個確認,將重發這個報文段。 當TCP收到發自TCP連接另一端的數據,它將發送一個確認。這個確認不是立即發送,通常將推遲幾分之一秒。 TCP將保持它首部和數據的檢驗和。這是一個端到端的檢驗和,目的是檢測數據在傳輸過程中的任何變化。如果收到段的檢驗和有差錯,TCP將丟棄這個報文段和不確認收到此報文段。 TCP數據是在IP數據包中傳輸,如果IP數據丟失,那麼TCP數據也會丟失,進行重發。如有必要,TCP將對收到的數據進行重新排序,將收到的數據以正確的順序交給應用層。 TCP的接收端會丟棄重複的數據。 TCP還能提供流量控制。TCP連接的每一方都有固定大小的緩衝空間。TCP的接收端只允許另一端發送接收端緩衝區所能接納的數據。這將防止較快主機致使較慢主機的緩衝區溢出。

其實我覺得Halfrost總結的很好:TCP就是通過檢驗和、序列號、確認應答、重發控制、連接管理以及窗口控制等機制實現可靠性傳輸。

1.TCP首部

網絡編程 - TCP/IP協議

如果不計任選字段,它通常是20個字節。
依然進入看圖說話環節:

  • 每個TCP段都包含源端和目的端的端口號,用於尋找發端和收端應用進程。
  • 序號,即Sequence Number,用來解決網絡包亂序問題。
  • 確認序號,即Acknowledgement Number,就是ACK——用於確認收到,用來解決不丟包的問題。
  • 首部長度,或叫數據偏移,該字段表示 TCP 所傳輸的數據部分應該從 TCP 包的哪個位開始計算。
  • 保留,該字段主要是為了以後擴展使用。
  • 窗口控制,TCP的流量控制由連接的每一端通過聲明的窗口大小來提供。
  • 檢驗和,它覆蓋了整個的TCP報文段:TCP首部和TCP數據。這是一個強制性的字段,一定是由發端計算和存儲,並由收端進行驗證。
  • 緊急指針,只有當URG標誌置1時緊急指針才有效

2.TCP三次握手、四次揮手

2.1三次握手

網絡編程 - TCP/IP協議

簡單來說過程就是這樣的:

  1. 客戶端首先向服務端發送一個SYN包和一個隨機序列號 J
  2. 服務端收到後會回覆客戶端一個 SYN-ACK 包以及一個確認號(用於確認收到 SYN)J+1,同時再發送一個隨機序列號 K
  3. 客戶端收到後會發送一個 ACK 包和確定號 K+1 給服務端

我們看一個例子:

<code> % sudo tcpdump -c 3 -i en3 -nS host 23.63.125.15
18:31:29.140787 IP 10.0.1.6.52181 > 23.63.125.15.80: Flags [S], seq 1721092979, win 65535, options [mss 1460,nop,wscale 4,nop,nop,TS val 743929763 ecr 0,sackOK,eol], length 0
18:31:29.150866 IP 23.63.125.15.80 > 10.0.1.6.52181: Flags [S.], seq 673593777, ack 1721092980, win 14480, options [mss 1460,sackOK,TS val 1433256622 ecr 743929763,nop,wscale 1], length 0
18:31:29.150908 IP 10.0.1.6.52181 > 23.63.125.15.80: Flags [.], ack 673593778, win 8235, options [nop,nop,TS val 743929773 ecr 1433256622], length 0
/<code>

第一行
client -> server
左面是發送時間18:31,IP代表的是這些都是 IP 協議數據包。
10.0.1.6.52181 > 23.63.125.15.80,代表源和目標端的 IP 地址+端口。比如10.0.1.6.52181,10.0.1.6是IP地址,52181是端口號。
Flags表示 TCP 報文段 header 信息中的一些縮寫標識。S代表 SYN,. 代表ACK,P代表PUSH,F是FIN。
1721092979是隨機號seq
第二行
server -> client
前面幾個就不多做說明,Flags [S.],表示報文段 header中帶有SYN和ACK。
ack為1721092980,即第一行的seq+1,seq為673593777
第三行
client -> server
客戶端接收到信息後,發送Flags [.],報文段 header中ACK。
ack為673593778,即第二行的seq+1。

2.2四次揮手

TCP四次分手.png

  1. 客戶端要斷開連接了,向服務器發送FIN信號,告訴它我的數據發送完了,但是如果你有數據,我還可以接受,然後進入FIN_WAIT_1狀態
  2. 服務器接確認FIN包後,發送一個ack確認包,告訴客戶端我已接收到信息,但還沒有做好關閉準備。發送完畢後,服務器端進入 CLOSE_WAIT狀態,客戶端接收到這個確認包之後,進入 FIN_WAIT_2狀態,等待服務器端關閉連接。
  3. 服務器端準備好關閉連接時,向客戶端發送FIN包,要斷開連接。然後進入服務器進入LAST_ACK狀態。
  4. 客戶端接收到來自服務器端的關閉請求,發送一個確認包,並進入 TIME_WAIT狀態,等待可能出現的要求重傳的ACK包。服務器端接收到這個確認包之後,關閉連接,進入CLOSED狀態。等過了一定時間後,客戶端沒有收到服務器的ACK包,就知道已經斷開連接,進入CLOSED狀態。

2.3為什麼要進行三次握手?

通常我們會覺得,客戶端告訴服務器,我要和你握手了,然後服務器告訴客戶端,我知道了,這樣就可以了。為什麼要多客戶端再給服務器確認一遍呢?


這是因為我們現實生活中的網絡是複雜的,TCP數據在傳輸的過程中,很有可能會出現延遲到達或者重發的情況。我們在之前談到TCP的可靠性時,說到當TCP發出一個段後,它啟動一個定時器,等待目的端確認收到這個報文段。如果不能及時收到一個確認,將重發這個報文段。這個時候TCP首部的序列號是相同的。
如果因為網絡問題,第二個SYN包提前到達,在連接結束後第一個SYN包才到,服務器又會發一次ACK建立連接。此時服務器建立了連接,客戶端沒有連接,從而導致服務端建立了一個空的連接,浪費資源。
如果是三次握手,客戶端再次收到相同的ACK時,會丟棄這個包,不向服務端發送ACK和ack,從而避免了空連接。

2.4為什麼進行四次揮手

因為TCP是雙全工模式,即可以同時發送和接收數據,兩條通道是完全獨立的。客戶端向服務器揮手關閉的時候,服務器會繼續傳送之前沒有傳完的數據。在二三揮手之間,多了一個數據傳送的過程,這也是為什麼ACK和FIN不能同時發送的原因。

3. SYN攻擊

3.1 SYN攻擊是什麼

在三次握手過程中,服務器發送SYN-ACK之後,收到客戶端的ACK之前的TCP連接成為半連接(half-open connect)。此時服務器處於SYN_RCVD狀態。當收到ACK之後,服務器才能轉入ESTABLISHED狀態。
SYN攻擊指的是,攻擊客戶端在短時間內偽造大量不存在的IP地址,向服務器不斷髮送SYN包,服務器回覆確認包,並等待客戶的確認。由於源地址是不存在的,服務器需要不斷地重發直至超時,這些偽造的SYN包將長時間佔用未連接隊列,正常的SYN請求被丟棄,導致目標系統運行緩慢,嚴重會造成網絡堵塞甚至系統癱瘓。
SYN攻擊是一種典型的DoS/DDoS攻擊。

3.2 如何檢測SYN攻擊

檢測SYN攻擊非常的方便,當你在服務器上看到大量的半連接狀態時,特別是源IP地址是隨機的,基本上可以斷定這是一次SYN攻擊。在 Linux/Unix 上可以使用系統自帶的netstats命令來檢測 SYN 攻擊。

3.3 如何防禦SYN攻擊

SYN攻擊不能完全被阻止,除非將TCP協議重新設計。我們所做的是儘可能的減輕SYN攻擊的危害,常見的防禦 SYN 攻擊的方法有如下幾種:

  • 縮短超時(SYN Timeout)時間
  • 增加最大半連接數
  • 過濾網關防護
  • SYN cookies技術

4. TCP KeepAlive

TCP 通信雙方建立交互的連接,但是並不是一直存在數據交互,有些連接會在數據交互完畢後,主動釋放連接,而有些不會。交互雙方出現死機、異常重啟等情況都不會使TCP連接及時正常釋放,造成端系統資源的消耗和浪費。為了解決這個問題,在傳輸層可以利用 TCP 的 KeepAlive 機制實現來實現。主流的操作系統基本都在內核裡支持了這個特性。
TCP KeepAlive 的基本原理是,隔一段時間給連接對端發送一個探測包,如果收到對方回應的 ACK,則認為連接還是存活的,在超過一定重試次數之後還是沒有收到對方的回應,則丟棄該 TCP 連接。
但TCP KeepAlive 是有侷限。首先 TCP KeepAlive 監測的方式是發送一個 probe 包,會給網絡帶來額外的流量,另外 TCP KeepAlive 只能在內核層級監測連接的存活與否,而連接的存活不一定代表服務的可用。例如當一個服務器 CPU 進程服務器佔用達到 100%,已經卡死不能響應請求了,此時 TCP KeepAlive 依然會認為連接是存活的。因此 TCP KeepAlive 對於應用層程序的價值是相對較小的。需要做連接保活的應用層程序,例如 QQ,往往會在應用層實現自己的心跳功能。

四、UDP協議

UDP協議(User Datagram Protocol),用戶數據報協議。UDP 不提供複雜的控制機制,利用 IP 提供面向無連接的通信服務。傳輸途中即使出現丟包,UDP 也不負責重發,甚至當出現包的到達順序亂掉時也沒有糾正的功能。UDP 面向無連接,它可以隨時發送數據。

  • 面向無連接:通信雙方不需要事先建立一條連接,而是把每個帶有目的地址的包送到線路上,由系統自主選定路線進行傳輸。
  • 不可靠性:它把應用程序傳給IP層的數據發送出去,但是並不保證它們能到達目的。

1.UDP首部

網絡編程 - TCP/IP協議

  • 端口號不在說明了,和TCP一樣,只不過TCP端口號由TCP來查看,而UDP端口號由UDP來查看,這是根據IP數據報裡面的協議來區分的。
  • UDP長度字段指的是UDP首部和UDP數據的字節長度
  • UDP檢驗和覆蓋UDP首部和UDP數據。和TCP區別是,TCP檢驗和是必需的,而UDP的檢驗和是可選的。

2.TCP和UDP區別

  • 數據發送方式區別:TCP是建立在兩端連接之上的協議,UDP本身發送的就是一份份數據報。
  • 數據大小的區別:TCP理論上發送的數據流沒有上限,但是由於緩衝區有大小限制,但如果TCP數據過大,會被截為好幾段,接收方依次接收。UDP報文長度不能超過2^16=65536(如果想具體瞭解UDP包長限制,可以看這篇).
  • 數據有序性的區別:TCP本身有著超時重傳、錯誤重傳、還有等等一系列複雜的算法保證了 TCP 的數據是有序的。UDP並不具備數據糾正功能。
  • 數據可靠性的區別:TCP 的超時重傳、錯誤重傳、TCP 的流量控制、阻塞控制、慢熱啟動算法、擁塞避免算法、快速恢復算法等方法都使得TCP在保持連接的過程中是可靠的。UDP是一個面向非連接的協議,UDP 發送的每個數據報帶有自己的 IP 地址和接收方的 IP 地址,它本身對這個數據報是否出錯,是否到達不關心,只要發出去了就好了。
  • 使用場景區別:UDP 主要用於那些對高速傳輸和實時性有較高要求的通信或廣播通信,比如:流媒體、物聯網、實時遊戲等。其他就可以考慮使用TCP(只是考慮,具體問題具體分析),比如QQ文件傳輸。

五、DNS協議

通常我們去請求一個網址輸入的是https://github.com這種形式,但這並不是IP地址。那我們怎麼去尋找他的地址呢?這時候就需要DNS。
DNS域名系統是一種用於TCP/IP應用程序的分佈式數據庫。我們向DNS服務器發送一個DNS數據包,然後DNS服務器做出響應告訴我們github的IP地址是192.30.253.113。
目前有很多DNS服務器,比如google的8.8.8.8,阿里的223.5.5.0,百度的180.76.76.76。
有時候我們會遇到DNS被汙染的情況,這個時候我們就沒辦法去請求某一個網頁。一個小技巧:在使用MAC的情況下,在跳轉路徑輸入:/private/etc/,找到hosts文件,添加內容即可。

網絡編程 - TCP/IP協議

以上便是我對TCP/IP協議的理解,如果不當之處還望指出。

需要TCP/ip協議棧視頻資料的可以後臺私信【架構】獲取百度雲鏈接
需要更多c++ Linux後臺服務器開發的視頻資料的也可以回覆【架構師】獲取


分享到:


相關文章: