1. 程式人生 > >深入淺出之 TCP協議(三次握手與四次揮手、超時重發、流量控制、擁塞控制、與UDP區別)

深入淺出之 TCP協議(三次握手與四次揮手、超時重發、流量控制、擁塞控制、與UDP區別)

TCP/IP 中有兩個具有代表性的傳輸層協議,分別是TCP、UDP。TCP提供可靠的通訊傳輸,而UDP則常被用於讓廣播和細節控制交給應用的通訊傳輸。

要知道TCP為了這簡單描述“可靠的通訊傳輸”背後所做的努力,你會深感佩服其強大性。TCP的特徵:序列化+確認應答、超時重發、流量控制、擁塞控制等等,每一個都是為了能夠可靠不丟包遺漏地將資料包傳輸給對方,而此篇文章將詳細來解析TCP的這些精髓所在,涉及的知識點有:

  • TCP概念、優缺點
  • 序列化+確認應答、三次握手與四次揮手、超時重發、流量控制、擁塞控制
  • TCP與UDP的區別
  • 常見面試問題
  • 埠號概念

一. TCP重點解析

TCP位於傳輸層,提供可靠的位元組流服務

(Byte Stream Service)。

  • 位元組流服務:為了方便傳輸,將大塊資料分割以報文段(segment)為單位的資料包進行管理。應用程式和TCP的互動是一次一個資料塊(大小不等),但TCP把應用程式看成是一連串的無結構的位元組流。
    • 當資料塊太長時,TCP中的快取可以將應用程式發來的資料塊劃分成若干個短部分再傳送。
    • 當資料塊太短時,例如應用程式一次只發送一個位元組,TCP也可以等待積累有足夠多的位元組後再構成報文段傳送出去。
  • 可靠的傳輸服務:能夠把資料準確可靠地傳給對方。

優點:

  • 可靠、穩定性
    • 傳遞資料前,會有三次握手建立連線 ;
    • 傳遞資料時,有確認、視窗、重傳、擁塞控制;
    • 傳遞資料後,會斷開連線節省系統資源;

缺點:

  • 傳輸慢,效率低,佔用系統資源高:
    • 傳遞資料前,建立連線需要耗時
    • 傳遞資料時,確認、重傳、擁塞等會消耗大量時間以及CPU和記憶體等硬體資源
  • 易被攻擊 :因為有確認機制,三次握手等機制,容易被人利用,實現DOS 、DDOS攻擊

TCP協議為了更容易傳送大資料才把資料分割,而且TCP協議能夠確認資料最終是否送達到對方。為了通過IP資料報實現可靠傳輸,需要考慮很多事情,例如資料破壞、丟包、重複以及分片順序混亂等問題。若無法節解決,無需談論可靠傳輸。

TCP通過檢驗和、序列號、確認應答、重發控制、連線管理及視窗等機制實現可靠傳輸。

1. 可靠傳輸(序列化+確認應答)

(1)確認應答ACK(Positive Acknowledgment)

在TCP中,當傳送端的資料到達接收主機時,接收端主機會返回一個已收到訊息的通知。此訊息叫做確認應答ACK。

這裡寫圖片描述這裡寫圖片描述

如圖1,TCP通過肯定的確認回答(ACK)實現可靠的資料傳輸。當傳送端將資料發出後等待對方的確認應答,若有應答則表示對方已成功接收。反之則資料丟失可能性大。

如圖2,在一定時間內沒有等待確認應答,傳送端就可以認為資料已丟失,進行重發。因此即使丟包,仍然可以保證資料傳輸到對方。(注意:未收到應答不一定是資料丟失,可能是確認應答在途中丟失)

(2)序列號

此外,也有可能是其它原因導致傳送端未收到確認應答,主機只需按照機制重發資料即可,但對於目標主機而言,它會收到相同的資料包,為此引入一種機制,能夠識別是否已經接受資料和判斷是否需要接收。

上述這些確認應答處理、重發控制以及重複控制等功能都可以通過序列號實現。序列號是按順序給傳送資料的每一個位元組(8位位元組)都標上號碼的編號。接收端查詢接收資料TCP首部中的序列號和資料長度,將下一步應接收的序號作為確認應答返送回去。

這裡寫圖片描述

綜上,通過序列號和確認應答,TCP可以實現可靠傳輸。

2. 重發超時

重發超時是指在重發資料之前,等待確認應答到來的那個特定時間間隔,如果超過這個時間仍未收到確認應答,傳送端將進行資料重發。TCP要保證所有的資料包都可以到達,所以,必需要有重傳機制。

接收端給傳送端的Ack確認只會確認最後一個連續的包

幾個例子,傳送端發了1,2,3,4,5一共五份資料,接收端收到了1,2,於是回ack 3,然後收到了4(注意此時3沒收到),此時的TCP會怎麼辦?

(1)超時重傳機制

傳送端繼續等待3,即使收到了4,也不會回覆ack。當傳送方發現收不到3的ack超時後,會重傳3。一旦接收方收到3後,會ack 4,意味著3和4都收到了。此機制下有兩種應對方法:

  • 僅重傳timeout的包。也就是第3份資料。
  • 重傳timeout後所有的資料,也就是第3,4,5這三份資料

第一種會節省頻寬,但是慢,第二種會快一點,但是會浪費頻寬。但其實這兩種方法都不太好,都需要等待timeout(timeout可能會很長)。

(2)快速重傳(Fast Retransmit )機制

TCP引入了一種叫Fast Retransmit 的演算法,不以時間驅動,而以資料驅動重傳。如果資料包沒有連續到達,就ack最後那個可能被丟了的包,如果傳送端連續收到3次相同的ack就重傳。其好處是傳送端不需要一直等待,直到timeout後再重傳。

這裡寫圖片描述

如上圖,再舉個例子,如果傳送方發出了1,2,3,4,5份資料,第一份先到送了,於是就ack回2,結果2因為某些原因沒收到,3到達了,於是還是ack回2,後面的4和5都到了,但是還是ack回2,因為2還是沒有收到,於是傳送端收到了三個ack=2的確認,知道了2還沒有到,於是就馬上重轉2。然後,接收端收到了2,此時因為3,4,5都收到了,於是ack回6。

雖然快速重傳機制解決了timeout的問題,還遺留了之前提出的一個問題:是重傳之前的一個還是重傳所有資料包?對於上面的示例來說,是重傳#2呢還是重傳#2,#3,#4,#5呢?因為傳送端並不清楚這連續的3個ack(2)是誰傳回來的?也許傳送端發了20份資料,是#6,#10,#20傳來的。

因此,快速重傳機制仍然是有缺點的!

(3)SACK 方法

Selective Acknowledgment (SACK)方法:需要在TCP頭裡加一個SACK的東西,ACK還是Fast Retransmit的ACK,SACK則是彙報收到的資料碎版。參考下圖:

這裡寫圖片描述

此方法是基於Fast Retransmit的演算法上的優化,在傳送端就可以根據回傳的SACK來知道哪些資料到了,哪些沒有到。

但是!SACK會消費傳送方的資源,試想,如果一個攻擊者給資料傳送方發一堆SACK的選項,這會導致傳送方開始要重傳甚至遍歷已經發出的資料,這會消耗很多傳送端的資源。

(4)Duplicate SACK – 重複收到資料的問題

主要使用了SACK來告訴傳送方有哪些資料被重複接收了,D-SACK使用了SACK的第一個段來做標誌:

  • 如果SACK的第一個段的範圍被ACK所覆蓋,那麼就是D-SACK
  • 如果SACK的第一個段的範圍被SACK的第二個段覆蓋,那麼就是D-SACK

D-SACK方法的好處:

  • 可以讓傳送方知道,是發出去的包丟了,還是回來的ACK包丟了。
  • 是不是自己的timeout太小了,導致重傳。
  • 網路上出現了先發的包後到的情況(又稱reordering)
  • 網路上是不是把我的資料包給複製了。

3. 連線管理

為了準確無誤地將資料送達目標處,TCP協議採用了三次握手(three-way handshaking)策略。用TCP協議將資料包送出去後,TCP一定會向對方確認是否成功送達。若在握手過程中某個階段莫名中斷,TCP協議會再次以相同的順序傳送相同的順序包。

(1)三次握手過程

定義:三次握手,是指建立一個TCP連線時,需要客戶端和伺服器總共傳送3個包。

目的:是連線伺服器指定埠,建立TCP連線,並同步連線雙方的序列號和確認號並交換 TCP 視窗大小資訊

在socket程式設計中,客戶端執行connect()時,將觸發三次握手。

這裡寫圖片描述

  • 第一次握手:建立連線時,客戶端傳送syn包(syn=j)到伺服器,並進入SYN_SEND狀態,等待伺服器確認;

  • 第二次握手:伺服器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也傳送一個SYN包(syn=k),即SYN+ACK包,此時伺服器進入SYN_RECV狀態;

  • 第三次握手:客戶端收到伺服器的SYN+ACK包,向伺服器傳送確認包ACK(ack=k+1),此包傳送完畢,客戶端和伺服器進入ESTABLISHED狀態,完成三次握手。完成三次握手,客戶端與伺服器開始傳送資料。

(2)四次揮手

所謂四次揮手(Four-Way Wavehand)即終止TCP連線,就是指斷開一個TCP連線時,需要客戶端和服務端總共傳送4個包以確認連線的斷開。在socket程式設計中,這一過程由客戶端或服務端任一方執行close來觸發,整個流程如下圖所示:

這裡寫圖片描述

由於TCP連線時全雙工的,因此每個方向都必須要單獨進行關閉。首先進行關閉的一方將執行主動關閉,而另一方則執行被動關閉。

當一方完成資料傳送任務後,傳送一個FIN來終止這一方向的連線,收到一個FIN只是意味著這一方向上沒有資料流動了,即不會再收到資料了,但是在這個TCP連線上仍然能夠傳送資料,直到這一方向也傳送了FIN。

  • 第一次揮手:主動關閉方傳送一個FIN並進入FIN_WAIT1狀態

  • 第二次揮手:被動關閉方接收到主動關閉方傳送的FIN併發送ACK,此時被動關閉方進入CLOSE_WAIT狀態;主動關閉方收到被動關閉方的ACK後,進入FIN_WAIT2狀態

  • 第三次揮手:被動關閉方傳送一個FIN並進入LAST_ACK狀態

  • 第四次揮手:主動關閉方收到被動關閉方傳送的FIN併發送ACK,此時主動關閉方進入TIME_WAIT狀態,經過2MSL時間後關閉連線;被動關閉方收到主動關閉方的ACK後,關閉連線

(3)為什麼建立連線是三次握手,而關閉連線卻是四次揮手呢

  • 對於3次握手:主要是要初始化Sequence Number 的初始值。通訊的雙方要互相通知對方自己的初始化的Sequence Number(縮寫為ISN:Inital Sequence Number)——所以叫SYN,全稱Synchronize Sequence Numbers。也就上圖中的 x 和 y。這個號要作為以後的資料通訊的序號,以保證應用層接收到的資料不會因為網路上的傳輸的問題而亂序(TCP會用這個序號來拼接資料)。
  • 對於4次揮手:其實你仔細看是2次,因為TCP是全雙工的,所以,傳送方和接收方都需要Fin和Ack。只不過,有一方是被動的,所以看上去就成了所謂的4次揮手。如果兩邊同時斷連線,那就會就進入到CLOSING狀態,然後到達TIME_WAIT狀態。

服務端在LISTEN狀態下,收到建立連線請求的SYN報文後,把ACK和SYN放在一個報文裡傳送給客戶端。

而關閉連線時,當收到對方的FIN報文時,僅僅表示對方不再發送資料了但是還能接收資料,己方也未必全部資料都發送給對方了,所以己方可以立即close,也可以傳送一些資料給對方後,再發送FIN報文給對方來表示同意現在關閉連線,因此,己方ACK和FIN一般都會分開發送。

二. 流控制(Flow Control)

1. 滑動視窗協議

此部分進行的講解重心還是放在網路傳輸的可靠性,仔細探究TCP協議是如何解決網路傳輸的不可靠問題,其中有個非常關鍵部分——滑動視窗協議,同時可驗證網路學科的實踐性、工程性。

(1)滑動視窗協議的特徵定義

  • TCP協議中使用
  • 維持傳送方/接收方快取區

此快取區主要用於解決網路傳輸的不可靠問題,在上一點已經介紹過網路傳輸的不可靠問題,如丟包、重複包、出錯等,在TCP協議中傳送方、接收方各自維護自己的快取區,互相商定包的重傳機制,由此解決不可靠問題。

(2)提出問題

如果沒有滑動視窗協議,如何保證接收方能夠收到正確有序的包?

這裡寫圖片描述

如上圖所示,傳送方傳送包1,接收方確認包1,傳送包2,確認包2,這樣即可解決不可靠性問題。但同時此過程的問題十分明顯:吞吐量低,必須要等接收方確認完後才能傳送下一個包。試考慮,若能連發幾個包,接收方可以同時確認,這樣效率豈不更高?

(3)簡單改進

在此問題上,出現了以下改進:傳送方可以同時發多個包,接收方一起確認。

這裡寫圖片描述

(4)深度改進——滑動視窗實現

由此又衍生出一個問題,同時發包的數量多少才會是最優方案呢?例如傳送方同時傳送包1、2,在獲得接收方確認包1訊息後,能否不等包2確認資訊,直接傳送包3呢?

這樣很自然地思考到了“滑動視窗實現”。以下有16個數據包,傳送方希望按照順序傳送,在接收方收到每個包後都逐一給予確認:

這裡寫圖片描述

  • 初始:(視窗為4到7)
    • 1、2、3包已傳送並且獲取傳送方Ack確認;
    • 4、5、6、7包已傳送但尚未獲取傳送方Ack確認;
    • 8、9、10包待發送;
    • 而11、12、13、14、15、16包未傳送甚至都沒有裝入記憶體;
  • 正常:(視窗為5到9)
    • 1、2、3、4包已傳送並且獲取傳送方Ack確認;
    • 5、6、7、8、9包已傳送但尚未獲取傳送方Ack確認;
    • 10、11包待發送;
    • 而12、13、14、15、16包未傳送甚至都沒有裝入記憶體;

這裡寫圖片描述

  • 丟Ack:(視窗為5到11)
    • 5、6、7、8、9包未收到Ack(丟Ack),在等待過程又傳送了10、11包,此時視窗已滿,無法讀進包12,只能等待Ack。如果真的是丟包,始終無法收到Ack,此時超時重傳機制會從包5開始重新發送。(注意,這裡的Ack是按照順序傳送的!)
  • 重發: (視窗為9到15)
    • 5、6、7、8包獲取傳送方Ack確認;
    • 9、10、11、12、13包已傳送但尚未獲取傳送方Ack確認;
    • 13、14包待發送;
    • 而16包未傳送甚至都沒有裝入記憶體;

(5)總結

運用工程學的思想來考慮滑動視窗機制較為容易,為了增加線路的吞吐量,改進原版方案,令傳送方同時傳送包;為了衡量同時傳送的數量達到吞吐量最優解,從而引進滑動視窗機制;為了解決丟包等不可靠性問題導致傳送方無法收到接收方的Ack,又引進了重發機制。以上一系列過程使得整個傳輸過程更加可靠。

2. 解釋流控制

理解以上滑動視窗協議的示例後,大體也就知道了“流控制”是怎麼回事兒,此部分用較書面的表達再解釋一次。

(1)出現的問題

傳送端根據自己的實際情況傳送資料,但是接收端在處理別的事(可能正處於高負荷的狀態無法接收任何資料),而且此資料包並無重要意義,這樣導致此包丟失又會觸發重發機制,令網路流量無端浪費。

(2)解決方法

為了防止此現象發生,TCP提供一種機制可以讓傳送端根據接收端的實際接收能力控制傳送的資料量。這就是“控制流”。

(3)具體操作

接收端想傳送端通知自己可以接收資料的大小,傳送端傳送時不會超過這個限度的資料,該大小限制被稱為視窗大小。

TCP首部中專門有一個欄位用來通知視窗大小。接收端將自己可接收的緩衝區大小放入欄位中並通知傳送端。此值越大代表網路的吞吐量越高。

當快取區一旦面臨資料溢位時,視窗大小的值也會隨之被設定成一個更小的值傳送給傳送端,從而控制資料傳送量。也就是說,傳送端會根據接收端的指示,對傳送資料量進行控制。這就形成了一個完整的TCP流控制。

檢視下圖示例:

這裡寫圖片描述

如上圖所示,當接收端收到從3001號開始的資料段後,緩衝區已滿,需要暫時停止接收資料。之後在收到傳送視窗更新通知後通訊才得以繼續進行。如果此視窗更新通知在傳送途中丟失,可能導致無法繼續通訊。為避免此類問題產生,傳送端主機會時不時傳送一個叫做“視窗探測”的資料段,此資料段僅含一個位元組以獲取最新的視窗大小資訊。

3. Zero Window

通過以上講解後,可知傳送端可以傳送資料動態修改“滑動視窗”的大小,注意其值是可以為0的!那這樣是否意味著傳送端就不發資料了?確實如此,接收端都已經表示自己無力接收了,因此不會再發,類似於“Window Closed”

可是過了一會兒,接收端如何通知傳送端視窗可用了呢?

解決這個問題,TCP使用了Zero Window Probe技術,縮寫為ZWP。即傳送端在視窗變成0後,會發ZWP的包給接收端,讓接收端來ack他的Window尺寸,一般這個值會設定成3次,第次大約30-60秒(不同的實現可能會不一樣)。如果3次過後還是0的話,有的TCP實現就會發RST把連結斷了。

注意:只要有等待的地方都可能出現DDoS攻擊,Zero Window也不例外,一些攻擊者會在和HTTP建好鏈發完GET請求後,就把Window設定為0,然後服務端就只能等待進行ZWP,於是攻擊者會併發大量的這樣的請求,把伺服器端的資源耗盡。

三. 擁塞控制(Congestion Control)

有了TCP的視窗控制,收發端之間不再以一個數據段為單位傳送確認應答,也能夠連續傳送大量資料包。但是剛開始通訊就傳送大量資料會引發其它問題。計算機網路處於一個共享的環境,因此有可能因為其他主機之間的通訊使得網路擁堵,此時突然傳送一個大量資料,可能導致整個網路癱瘓。

擁塞控制主要是四個演算法:

  • 慢啟動
  • 擁塞避免
  • 擁塞發生
  • 快速恢復

1. 慢啟動(Slow Start)

首先,為了在傳送端調節待發送的資料量,定義了“擁塞視窗”的概念,在慢啟動時將其設為1個數據段(IMSS)傳送資料,之後每收到一次確認應答(ACK),擁塞視窗的值就加1。在傳送資料段時,將擁塞視窗的大小與接收端通知的視窗大小做比較,以較小值為標準,傳送比其還要小的資料量。

根據以上機制,可有效減少通訊開始時連續發包導致的網路擁堵,還可以避免網路擁塞的情況。

慢啟動的演算法如下:(cwnd全稱Congestion Window)

  • 連線建好的開始先初始化cwnd = 1,表明可以傳一個MSS大小的資料。
  • 每當收到一個ACK,cwnd++; 呈線性上升
  • 每當過了一個RTT,cwnd = cwnd*2; 呈指數讓升
  • 還有一個ssthresh(slow start threshold),是一個上限,當cwnd >= ssthresh時,就會進入“擁塞避免演算法”(後面會說這個演算法)

所以,我們可以看到,如果網速很快的話,ACK也會返回得快,RTT也會短,那麼,這個慢啟動就一點也不慢。下圖說明了這個過程

這裡寫圖片描述

2. 擁塞避免演算法(Congestion Avoidance)

前面慢啟動的演算法第四步中的ssthresh(slow start threshold)是一個上限,當cwnd >= ssthresh時,就會進入“擁塞避免演算法”。一般來說ssthresh的值是65535,單位是位元組,當cwnd達到這個值時後,演算法如下:

  • 收到一個ACK時,cwnd = cwnd + 1/cwnd
  • 當每過一個RTT時,cwnd = cwnd + 1

這樣就可以避免增長過快導致網路擁塞,慢慢的增加調整到網路的最佳值。很明顯,是一個線性上升的演算法。

3. 擁塞狀態時的演算法

在講解超時重傳機制中提到TCP面臨丟包時,有以下兩個問題:

a)等到RTO 超時,重傳資料包。TCP認為這種情況太糟糕,反應也很強烈:

sshthresh =  cwnd /2
cwnd 重置為 1
進入慢啟動過程

b) Fast Retransmit演算法,也就是在收到3個duplicate ACK時就開啟重傳,而不用等到RTO超時,TCP Tahoe的實現和RTO超時一樣。TCP Reno的實現是:

cwnd = cwnd /2
sshthresh = cwnd
進入快速恢復演算法——Fast Recovery

上面我們可以看到RTO超時後,sshthresh會變成cwnd的一半,這意味著,如果cwnd<=sshthresh時出現的丟包,那麼TCP的sshthresh就會減了一半,然後等cwnd又很快地以指數級增漲爬到這個地方時,就會成慢慢的線性增漲。我們可以看到,TCP是怎麼通過這種強烈地震盪快速而小心得找到網站流量的平衡點的。

4. 快速恢復演算法(Fast Recovery)

快速重傳和快速恢復演算法一般同時使用。快速恢復演算法是認為,你還有3個Duplicated Acks說明網路也不那麼糟糕,所以沒有必要像RTO超時那麼強烈。 注意,正如前面所說,進入Fast Recovery之前,cwnd 和 sshthresh已被更新:

cwnd = cwnd /2
sshthresh = cwnd

真正的Fast Recovery演算法如下:

  • cwnd = sshthresh + 3 * MSS (3的意思是確認有3個數據包被收到了)
  • 重傳Duplicated ACKs指定的資料包
  • 如果再收到 duplicated Acks,那麼cwnd = cwnd +1
  • 如果收到了新的Ack,那麼,cwnd = sshthresh ,然後就進入了擁塞避免的演算法了。

仔細思考一下你會發現上面這個演算法也有問題:它依賴於3個重複的Acks。

注意:3個重複的Acks並不代表只丟了一個數據包,很有可能不止一個。但此演算法只會重傳一個,而剩下的那些包只能等到RTO超時,從而導致一種可怕的現象:超時一個視窗就減半一下,多個超時會超成TCP的傳輸速度呈級數下降,而且也不會觸發Fast Recovery演算法了。

(還有一些其他演算法,在此只著重選取幾個重要的介紹,其餘的讀者可自行了解學習)

四. TCP和UDP的區別

1. UDP(User Datagram Protocol)

使用者資料包協議,UDP不提供複雜的控制機制,利用IP提供面向無連線的通訊服務。即使是出現網路擁堵的情況下,UDP也無法進行流量控制等避免網路擁塞的行為,同樣出現丟包情況,UDP也不負責重發,也沒有當包的到達順序混亂糾正功能。如果需要這些細節控制,只能交由UDP的應用程式去處理。(UDP有點類似於使用者說啥就聽啥的機制)

面向報文傳輸,應用層交給UDP多長的報文,UDP就照樣傳送,即一次傳送一個報文。因此,應用程式必須選擇合適大小的報文。

  • 若報文太長,則IP層需要分片,降低效率。
  • 若報文太短,浪費資源。

UDP對應用層交下來的報文,既不合並,也不拆分,而是保留這些報文的邊界。即應用層交給UDP多長的報文,UDP就照樣傳送,即一次傳送一個報文。

因此它有以下特點:

  • 傳輸資料之前源端和終端不建立連線,當它想傳送時就簡單地去抓取來自應用程式的資料,並儘可能快的把它扔到網路上
  • 由於傳輸資料不建立連線,因此也就不需要維護連線狀態,包括收發狀態等,因此一臺服務機可同時向多個客戶機傳輸相同的訊息
  • 在傳送端,UDP傳送資料的速度僅僅是受應用程式生成資料的速度、計算機的能力和傳輸頻寬的限制
  • 在接收端,UDP把每個訊息段放在佇列中,應用程式每次從佇列中讀一個訊息段
  • UDP資訊包的標題很短,只有8個位元組,相對於TCP的20個位元組資訊包的額外開銷很小
  • 吞吐量不受擁擠控制演算法的調節,只受應用軟體生成資料的速率、傳輸頻寬、源端和終端主機效能的限制
  • UDP是面向報文的。傳送方的UDP對應用程式交下來的報文,在新增首部後就向下交付給IP層。既不拆分,也不合並,而是保留這些報文的邊界,因此,應用程式需要選擇合適的報文大小。

優點

  • 傳輸速率快:傳輸資料前,不需要像TCP一樣建立連線;傳輸資料時,沒有確認、視窗、重傳、擁塞控制等機制。
  • 較安全:由於沒有了TCP的一些機制,被攻擊者利用的漏洞就少了

缺點

  • 不可靠,不穩定:由於沒有了TCP的機制,在資料傳輸時如果網路不好,很可能丟包

2. 區別

其實在真正理解了TCP相關特徵屬性後,兩者的區別顯而易見就出來了,簡單的總結如下:

TCP UDP
面向位元組流 面向報文
一對一 可以一對一,一對多
面向有連結的通訊服務 面向無連線的通訊服務
速度快 速度慢
提供可靠的通訊傳輸 不可靠,會丟包
保證資料包順序 不保證
有流量控制,擁塞控制 沒有
資料無邊界 資料有邊界
報頭至少20位元組 報頭8位元組

3. 常見問題

(1)為什麼UDP比TCP快

因為TCP中連線需要三次握手,斷開連線需要四次握手,傳輸過程中還有擁塞控制,控制流量等機制。

(2)為什麼TCP比UDP可靠

  • TCP是面向有連線的,建立連線之後才傳送資料;而UDP則不管對方存不存在都會發送資料。
  • TCP有確認機制,接收端每收到一個正確包都會迴應給傳送端。超時或者資料包不完整的話傳送端會重傳。UDP沒有。因此可能丟包。

(3)什麼時候使用TCP

當對網路通訊質量有要求的時候,比如:整個資料要準確無誤的傳遞給對方,這往往用於一些要求可靠的應用,比如HTTP、HTTPS、FTP等傳輸檔案的協議,POP、SMTP等郵件傳輸的協議。

例如日常生活中使用TCP協議的應用如下: 瀏覽器,用的HTTP FlashFXP,用的FTP Outlook,用的POP、SMTP Putty,用的Telnet、SSH QQ檔案傳輸

(4)什麼時候應該使用UDP

當對網路通訊質量要求不高的時候,要求網路通訊速度能儘量的快,這時就可以使用UDP。

比如日常生活中使用UDP協議的應用如下: QQ語音 QQ視訊 TFTP

(5)TCP無邊界,UDP有邊界

  • TCP無邊界:客戶端分多次傳送資料給伺服器,若伺服器的緩衝區夠大,那麼伺服器端會在客戶端傳送完之後一次性接收過來,所以是無邊界的。

  • UDP有邊界:客戶端每傳送一次,伺服器端就會接收一次,也就是說傳送多少次就會接收多少次,因此是有邊界的。

五. 面試問題

1. 在瀏覽器輸入一個URL按下回車後,其流程是?

分析:如果要連線到遠端伺服器,首先要知道伺服器的IP地址和埠,然後傳送請求到伺服器,伺服器再響應。因此定址和如何建立連線是關鍵。

步驟:

(1)進行定址:若瀏覽器快取中存有URL的對應IP,則直接查詢IP;否則訪問DNS(Domain Name System)進行定址(Domain Name Resolution)。

(2) DNS或者URL Cache返回網頁伺服器的IP地址。

(3)瀏覽器與網頁伺服器進行三次握手建立TCP連線。由於是網頁瀏覽服務,故連線到伺服器的80埠。

(4)瀏覽器與伺服器建立HTTP會話(Session),接收來自伺服器的HTTP資料。

(5)瀏覽器解析HTTP資料,在本地視窗內渲染並顯示網頁。

(6)當瀏覽器頁面被關閉時,終止HTTP會話並關閉連線。

2. 設計一個可靠的UDP,如何做?

分析: “可靠”是指接收端能夠將收到的資料情況反饋給傳送端。因此完全可以參照可靠的傳輸協議—–TCP,引入ACK、Flow Cotrol、Congestion Control等模組。可靠的UDP核心在於反饋機制,以下是幾種實現方式。

解答:(由於可靠性要求在接收端能夠恢復資料包的順序,故傳送端每個資料包都需要序列號。這裡著重討論反饋機制)

(1)最樸素的ACK傳送:傳送端沒傳送一個數據包,都需要接收端返回ACK,一旦超時,傳送端重新發送資料包,直到該資料包被接收端ACK。該方法效率不高,因為之後的所以資料包都有可能被當前資料包block,並且每次返回ACK增加了overHead。

(2)Block/bit map ACK:

傳送端傳送一批資料包,例如32個,編號是0~31.接收端發回的ACK中用32bit(4byte)的bit map表示收到哪些資料包,傳送端再一次性重發所有未被收到的資料包。該方法能夠更加充分地利用頻寬,在傳送端一次性傳輸更多資料,但缺點是傳送、接收端需要更深的buffer來暫存傳輸的所有資料。

(3)ACK last packet

傳送端可以在傳送最後一個數據包時要求接收端反饋ACK,並重發丟失的資料包。好處是可以減少由ACK造成的 data overhead,但需要buffer暫存資料。

最佳方法:

事實上,可以結合方法2、3,在每一批資料包的最後一個置位request ACK flag,要求接收端返回bit map ACK。更進一步,可以根據丟包率及延遲,估計網路狀態,動態調整bit map大小:網路狀態好時,用更大的bit map,即同時傳送更多資料。否則減少傳送資料量。這種對網路狀況的自適應相當於實現了Congestion Control。

3. 實時視訊會議應用應選擇UDP還是TCP?

分析:本題的關鍵在於比較TCP和UDP的特點,並且根據此場景選擇。

TCP的重傳機制特點,會增加延遲,所以不適合此場景。其次視訊音訊編碼本身可以容忍資料出錯甚至資料丟失,因此並不需要TCP進行可靠傳輸。當某一視訊幀出現丟包,可以直接跳過。一旦出現網路堵塞情況,傳送端應主動丟棄一部分資料,因為即使被髮送到接收端也都“過期”了,不會被解碼顯示。

不過即使採用UDP,也需要實現TCP某些模組,例如Flow Control、Congestion Control 來判斷接收端的播放情況和網路情況,也需要反饋機制來判斷接收端的接收狀況。儘管當前場景不需要ACK每個資料包,但接收端可以反饋當前收到最新完整視訊幀的序號,這樣即使丟包,傳送端可以接收端收到最新視訊幀為基礎,壓縮後繼的視訊。

4. 網路中常見的ping 命令是什麼協議?

分析使用“ping”命令來測試兩臺主機之間TCP/IP通訊是否正常,其實“ping”命令的原理就是向對方主機發送UDP資料包,然後對方主機確認收到資料包,如果資料包是否到達的訊息及時反饋回來,那麼網路就是通的。

書面解答: ping.exe的原理是向指定的IP地址傳送一定長度的資料包,若指定IP地址存在會返回同樣大小的資料包,若在特定時間內沒有返回,就是“超時”,即指定IP地址不存在。由於ping使用的ICMP協議,有些防火牆軟體會平米ICMP協議,所以ping結果只能作為參考,ping不通不一定代表對方IP不存在。

(ping命令是一個非常有用的網路命令,大家常用它來測試網路連通情況。但同時它也是一把“雙刃劍”,別人使用ping命令能探測到你計算機上的很多敏感資訊,造成不安全。為了安全,防止ping的方法也有很多,比如防火牆,又比如建立一個禁止所有計算機ping本機IP地址的安全策略。)

ICMP協議: ICMP是“Internet Control Message Protocol”(Internet控制訊息協議)的縮寫。它是
TCP/IP協議族的一個子協議,用於在IP主機、路由器之間傳遞控制訊息。控制訊息是指網路通不通、主機是否可達、路由是否可用等網路本身的訊息。這些控制訊息雖然並不傳輸使用者資料,但是對於使用者資料的傳遞起著重要的作用。

5. 如何編寫Socket套接字?(擴充套件)

分析:Socket相當於進行網路通訊兩端的插座,只要對方的Socket和自己的Socket有通訊聯接,雙方就可以傳送和接收資料了。其定義類似於檔案控制代碼的定義。

  • 如果你要編寫的是一個服務程式,那麼先呼叫socket()建立一個套接字,呼叫bind()繫結IP地址和埠,然後啟動一個死迴圈,迴圈中呼叫accept()接受連線。對於每個接受的連線,可以啟動多執行緒方式進行處理,線上程中呼叫send()、recv()傳送和接收資料。
  • 如果你要編寫的是一個客戶端程式,那麼就簡單多了。先呼叫socket()建立一個套接字,然後呼叫connect()連線伺服器,之後就是呼叫send()、recv()傳送和接收資料了。

解答:

  • 伺服器端程式編寫:

    • 呼叫 ServerSocket(int port) 建立一個伺服器端套接字,並繫結到指定埠上。
    • 呼叫 accept(),監聽連線請求,則接收連線,返回通訊套接字。
    • 呼叫Socket類的 getOutStream()getInputStream()獲取輸出流和輸入流,開始網路資料的傳送和接收。
    • 關閉通訊套接字 Socket.close()
  • 客戶端程式編寫:

    • 呼叫 Socket() 建立一個流套接字,並連線到伺服器端。
    • 呼叫Socket類的 getOutputStream()getInputStream()獲取輸出流和輸入流,開始網路資料的傳送和接收。
    • 關閉通訊套接字 Socket.close()

6. 埠概念(擴充套件)

在網路技術中,埠(Port)大致有兩種意思:

  • 一是物理意義上的埠,比如,ADSL MODEM、集線器、交換機、路由器用於連線其他網路裝置的介面;
  • 二是邏輯意義上的埠,一般是指TCP/IP協議中的埠,埠號的範圍為0~65535,比如用於瀏覽網頁服務的80埠,用於FTP服務的21埠。

這裡將主要介紹邏輯意義上的埠,邏輯意義上的埠有多種分類標準,下面將介紹兩種常見的分類:

(1)按埠號分佈劃分

  • 知名埠(Well-Known Ports):即眾所周知的埠號,範圍為0~1023,這些埠號一般固定分配給一些服務。

比如21埠分配給FTP服務,25埠分配給SMTP(簡單郵件傳輸協議)服務,80埠分配給HTTP服務。

  • 動態埠(Dynamic Ports):範圍為1024~65535,這些埠號一般不固定分配給某個服務,也就是說許多服務都可以使用這些埠。只要執行的程式向系統提出訪問網路的申請,那麼系統就可以從這些埠號中分配一個供該程式使用。比如1024埠就是
    分配給第一個向系統發出申請的程式。在關閉程式程序後,就會釋放所佔用的埠號。

(2)按協議型別劃分

按協議型別劃分,可以分為TCP、UDP、IP和ICMP(Internet控制訊息協議)等埠。下面主要介紹TCP和UDP埠:

  • TCP埠:即傳輸控制協議埠,需要在客戶端和伺服器之間建立連線,這樣可以提供可靠的資料傳輸。常見的包括FTP服務的21埠,Telnet服務的23埠,SMTP服務的25埠,以及HTTP服務的80埠等等。
  • UDP埠:即使用者資料包協議埠,無須在客戶端和伺服器之間建立連線,安全性得不到保障。常見的有DNS服務的53埠,SNMP(簡單網路管理協議)服務的161埠,QQ使用的8000和4000埠等等。

以上內容將重點主要放在TCP協議解析上,深究下來你會發現TCP協議並不簡單,其中涉及到的特性和相關的演算法比較多,此篇內容只是偏白話文的方式進行了總結,可能有許多地方還不夠詳細,所以還是推薦各位閱讀TCP的大佬之作《詳解TCP/IP》,更為權威,其中的講解更加學術深入。共勉~

在此宣告:此篇總結TCP博文參考資料如下:
RTT、滑動視窗、擁塞處理
《圖解TCP/IP》
《詳解TCP/IP》
《程式設計師面試白皮書》
《程式設計師面試寶典》

若有錯誤,虛心指教~