tcp 和UDP

 

文章目錄
前言
1. UDP
2. TCP
2.1 TCP 的三次握手
2.2 TCP 四次揮手
2.3 累計確認
2.4 順序問題和丟包問題
2.5 流量控制的問題
2.6 擁塞控制的問題
總結及面試問題
前言
前端的面試中常常問的 TCP 和 UDP 的區別,網上也有好多內容,好比html

TCP 和 UDP 的區別前端

TCP 是面向鏈接的,UDP 是面向無鏈接的
UDP程序結構較簡單
TCP 是面向字節流的,UDP 是基於數據報的
TCP 保證數據正確性,UDP 可能丟包
TCP 保證數據順序,UDP 不保證
以前也由於面試的緣由瞭解過一下,可是面試官又問了爲何 TCP 是可靠傳輸,一下就露餡了,說不出來了,而後這兩天就仔細瞭解了一下這方面的內容,還專門訂閱了極客時間的趣談網絡協議,所以,這篇文章主要基於趣談網絡協議和本身的理解。面試

1. UDP
要想理解 TCP 和 UDP 的區別,首先要明白什麼是 TCP,什麼是 UDP算法

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

咱們來看一下 UDP 的包頭服務器

由上圖能夠看出,UDP 除了端口號,基本啥都沒有了。若是沒有這兩個端口號,數據就不知道該發給哪一個應用。網絡

因此 UDP 就像一個小孩子,特別簡單,有以下三個特色數據結構

UDP 的特色tcp

溝通簡單,不須要大量的數據結構,處理邏輯和包頭字段
輕信他人。它不會創建鏈接,可是會監聽這個地方,誰均可以傳給它數據,它也能夠傳給任何人數據,甚至能夠同時傳給多我的數據。
愣頭青,作事不懂變通。不會根據網絡的狀況進行擁塞控制,不管是否丟包,它該怎麼發仍是怎麼發
由於 UDP 是"小孩子",因此處理的是一些沒那麼難的項目,而且就算失敗的也能接收。基於這些特色的話,UDP 可使用在以下場景中post

UDP 的主要應用場景

須要資源少,網絡狀況穩定的內網,或者對於丟包不敏感的應用,好比 DHCP 就是基於 UDP 協議的。
不須要一對一溝通,創建鏈接,而是能夠廣播的應用。由於它不面向鏈接,因此能夠作到一對多,承擔廣播或者多播的協議。
須要處理速度快,能夠容忍丟包,可是即便網絡擁塞,也絕不退縮,勇往直前的時候
基於 UDP 的幾個例子

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

2. TCP
首先是 TCP 的包頭格式


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

首先,源端口和目標端口是不可少的。
接下來是包的序號。主要是爲了解決亂序問題。不編好號怎麼知道哪一個先來,哪一個後到
確認序號。發出去的包應該有確認,這樣能知道對方是否收到,若是沒收到就應該從新發送,這個解決的是不丟包的問題
狀態位。SYN 是發起一個連接,ACK 是回覆,RST 是從新鏈接,FIN 是結束鏈接。由於 TCP 是面向鏈接的,所以須要雙方維護鏈接的狀態,這些狀態位的包會引發雙方的狀態變動
窗口大小,TCP 要作流量控制,須要通訊雙方各聲明一個窗口,標識本身當前的處理能力。
經過對 TCP 頭的解析,咱們知道要掌握 TCP 協議,應該重點關注如下問題:

順序問題
丟包問題
鏈接維護
流量控制
擁塞控制
2.1 TCP 的三次握手
全部的問題,首先都要創建鏈接,因此首先是鏈接維護的問題

TCP 的創建鏈接稱爲三次握手,能夠簡單理解爲下面這種狀況

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

至於爲何是三次握手我這裏就不細講了,能夠看其餘人的博客,總結的話就是通訊雙方全都有來有回

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

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

A 告訴 B,我發起的包的序號是從哪一個號開始的,B 一樣也告訴 A,B 發起的 包的序號是從哪一個號開始的。

雙方創建鏈接以後須要共同維護一個狀態機,在創建鏈接的過程當中,雙方的狀態變化時序圖以下所示

這是網上常常見到的一張圖,剛開始的時候,客戶端和服務器都處於 CLOSED 狀態,先是服務端主動監聽某個端口,處於 LISTEN 狀態。而後客戶端主動發起鏈接 SYN,以後處於 SYN-SENT 狀態。服務端接收了發起的鏈接,返回 SYN,而且 ACK ( 確認 ) 客戶端的 SYN,以後處於 SYN-SENT 狀態。客戶端接收到服務端發送的 SYN 和 ACK 以後,發送 ACK 的 ACK,以後就處於 ESTAVLISHED 狀態,由於它一發一收成功了。服務端收到 ACK 的 ACK 以後,也處於 ESTABLISHED 狀態,由於它也一發一收了。

2.2 TCP 四次揮手
說完創建鏈接,再說下斷開鏈接,也被稱爲四次揮手,能夠簡單理解以下

A:B 啊,我不想玩了
B:哦,你不想玩了啊,我知道了
這個時候,只是 A 不想玩了,即再也不發送數據,可是 B 可能還有未發送完的數據,因此須要等待 B 也主動關閉。
B:A 啊,好吧,我也不玩了,拜拜
A:好的,拜拜

這樣整個鏈接就關閉了,固然上面只是正常的狀態,也有些非正常的狀態(好比 A 說完不玩了,直接跑路,B 發起的結束得不到 A 的回答,不知道該怎麼辦或則 B 直接跑路 A 不知道該怎麼辦),TCP 協議專門設計了幾個狀態來處理這些非正常狀態

斷開的時候,當 A 說不玩了,就進入 FIN_WAIT_1 的狀態,B 收到 A 不玩了的消息後,進入 CLOSE_WAIT 的狀態。

A 收到 B 說知道了,就進入 FIN_WAIT_2 的狀態,若是 B 直接跑路,則 A 永遠處與這個狀態。TCP 協議裏面並無對這個狀態的處理,但 Linux 有,能夠調整 tcp_fin_timeout 這個參數,設置一個超時時間。

若是 B 沒有跑路,A 接收到 B 的不玩了請求以後,從 FIN_WAIT_2 狀態結束,按說 A 能夠跑路了,可是若是 B 沒有接收到 A 跑路的 ACK 呢,就再也接收不到了,因此這時候 A 須要等待一段時間,由於若是 B 沒接收到 A 的 ACK 的話會從新發送給 A,因此 A 的等待時間須要足夠長。

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

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

爲了記錄全部發送的包和接收的包,TCP 須要發送端和接收端分別來緩存這些記錄,發送端的緩存裏是按照包的 ID 一個個排列,根據處理的狀況分紅四個部分

發送而且確認的
發送還沒有確認的
沒有發送等待發送的
沒有發送而且暫時不會發送的
這裏的第三部分和第四部分就屬於流量控制的內容

在 TCP 裏,接收端會給發送端報一個窗口大小,叫 Advertised window。這個窗口應該等於上面的第二部分加上第三部分,超過這個窗口,接收端作不過來,就不能發送了

因而,發送端要保持下面的數據結構

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

接收而且確認過的
還沒接收,可是立刻就能接收的
還沒接收,但也沒法接收的
對應的數據結構以下


2.4 順序問題和丟包問題
結合上面的圖看,在發送端,一、二、3 已發送並確認;四、五、六、七、八、9 都是發送了還沒確認;十、十一、12 是還沒發出的;1三、1四、15 是接收方沒有空間,不許備發的。

在接收端來看,一、二、三、四、5 是已經完成 ACK 可是還沒讀取的;六、7 是等待接收的;八、9 是已經接收尚未 ACK 的。

發送端和接收端當前的狀態以下:

一、二、3 沒有問題,雙方達成了一致
四、5 接收方說 ACK 了,可是發送方還沒收到
六、七、八、9 確定都發了,可是 八、9 已經到了,六、7 沒到,出現了亂序,緩存着可是沒辦法 ACK。
根據這個例子能夠知道順序問題和丟包問題都有可能存在,因此咱們先來看確認與重傳機制。

假設 4 的確認收到了,5 的 ACK 丟了,六、7 的數據包丟了,該怎麼辦?

一種方法是超時重試,即對每個發送了可是沒有 ACK 的包設定一個定時器,超過了必定的事件就從新嘗試。這個時間必須大於往返時間,但也不宜過長,不然超時時間變長,訪問就變慢了。

若是過一段時間,五、六、7 都超時了就會從新發送。接收方發現 5 原來接收過,因而丟棄 5;6 收到了,發送 ACK,要求下一個是 7,7 不幸又丟了。當 7 再次超時的時候,TCP 的策略是超時間隔加倍。每當遇到一次超時重傳的時候,都會講下一次超時時間間隔設爲先前值的兩倍。

超時重傳的機制是超時週期可能相對較長,是否有更快的方式呢?

有一個快速重傳的機制,即當接收方接收到一個序號大於指望的報文段時,就檢測到了數據流之間的間隔,因而發送三個冗餘的 ACK,客戶端接收到以後,知道數據報丟失,因而重傳丟失的報文段。

例如,接收方發現 六、八、9 都接收了,可是 7 沒來,因此確定丟了,因而發送三個 6 的 ACK,要求下一個是 7。客戶端接收到 3 個,就會發現 7 的確又丟了,不等超時,立刻重發。

2.5 流量控制的問題
在流量控制的機制裏面,在對於包的確認中,會攜帶一個窗口的大小

簡單的說一下就是接收端在發送 ACK 的時候會帶上緩衝區的窗口大小,可是通常在窗口達到必定大小纔會更新窗口,由於每次都更新的話,剛空下來就又被填滿了

2.6 擁塞控制的問題
也是經過窗口的大小來控制的,可是檢測網絡滿不盡是個挺難的事情,因此 TCP 發送包常常被比喻成往誰管理灌水,因此擁塞控制就是在不堵塞,不丟包的狀況下儘量的發揮帶寬。

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

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

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

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

TCP 擁塞控制主要來避免兩種現象,包丟失和超時重傳,一旦出現了這些現象說明發送的太快了,要慢一點。

具體的方法就是發送端慢啓動,好比倒水,剛開始倒的很慢,漸漸變快。而後設置一個閾值,當超過這個值的時候就要慢下來

慢下來仍是在增加,這時候就可能水滿則溢,出現擁塞,須要下降倒水的速度,等水慢慢滲下去。

擁塞的一種表現是丟包,須要超時重傳,這個時候,採用快速重傳算法,將當前速度變爲一半。因此速度仍是在比較高的值,也沒有一晚上回到解放前。

總結及面試問題
TCP 和 UDP 的區別

TCP 是面向鏈接的,UDP 是面向無鏈接的
UDP程序結構較簡單
TCP 是面向字節流的,UDP 是基於數據報的
TCP 保證數據正確性,UDP 可能丟包
TCP 保證數據順序,UDP 不保證
什麼是面向鏈接,什麼是面向無鏈接

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

TCP 爲何是可靠鏈接

經過 TCP 鏈接傳輸的數據無差錯,不丟失,不重複,且按順序到達。TCP 報文頭裏面的序號能使 TCP 的數據按序到達報文頭裏面的確認序號能保證不丟包,累計確認及超時重傳機制TCP 擁有流量控制及擁塞控制的機制

相關文章
相關標籤/搜索