寫在前面
本文來看下TCP和UDP協議。
我們接觸這兩個協議最多的應該就是在面試中了,經典題目就是“TCP和UDP有什么區別?”,而最常得到的答案就是TCP是面向連接的,而UDP是面向無連接的。
那么這里的連接
到底是什么呢?難道真的是有一條物理上的線在那里嗎?當然不是,實際上是這樣子的,我們知道,TCP想要建立連接,必須經歷三次握手的過程,三次握手其實就是在交換數據,而三次握手之后,雙方都會將這些TCP協議本身需要用到的數據使用一定的數據結構維護起來,所以連接其實就是使用一定的數據結構保存的數據
,也所以連接其實就是數據了,即連接=數據
。那么UDP為什么是無連接的呢,因為它不需要維護這些數據。使用這些數據來維護交互的狀態,也就是在邏輯上連接起來了,而絕非物理上的。
TCP維護連接狀態的數據都有哪些呢,比如滑動窗口信息,哪些數據發送了沒有ack,哪些數據發送了還沒有ack,哪些數據還沒有發送等。
其他區別:
TCP提供可靠交付,UDP不是
TCP是面向流的,沒頭沒尾,而UDP是基于數據包的,一個個發,一個個收
TCP有擁塞控制,UDP沒有
所以啊,可以總結來看,TCP也是一個服務,而程序分為無狀態的服務和有狀態的服務,很明顯TCP是屬于有狀態的服務了。相對應的UDP就是一個無狀態的服務。
1:UDP
UDP全稱,user diagram protocol,即用戶數據報協議,是一種無連接協議。
1.1:UDP的頭
當機器收到一個包之后,物理層首先會拆掉物理層頭部,判斷MAC地址是否匹配,如果是匹配則交給網際層,網際層獲取頭部后,發現IP地址匹配,則交給傳輸層處理,但是到底是交給哪種傳輸層協議呢,這里需要看IP頭部的具體存放使用的是TCP還是UDP的8位協議信息了,這里假定是UDP,數據到達UDP,UDP怎么知道交給哪個應用程序呢?這就需要端口號了,也就是UDP頭的如下信息:
這里也可以看到UDP的頭只有8個字節,簡單到一塌糊涂。而相比之下TCP的頭就要復雜多了。
傳輸層處理完畢之后,內核的工作也就完成了。接下來只要找到監聽了目標端口號
的應用程序,交給其處理就行了。
1.2:UDP適用的場景和實例
1.2.1:網絡比較好的內網環境
比如像飛鴿,飛秋等內網的聊天工具。
1.2.2:對時延敏感,且對少少量丟包不敏感應用
比如實時對戰游戲,屬于分秒必爭型的,很多職業玩家,為了進一步降低時延甚至會買專業版的鼠標和鍵盤。如果是使用TCP,可能為了等待上一個沒有到達的包,早就被爆頭了。
比如直播場景,視頻網站,少量的丟包用戶其實是沒有感知的,特別是直播追求實時性,已經丟失的包就算等到了其實也沒有意義了。
1.2.3:應用本身資源少
比如IOT物聯網,設備內部可能只是嵌入了一個很小的操作系統,終端系統資源很少,而TCP需要額外存儲一些維護連接狀態的數據,協議代價比較大。
1.2.4:廣播場景
比如DHCP。就算丟包也所謂,重發就行了。
2:TCP
TCP相對于UDP復雜多了,因為TCP要實現流量控制,順序控制,擁塞控制等,而想要實現這些控制,就需要額外存儲相關數據,這些數據自然需要保存在頭中,所以,這部分我們先從TCP的頭看起。
2.1:TCP頭
如下:
- 源端口和目標端口
沒得說,最低配了,UDP就是如此。 - 序號和確認序號
序號是給包指定順序的,解決亂序問題。確認序號是用來進行確認哪個序號的包已經收到的,解決包丟失問題。
需要注意:確認序號是來確認哪個序號的包已經收到的,其和序號本身具有順序是沒有任何關系的,
即就算序號本身是隨機順序對確認序號也是沒有絲毫影響的。
- 常用的狀態位們
URG:緊急位,需要被優先發送的包,比如要下一個大文件,但是下載過程中突然取消下載,這個取消下載的消息就應該緊急發送到應用層。
ACK:確認包位,該位置為1時代表時一個確認包
PSH:推送
RST:連接重置包位,跳過四次揮手,直接斷開連接
SYN:三次握手建立連接位
FIN:四次回收斷開連接位
注意這些狀態位的發送會引起雙方狀態的變更。
- 窗口大小
做流量控制,用來告知對方自己的處理能力,別發太快了,也別發太慢了,即改用什么速度來發送數據,就是流控了。 - 校驗和
UDP也有,最低配了,校驗數據的完整性。
2.2:三次握手
- 為什么是三次?
既然要建立連接就要確定對方是在的,至少在自己發消息的那一刻是在的,而要確定是在的,就至少需要一個來回,如下:
1:A給B發消息,此時B知道A是在的
2:B給A回消息,此時A知道B是在的
欸,這么看起來2次握手就夠了,但,握手的目的是要建立連接,而建立連接的本質就是數據的交換,這里交換的數據呢就是數據的序號了,當然這個不必過分關心,只要知道是要交換數據來構建維護連接的狀態的數據結構
就行了。因此不僅要確定對方在,還要確定自己發給對方的數據對方收到了,所以過程就變為如下這樣:
1:A給B發消息并攜帶數據,此時B知道A是在的
2:B給A回消息并攜帶數據,此時A知道B在的,并且收到了自己的數據
3:A給B回消息并攜帶數據(此時其實就可以攜帶業務數據了),B就知道A收到自己的數據了
所以至少需要三次握手。你可能會說萬一三次握手之后服務掛了咋辦,這咱就控制不了了,只能是盡人事,聽天命
了。參考圖:
2.3:四次揮手
按照正常的邏輯斷開連接的過程應該是這個樣子的:
1:A給B說,我要斷開
2:B給A回,好的,我也斷開了
這樣子其實是有問題的,因為B不能直接斷開連接,原因是這個關閉的動作應該由上層應用來被動完成,而非主動完成,因為上層應用還要釋放資源等。所以這個過程要變成如下:
1:A給B說,我要斷開
2:B給A回,好的,我已經通知上層應用了,等上層應用關閉我再通知你
3:B上層應用調用關閉方法,B再給A回,上層應用已經關閉了,我關閉了啊
4:A給B回,好的,我收到了
這個時候B已經關閉了,但是A還不能關閉,因為B的包可能還在路上,所以要等待所有的包都死翹翹了才關閉,這個時間時2MSL。如果是A很快將端口釋放出來,則來自B還在路上的包可能會被新占用了該端口的新應用收到,出現問題,當然現在可以通過時間戳等技術直接識別并丟棄端口上一任主人
的包,但這里就相當于是上了個雙保險了。
為啥B不用等2MSL呢?因為A主動關閉,這個時候A不會再發業務包出去了,而在四次握手時,因為上層應用還沒有釋放資源和調用內核的關閉,所以上層應用還是有可能發出新的包的,所以A要等,而B不用等。
為啥是2MSL?一來一回的時間,A主動關閉前可能剛給B發了包,此時A發給B,B響應A,剛好2MSL。
這個過程如下圖:
2.4:TCP狀態機
看圖重要
:
2.5:消息重傳和確認
參考這里 。
2.6:滑動窗口
參考這里 。
2.7:擁塞控制
參考這里 。
寫在后面
參考文章列表
多知道一點
網絡包的單位都有哪些?
網絡傳輸是以包為單位的,二層叫幀,網絡層叫包,傳輸層叫段。我們籠統地稱為包。