TCP和UDP總結及常見面試題

(7條消息) [計算機網絡] TCP和UDP總結及常見面試題_努力變得不菜的菜雞的博客-CSDN博客

1 TCP和UDP區別

  • TCP是面向連接的,UDP是面向無連接的
  • TCP是可靠的,UDP不是可靠的(也就是說,通過TCP連接傳送的數據,無差錯,不丟失,不重複,且按序到達;UDP盡最大努力交付,即不保證可靠交付)
  • TCP是面向字節流的,UDP是面向報文的
  • TCP只支持點對點通信,UDP支持一對一,一對多,多對一,多對多的通信模式
  • TCP首部開銷(20字節)比UDP的首部開銷(8個字節)要大
  • TCP保證數據正確性,UDP可能丟包
  • TCP保證數據順序,UDP不保證

2 UDP
TCP 和 UDP 是傳輸層的兩個協議

我們來看一下 UDP 的包頭

 

 

 

由上圖可以看出,UDP 除了端口號,基本啥都沒有了。如果沒有這兩個端口號,數據就不知道該發給哪個應用。

所以 UDP 就像一個小孩子,特別簡單,有如下三個特點

UDP 的特點

  • 溝通簡單,不需要大量的數據結構,處理邏輯和包頭字段
  • 輕信他人。它不會建立連接,但是會監聽這個地方,誰都可以傳給它數據,它也可以傳給任何人數據,甚至可以同時傳給多個人數據。
  • 愣頭青,做事不懂變通。不會根據網絡的情況進行擁塞控制,無論是否丟包,它該怎麼發還是怎麼發
  • 因爲 UDP 是"小孩子",所以處理的是一些沒那麼難的項目,並且就算失敗的也能接收。基於這些特點的話,UDP 可以使用在如下場景中

UDP 的主要應用場景

  • 需要資源少,網絡情況穩定的內網,或者對於丟包不敏感的應用,比如 DHCP 就是基於 UDP 協議的。
  • 不需要一對一溝通,建立連接,而是可以廣播的應用。因爲它不面向連接,所以可以做到一對多,承擔廣播或者多播的協議。
  • 需要處理速度快,可以容忍丟包,但是即使網絡擁塞,也毫不退縮,一往無前的時候

基於 UDP 的幾個例子

  • 直播。直播對實時性的要求比較高,寧可丟包,也不要卡頓的,所以很多直播應用都基於 UDP 實現了自己的視頻傳輸協議
  • 實時遊戲。遊戲的特點也是實時性比較高,在這種情況下,採用自定義的可靠的 UDP 協議,自定義重傳策略,能夠把產生的延遲降到最低,減少網絡問題對遊戲造成的影響
  • 物聯網。一方面,物聯網領域中斷資源少,很可能知識個很小的嵌入式系統,而維護 TCP 協議的代價太大了;另一方面,物聯網對實時性的要求也特別高。比如 Google 旗下的 Nest 簡歷 Thread Group,推出了物聯網通信協議 Thread,就是基於 UDP 協議的。

 

3 TCP

首先是 TCP 的包頭格式

TCP 的包頭有哪些內容,分別有什麼用

  • 首先,源端口和目標端口是不可少的。
  • 接下來是包的序號。主要是爲了解決亂序問題。不編好號怎麼知道哪個先來,哪個後到
  • 確認序號。發出去的包應該有確認,這樣能知道對方是否收到,如果沒收到就應該重新發送,這個解決的是不丟包的問題
  • 狀態位。SYN 是發起一個鏈接,ACK 是回覆,RST 是重新連接,FIN 是結束連接。因爲 TCP 是面向連接的,因此需要雙方維護連接的狀態,這些狀態位的包會引起雙方的狀態變更
  • 窗口大小,TCP 要做流量控制,需要通信雙方各聲明一個窗口,標識自己當前的處理能力。

通過對 TCP 頭的解析,我們知道要掌握 TCP 協議,應該重點關注以下問題:

  • 順序問題
  • 丟包問題
  • 連接維護
  • 流量控制
  • 擁塞控制

4 TCP 的三次握手
所有的問題,首先都要建立連接,所以首先是連接維護的問題

TCP 的建立連接稱爲三次握手,可以簡單理解爲下面這種情況:

A:您好,我是 A
B:您好 A,我是 B
A:您好 B

至於爲什麼是三次握手,總結的話就是通信雙方全都有來有回

對於 A 來說它發出請求,並收到了 B 的響應,對於 B 來說它響應了 A 的請求,並且也接收到了響應。

TCP 的三次握手除了建立連接外,主要還是爲了溝通 TCP 包的序號問題。

 

 

 

 

 

 

 

 

 

客戶端等待完2MSL之後,結束TIME-WAIT階段,進入CLOSED階段,由此完成“四次揮手”。

後“兩次揮手”既讓客戶端知道了服務器端準備好釋放連接了,也讓服務器端知道了客戶端了解了自己準備好釋放連接了。
於是,可以確認關閉服務器端到客戶端方向上的連接了,由此完成“四次揮手”。

與“三次揮手”一樣,在客戶端與服務器端傳輸的TCP報文中,雙方的確認號Ack和序號Seq的值,都是在彼此Ack和Seq值的基礎上進行計算的,這樣做保證了TCP報文傳輸的連貫性,一旦出現某一方發出的TCP報文丟失,便無法繼續"揮手",以此確保了"四次揮手"的順利完成。

6 累計確認
TCP如何實現可靠傳輸?

首先爲了保證時序性,每個包都有一個ID。在建立連接的時候會商定起始ID是什麼,然後按照ID一個個發送,爲了保證不丟包,需要對發送的包都要進行應答,當然,這個應答不是一個一個來的,而是會應答某個之前的ID,表示都收到了,這種模式稱爲累計應答或累計確認。

爲了記錄所有發送的包和接收的包,TCP需要發送端和接收段分別緩存這些記錄,
發送端的緩存裏是按照包的ID一個個排序,根據處理的情況分爲四個部分:

(1)發送並且確認的
(2)發送尚未確認的
(3)沒有發送等待發送的
(4)沒有發送並且暫時不會發送的
這裏的第三部分和第四部分就屬於流量控制的內容
在TCP裏,接收端會給發送端報一個窗口大小,叫Advertised window。這個窗口應該等於上面的第一部分加第二部分,超過這個窗口,接收端就接收不過來了,就不能發送了
於是,發送端要保持下面的數據結構

對於接收端,它的裏面的內容要簡單一些

(1)接收並且確認過的
(2)還沒接收,但是馬上 就能接收的
(3)還沒接收,但也無法接收的
接收端對應的數據結構:

 

 

8 擁塞控制的問題
擁塞控制也是通過窗口的大小來控制的,但是檢測網絡滿不滿是個挺難的事情,所以TCP發送包經常被比喻成往水管裏灌水,所以擁塞控制就是在不堵塞,不丟包的情況下儘可能的發揮帶寬。

水管有粗細,網絡有帶寬,即每秒鐘能發送多少數據;水管有長度,端到端有時延。
理想情況下,水管裏面的水 = 水管粗細 * 水管長度,
對於網絡上,通道的容量 = 帶寬 * 往返時延。

如果我們設置發送窗口,使得發送但未確認的包爲通道的容量,就能撐滿整個管道。

 

 

如圖所示,假設往返時間爲 8 秒,去 4 秒,回 4 秒,每秒發送一個包,已經過去了 8 秒,則 8 個包都發出去了,其中前四個已經到達接收端,但是 ACK 還沒返回,不能算髮送成功,5-8 後四個包還在路上,還沒被接收,這個時候,管道正好撐滿,在發送端,已發送未確認的 8 個包,正好等於帶寬,也即每秒發送一個包,也即每秒發送一個包,乘以來回時間 8 秒。

如果在這個基礎上調大窗口,使得單位時間可以發送更多的包,那麼會出現接收端處理不過來,多出來的包就會被丟棄,這個時候,我們可以增加一個緩存,但是緩存裏面的包4秒內肯定達不到接收端了,它的缺點會增加時延,如果時延達到一定程度就會超時重傳

TCP擁塞控制主要用來避免兩種情況,包丟失和超時重傳,一旦出現了這些現象說明發送的太快了,要慢一點。
具體的方法就是發送端慢啓動, 比如倒水,剛開始倒的很慢,漸漸變快。然後設定一個閾值,當超過這個值的時候就要慢下來
慢下來還是在增長,這時候就可能水滿則溢,出現擁塞,需要降低倒水的速度,等水慢慢滲下去。

擁塞的一種表現是丟包,需要超時重傳,這個時候,採用快速重傳算法,將當前速度變爲一般,所以速度還是在比較高的值,也沒有一夜回到解放前。

tcp採用累積確認(累積ack)機制,一個窗口內的數據接收完全才進行發回一個ack.

9 面試問題
NO1 --- TCP和UDP的區別

  • TCP是面向連接的,UDP是面向無連接的
  • TCP是可靠的,UDP不是可靠的
  • (也就是說,通過TCP連接傳送的數據,無差錯,不丟失,不重複,且按序到達;UDP盡最大努力交付,即不保證可靠交付)
  • TCP是面向字節流的,UDP是面向報文的
  • TCP只支持點對點通信,UDP支持一對一,一對多,多對一,多對多的通信模式
  • TCP首部開銷(20字節)比UDP的首部開銷(8個字節)要大
  • TCP保證數據正確性,UDP可能丟包
  • TCP保證數據順序,UDP不保證

NO2 --- 什麼是面向連接,什麼是面向無連接

在互通之前,面向連接的協議會先建立連接,如 TCP 有三次握手,而 UDP 不會

  • **面向連接:**是指通信百雙方在通信時,要事先建立一條通信線路,其有三個過程:建立連接、使用連接和釋放連接。電話系統度是一個面向連接的模式,撥號、通知話、掛機;TCP協議就是一種面向連接的協議。
  • **面向無連接:**是指通信雙方不需要事先建立一條通信線路道,而是把每個帶有目的地址的包(報文分組)送到線路上,由系統自主選定路線進行傳輸。郵專政系統是一個無連接的模式,天羅地網式的選擇路線,天女散屬花式的傳播形式;IP、UDP協議就是一種無連接協議。

NO3 --- TCP爲什麼是可靠連接

通過TCP連接傳輸的數據無差錯,不丟失,不重複,且按順序到達
TCP報文頭裏面的序號能使TCP的數據按序到達
報文頭裏面的確認序號能保證不丟包,累計確認及超時重傳機制
TCP擁有流量控制及擁塞控制的機制
NO4 --- 爲什麼要進行三次握手?兩次不可以嗎?
1
爲了防止服務器端開啓一些無用的連接增加服務器開銷以及防止已失效的連接請求報文段突然又傳送到了服務端,因而產生錯誤。

  • 第一種情況:防止服務器端開啓一些無用的連接增加服務器開銷

由於網絡傳輸是有延時的(要通過網絡光纖和各種中間代理服務器),在傳輸的過程中,比如客戶端發起SYN = 1 創建連接的請求(第一次握手)。
如果服務器就直接創建了這個連接並返回包含SYN,ACK和Seq等內容的數據包給客戶端,這個數據包因爲網絡傳輸的原因丟失了,丟失之後客戶端一直沒接收到服務器返回的數據包。
客戶端可能設置了一個超時時間,時間到了就關閉創建連接的請求。再次重新發出創建連接的請求,而服務器端是不知道的,如果沒有第三次握手告訴服務器端客戶端收到了服務器傳輸數據的話,服務器端是不知道客戶端有沒有收到服務器端發送的消息的。
這樣的話,沒有給服務器端一個創建還是關閉連接端口的請求,服務器端的端口就一直開着,等到客戶端因超時重新發出請求時,服務器端會重新再開一個端口連接,那麼上一個數據請求的端口就一直開着,長此以往,這樣開着的端口就多了,就會造成服務器開銷的嚴重浪費。

  • 第二種情況:防止已失效的連接請求報文段突然又傳送到了服務端,因而產生錯誤

已經失效的客戶端發出的請求信息,由於某種原因傳輸到了服務器端,服務器端以爲是客戶端發出的有效請求,接收後產生錯誤。
所以我們需要“第三次握手” 來確認這個過程,讓客戶端和服務器端都能及時察覺到因爲網絡等一些問題導致的連接創建失敗,這樣服務器端的端口就可以關閉了而不用一直等待。

也可以這樣理解

  • “第三次握手”是客戶端向服務器發送數據,這個數據就是要告訴服務器,客戶端有沒有收到服務器“第二次握手”時傳過去的數據。若發送的這個數據是“收到了”的信息,接收後服務器就正常建立TCP連接,否則建立TCP連接失敗,服務器關閉連接端口。由此減少服務器開銷和防止接收到失效請求發生的錯誤。

NO5 --- 爲什麼“握手是三次,“揮手””卻需要四次?
1
TCP建立連接時之所以只需要“三次握手”,是因爲在第二次“握手” 過程中,服務器端發給客戶端的TCP報文是以SYN與ACK作爲標識位的。
SYN是請求連接標誌,表示服務器端同意建立連接;ACK是確認報文,表示告訴客戶端,服務器端收到了它的請求報文
即SYN建立連接報文與ACK確認接收報文是在同一次“握手”當中傳輸的,所以“三次握手”不多也不好,雙方剛好信息互通。

TCP釋放連接時之所以需要“四次握手”,是因爲FIN釋放連接報文與ACK確認接收報文是分別由第二次和第三次“握手”傳輸的。
爲何建立連接時一起傳,釋放連接時卻要分開傳輸?
建立連接時,被動房服務器端結束CLOSED階段進入“握手”階段並不需要任何準備,可以直接返回SYN和ACK報文,開始建立連接。
釋放連接時,被動方服務器,突然收到主動方客戶端釋放連接的請求並不能立即釋放連接,因爲還有必要的數據需要進行處理,所以服務器先返回ACK確認收到報文,經過CLOSED-WAIT階段準備好釋放連接之後,才能返回FIN釋放連接報文。

所以是,“三次握手”,“四次揮手”。

NO6 --- 爲什麼客戶端在TIME-WAIT階段要等2MSL?

爲的是確認服務器端是否收到客戶端發出的ACK確認報文

當客戶端發出最後的ACK確認報文時,並不能確定服務器就能夠收到該端報文。
所以在客戶端發送完ACK確認報文之後,會設置一個時長爲2MSL的計時器。
MSL指的是Maximum Segment Lifetime:一段TCP報文在傳輸過程中的最大生命週期。
2MSL即時服務器發出FIN報文和客戶端發出的ACK確認報文所能保持有效的最大時長。

1)服務器端在1MSL內沒有收到客戶端發出的ACK確認報文,就會再次向客戶端發出FIN報文;
2)如果客戶端在2MSL內,再次收到了來自服務器端的FIN報文,說明服務器端由於各種原因沒有接收到客戶端發出的ACK確認報文。客戶端再次向服務器端發出ACK確認報文,計時器重置,重新開始2MSL的計時;
3)否則客戶端在2MSL內沒有再次收到來自服務器端的FIN報文,說明服務器端正常接收了ACK確認報文,客戶端可以進入CLOSED階段,完成“四次揮手”。

所以,客戶端要經歷時長爲2SML的TIME-WAIT階段;這也是爲什麼客戶端比服務器端晚進入CLOSED階段的原因

NO7 --- TCP協議如何來保證傳輸的可靠性

TCP提供一種面向連接的、可靠的字節流服務,
其中,面向連接意味着兩個使用TCP的應用(通常是一個客戶一個服務器)在彼此交換數據之前先見一個一個TCP連接。
在一個TCP連接中,僅有兩方進行彼此通信,字節流服務意味着兩個應用程序通過TCP鏈接交換8bit字節構成的字節流,TCP不在字節流中插入記錄標識符。
對於可靠性,TCP通過以下方式進行保證:

  • 數據包校驗:目的是檢測數據在傳輸過程中的任何變化,若檢測出包有錯,則丟棄褒文段並且不給出響應,這時TCP發送數據端超時後會重發數據
  • 對失序數據包重新排序:既然TCP報文段作爲IP數據報來傳輸,而IP數據報的到達可能會失序,因此TCP報文段的到達也可能會失序。TCP將對失序數據進行重排序,然後才交給應用層。
  • 丟棄重複數據:對於重複數據,能夠丟棄重複數據
  • 應答機制: 當TCP收到發自TCP連接另一端的數據,它將發送一個確認。這個確認不是立即發送,通常將推遲幾分之一秒
  • 超時重發: 當TCP發出一個段後,它啓動一個定時器,等待目的端確認收到這個報文段。如果不能及時收到一個確認,將重發這個報文段
  • 流量控制 TCP連接的每一方都有固定大小的緩衝空間。TCP的接收端只允許另一端發送接收端緩衝區所能接納的數據,這可以防止較快主機致使較慢主機的緩衝區溢出,這就是流量控制。TCP使用的流量控制協議是可變大小的滑動窗口協議。

面向字節流:

創建一個TCP的socket, 同時在內核中創建一個發送緩衝區和一個接收緩衝區;
另一方面, TCP的一個連接, 既有發送緩衝區, 也有接收緩衝區, 那麼對於這一個連接, 既可以讀數據, 也可以寫數據. 這個概念叫做 全雙工 。

  1. 調用write時, 數據會先寫入發送緩衝區中;
  2. 如果發送的字節數太長, 會被拆分成多個TCP的數據包發出; 如果發送的字節數太短, 就會先在緩衝區裏等待, 等到緩衝區長度差不多了, 或者其他合適的時機發送出去;
  3. 接收數據的時候, 數據也是從網卡驅動程序到達內核的接收緩衝區;
  4. 然後應用程序可以調用read從接收緩衝區拿數據;

TCP重傳的次數和間隔時間

第一次發送後所設置的超時時間實際上爲1.5秒,此後該時間在每次重傳時增加一倍,一直到64秒,採用的是指數退避算法。一共重傳12次,大約9分鐘才放棄重傳,該時間在目前的TCP實現中是不可變的,Solaris2.2允許管理者改變這個時間,tcp_ip_abort_interval變量。且其默認值爲兩分鐘,而不是最常用的9分鐘。

TCP粘包問題

tcp作爲面向流的協議,不存在“粘包問題”,這個大家已經說清楚了,我補充一下國內開發人員說“粘包問題”的時候,到底想說什麼?

首先,什麼叫“包”?

在基於tcp開發應用的語境下,其實有兩種“包”,其一是tcp在傳輸的時候封裝的報文,分爲包頭和負載,其二是應用開發者在應用層封裝的報文結構。

第二,什麼叫“粘”?這裏同樣有兩種含義。

其一是指,由於tcp是面向流的協議,不會按照應用開發者的期望保持send輸入數據的邊界,導致接收側有可能一下子收到多個應用層報文,需要應用開發者自己分開,有些人覺得這樣不合理(那你爲啥不用udp),起了個名叫“粘包”。

其二是指,用戶數據被tcp發出去的時候,存在多個小尺寸數據被封裝在一個tcp報文中發出去的可能性。這種“粘”不是接收側的效果,而是由於Nagle算法(或者TCP_CORK)的存在,在發送的時候,就把應用開發者多次send的數據,“粘”在一個tcp報文裏面發出去了,於是,先被send的數據可能需要等待一段時間,才能跟後面被send的數據一起組成報文發出去。

日常生活中說“粘包”的人,指的可能是第一種情況,也可能是第二種,不繼續追問的話,很難知道他們到底在說什麼。

第三,這兩個其實都不是“問題”。

第一個是tcp的應有之義,人家本身就是個面向流的協議,如果你要用它傳輸數據報(datagram),必然要自己實現stream2datagram的過程。這不叫解決問題,這叫實現功能。

第二個是tcp在實現的時候,爲了解決大量小報文場景下包頭比負載大,導致傳輸性價比太低的問題,專門設計的。其實在99%的情況下,Nagle算法根本就不會導致可感知的傳輸延遲,只是在某些場景下,Nagle算法和延遲ACK機制碰到一起,纔會導致可感知的延遲。

有些應用開發者病急亂投醫,看到Nagle算法可能導致發送等待,並且可以禁止掉,於是以訛傳訛說禁止Nagle算法可以讓發送更快。其實99%的情況下禁不禁止都一樣,延遲根本不是Nagle算法導致的;就算真有問題,最優解決方案也不是屏蔽Nagle算法。

最後,粘包是個“土話”,容易引起歧義,不建議沿用。stream2datagram就是stream2datagram,TCP_NODELAY就是TCP_NODELAY,不要說什麼“粘包”。

ps:

說了半天忘了說怎麼解決“問題”。

第一種“粘包”,靠設計一個帶包頭的應用層報文結構就能解決。包頭定長,以特定標誌開頭,裏帶着負載長度,這樣接收側只要以定長嘗試讀取包頭,再按照包頭裏的負載長度讀取負載就行了,多出來的數據都留在緩衝區裏即可。

其實ip報文和tcp報文都是這麼幹的。

第二種“粘包”,設置TCP_NODELAY就能屏蔽Nagle算法,但你最好確定自己知道自己在幹什麼。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章