前言
本文已經(jīng)收錄到我的
Github個(gè)人博客,歡迎大佬們光臨寒舍:
學(xué)習(xí)導(dǎo)圖:

一.運(yùn)輸層概述
我們知道運(yùn)輸層位于網(wǎng)絡(luò)層之上,網(wǎng)絡(luò)層提供了主機(jī)之間的邏輯通道。
Q1:那既然已經(jīng)把一個(gè)數(shù)據(jù)包從一個(gè)主機(jī)發(fā)到另一個(gè)主機(jī)上面了,為什么還需要運(yùn)輸層呢?
A1:這是因?yàn)檫\(yùn)輸層提供了應(yīng)用進(jìn)程之間的端-端連接。
Q2:我們知道一個(gè)電腦可能有多個(gè)進(jìn)程同時(shí)在使用網(wǎng)絡(luò)連接,那么網(wǎng)絡(luò)包到達(dá)主機(jī)之后,怎么區(qū)分自己屬于那個(gè)進(jìn)程?
So,如果你對(duì)運(yùn)輸層感興趣的話,可以跟筆者一起來(lái)簡(jiǎn)要了解下運(yùn)輸層,了解下
UDP和TCP兩大面試常客
- 運(yùn)輸層為運(yùn)行在不同主機(jī)上的應(yīng)用程序之間提供邏輯通信
- 應(yīng)用報(bào)文加上運(yùn)輸層首部形成運(yùn)輸層報(bào)文段,報(bào)文段通過(guò)網(wǎng)絡(luò)層被封裝成網(wǎng)絡(luò)層分組(數(shù)據(jù)報(bào))向目的地發(fā)送
Q1:運(yùn)輸層和網(wǎng)絡(luò)層的關(guān)系
- 運(yùn)輸層:運(yùn)行在不同主機(jī)上的應(yīng)用程序之間提供邏輯通信
- 網(wǎng)絡(luò)層:提供主機(jī)之間的通信
舉個(gè)例子來(lái)說(shuō)明兩者關(guān)系:
有兩個(gè)家庭,一家位于廣州,一家位于北京,每家有 3個(gè)孩子。這兩個(gè)家庭的孩子們喜歡彼此通信,每封信都用單獨(dú)的信封通過(guò)傳統(tǒng)的郵政服務(wù)發(fā)送。每個(gè)家庭有一個(gè)孩子負(fù)責(zé)收發(fā)郵件,北京家庭是 阿京,而廣州家庭是 阿州。每周阿京去她所有的兄弟姐妹那里收集郵件,并將這些郵件交到郵遞員處上。當(dāng)信件到達(dá)北京家庭時(shí),阿京也負(fù)責(zé)將信件發(fā)到她的兄弟姐妹手上,廣州家庭中 阿州也負(fù)責(zé)類似工作
- 網(wǎng)絡(luò)層——郵遞員
- 運(yùn)輸層——阿京和阿州
- 應(yīng)用程序——兄弟姐妹
- 主機(jī)——兩個(gè)家庭
通過(guò)運(yùn)輸層協(xié)議,兩臺(tái)電腦仿佛直接相連一樣。應(yīng)用無(wú)需知道底層內(nèi)部實(shí)現(xiàn)的原理和細(xì)節(jié),比如怎么把遠(yuǎn)隔世界兩地電腦上的數(shù)據(jù)進(jìn)行相互傳輸
Q2:注意點(diǎn)
- 運(yùn)輸層協(xié)議僅僅實(shí)現(xiàn)在網(wǎng)絡(luò)的邊緣處,例如主機(jī),電腦,手機(jī)等。如路由器,交換機(jī)這些網(wǎng)絡(luò)核心設(shè)備,是沒(méi)有實(shí)現(xiàn)運(yùn)輸層協(xié)議的
- 每一層協(xié)議僅僅檢查分組相應(yīng)的協(xié)議層字段
- 最常用的兩種輸入層協(xié)議,
TCP和UDP - 運(yùn)輸層的下面是網(wǎng)絡(luò)層,網(wǎng)絡(luò)層的目的在于為不同的主機(jī)提供邏輯通信,而非主機(jī)上的進(jìn)程
- 網(wǎng)絡(luò)層常用協(xié)議是
IP,其提供的是一種不可靠的數(shù)據(jù)傳輸服務(wù) - 為了做到為不同主機(jī) (
host) 上的應(yīng)用或者說(shuō)進(jìn)程提供邏輯通信這一目的,運(yùn)輸層協(xié)議必須能分辨出數(shù)據(jù)的來(lái)源和去向。為此,運(yùn)輸層存在著兩種行為,多路復(fù)用和多路分解
二.多路復(fù)用與多路分解
- 多路復(fù)用:當(dāng)運(yùn)輸層收到來(lái)自上方應(yīng)用層的數(shù)據(jù)時(shí),運(yùn)輸層會(huì)為數(shù)據(jù)封上一些頭部信息,根據(jù)所有協(xié)議不同,封上的信息也不一樣
用上面的兩個(gè)家庭的例子進(jìn)行形象化地闡述就是:多路復(fù)用就是阿州和阿京將兄弟姐妹的信一起交給郵遞員
- 多路分解:當(dāng)運(yùn)輸層收到下方網(wǎng)絡(luò)層傳輸來(lái)的數(shù)據(jù)時(shí),運(yùn)輸層會(huì)檢查多路復(fù)用時(shí)封上的信息,從而正確的把數(shù)據(jù)定向到相應(yīng)的進(jìn)程
Q1:如何使用運(yùn)輸層的協(xié)議?
操作系統(tǒng)提供了被稱為 Socket 的接口 API 供編程人員調(diào)用,對(duì) Socket 的形象理解是其是一種抽象,將復(fù)雜的實(shí)現(xiàn) (TCP/UDP) 協(xié)議的各種行為抽形成簡(jiǎn)單的幾個(gè)函數(shù)給開(kāi)發(fā)人員使用。就像瀏覽器將發(fā)送請(qǐng)求報(bào)文這一 Http 協(xié)議規(guī)定的行為,抽象成我們只需要輸入 Url 然后回車即可
這里需要注意的一點(diǎn)是:
- 在一般情況下,一個(gè)計(jì)算機(jī)端口只能被一個(gè)進(jìn)程占用
- 一個(gè)進(jìn)程可以創(chuàng)建多個(gè)
Socket,多個(gè)TCPSocket可以監(jiān)聽(tīng)同一個(gè)端口,并保證接受的數(shù)據(jù)依舊是正確的 - 多個(gè)
UDP Socket就無(wú)法監(jiān)聽(tīng)同一端口,這其中的差異源于TCP和UDP協(xié)議的不同
TCP是面向連接的,其有足夠狀態(tài)的信息來(lái)分辨數(shù)據(jù)來(lái)源,后定向到正確的SocketUDP不需要維持連接,僅僅通過(guò)端口號(hào)來(lái)決定數(shù)據(jù)的去向,所以會(huì)導(dǎo)致沖突
三.UDP 和TCP的多路復(fù)用和分解
Q1:UDP的多路復(fù)用和分解
一個(gè) UDP Socket 通過(guò)一個(gè)二元組 (目的 IP 地址,目的端口號(hào)) 來(lái)標(biāo)識(shí),當(dāng)輸入層收到數(shù)據(jù)時(shí),通過(guò)檢查這個(gè)二元組,來(lái)定向數(shù)據(jù)該去往哪一個(gè) UDP Socket。這也是多個(gè) UDP Socket 無(wú)法監(jiān)聽(tīng)同一個(gè)端口的原因
Q2:TCP 的多路復(fù)用分解
一個(gè) TCP Socket 通過(guò)一個(gè)四元組 (源 IP,源端口,目的 IP,目的端口號(hào)) 來(lái)標(biāo)識(shí),這也解釋為什么多個(gè) TCP Socket 可以監(jiān)聽(tīng)同一個(gè)端口,盡管目的 IP和目的端口號(hào)是一樣的,但是源 IP和源端口的組合總是不同的

四.UDP
4.1 UDP基本概念
相比于 TCP來(lái)講,UDP是一個(gè)簡(jiǎn)單的協(xié)議,就是把網(wǎng)絡(luò)層 IP 提供的服務(wù)封裝了下,實(shí)現(xiàn)了多路復(fù)用和分解,提供了端到端進(jìn)程間的通信和錯(cuò)誤檢驗(yàn)服務(wù)
相對(duì)于 TCP 來(lái)說(shuō):
缺點(diǎn):
-
UDP是不可靠的傳輸服務(wù) - 沒(méi)有流量和擁塞控制
優(yōu)點(diǎn):
- 能夠夠精細(xì)的控制數(shù)據(jù)的發(fā)送時(shí)間和速率
- 無(wú)需事先建立連接
- 無(wú)連接狀態(tài)
- 分組首部開(kāi)銷小
UDP報(bào)文端結(jié)構(gòu):

- 源端口號(hào):發(fā)送方的端口號(hào)
- 目的端口號(hào):接收方端口號(hào)
- 長(zhǎng)度:包括首部在內(nèi)的報(bào)文長(zhǎng)度
- 檢驗(yàn)和:用來(lái)差錯(cuò)檢驗(yàn)。只發(fā)現(xiàn)錯(cuò)誤不糾正,錯(cuò)了就扔。然后重發(fā)
4.2 可靠數(shù)據(jù)傳輸原理
雖然
UDP并不可靠,但是我們要分析其為啥不可靠,從而引出可靠數(shù)據(jù)傳輸原理,有利于理解下文對(duì)TCP協(xié)議的可靠數(shù)據(jù)傳輸?shù)臋C(jī)制
Q1:數(shù)據(jù)傳輸可能遇到的問(wèn)題:
- 傳輸中數(shù)據(jù)被損壞
- 數(shù)據(jù)丟失
- 數(shù)據(jù)可能亂序到達(dá)
Q2:解決方法:
- 檢驗(yàn)和
- 序號(hào)
- 定時(shí)器
- 肯定和否定反饋分組
- 重傳
Q3:如何在保證可靠性的前提下,提高其性能?
A.通過(guò)引入流水線 (pipelining) 技術(shù)
引入流水線導(dǎo)致了:
- 序號(hào)范圍需要增加
- 收發(fā)雙方可能需要緩存亂序到達(dá)的分組
- 以上兩個(gè)的具體實(shí)現(xiàn)取決于傳輸協(xié)議如何處理分組丟失、損壞的問(wèn)題 (是選擇回退
N步,還是選擇重傳)
B.通過(guò)緩存處理
讀者如果對(duì)詳細(xì)的緩存機(jī)制感興趣的話,可以看下這篇文章:HTTP----HTTP緩存機(jī)制
- 緩存處理的規(guī)則:分為強(qiáng)制緩存和協(xié)商緩存
- 緩存的優(yōu)點(diǎn):
- 減少了冗余的數(shù)據(jù)傳遞,節(jié)省寬帶流量
- 減少了服務(wù)器的負(fù)擔(dān),大大提高了網(wǎng)站性能
- 加快了客戶端加載網(wǎng)頁(yè)的速度 這也正是
HTTP緩存屬于客戶端緩存的原因
Q4:如何處理分組丟失、損壞的問(wèn)題
A.回退 N 步
其核心在于,發(fā)送方會(huì)維持一個(gè)窗口,發(fā)送方能發(fā)送的數(shù)據(jù)量取決于窗口長(zhǎng)度,并且當(dāng)丟失時(shí)會(huì)重送所有未確認(rèn)的分組
接收方會(huì)丟棄亂序到達(dá)的緩存
-
特點(diǎn):
1.累計(jì)性
ACK2.單一定時(shí)器
B.選擇重傳
核心在于,收發(fā)雙方都會(huì)維持一個(gè)窗口,并且盡力保證窗口的狀態(tài)是同步的,因此當(dāng)分包丟失時(shí),發(fā)送方只會(huì)重送丟失的分組
接收方會(huì)緩存亂序到達(dá)的分組
-
特點(diǎn):
1.獨(dú)立性
ACK2.多個(gè)定時(shí)器
五.TCP
5.1 TCP基本概念
A.特點(diǎn):
- 面向連接
- 全雙工的
- 點(diǎn)對(duì)點(diǎn),不存在一次發(fā)送將數(shù)據(jù)傳遞給多個(gè)接收方、
- 在合適的時(shí)候發(fā)送 發(fā)送緩存 里的數(shù)據(jù)
- 為每個(gè)數(shù)據(jù)封上一個(gè)
TCP頭部 -
TCP連接的每一端都具有發(fā)送緩存和接受緩存
B.報(bào)文段結(jié)構(gòu)

部分參數(shù)解釋:
序號(hào) (
seq) :所帶數(shù)據(jù)的第一個(gè)比特的序號(hào),同時(shí)也是接收方期待的序號(hào),等于接收方回復(fù)報(bào)文中的ACK(n) 中的 n確認(rèn)號(hào) (
ack) : 對(duì)于一個(gè)ACK(n) 來(lái)說(shuō),告訴對(duì)方 n-1 前的數(shù)據(jù)已經(jīng)收到,下一次期待的序列號(hào)為 nACK:指示,用于指示報(bào)文中確認(rèn)號(hào)字段的值是有效的PSH:指示,立即發(fā)送發(fā)送緩存里的數(shù)據(jù)RST:指示,用于強(qiáng)制關(guān)閉連接SYN: 指示,用于握手階段也就是建立連接的階段FIN:指示,用于正常關(guān)閉連接接受窗口 :用于
TCP的流量控制功能
5.2 可靠數(shù)據(jù)傳輸
TCP協(xié)議為數(shù)據(jù)的每一Byte都編號(hào),而非針對(duì)報(bào)文段總是維持最老未經(jīng)確認(rèn)的 1
Byte的計(jì)時(shí)器每一次超時(shí)重置的計(jì)時(shí)器時(shí)間會(huì)加倍
其錯(cuò)誤恢復(fù)機(jī)制是回退 N 步和選擇重傳的混合體
- 不會(huì)丟棄亂序到達(dá)的分組,而是緩存起來(lái)(選擇重傳的特性)
- 采用累計(jì)性
ACK(回退N步的特性)- 只會(huì)重傳丟失報(bào)文段中的數(shù)據(jù)(選擇重傳的特性)
- 快速重傳:當(dāng)接收到連續(xù)的三個(gè)重復(fù)冗余
ACK(其實(shí)是收到四個(gè)同樣的ACK,第一個(gè)是正常的,后三個(gè)才是冗余的),會(huì)觸發(fā)快速重傳,立即重發(fā)分組
為什么是三個(gè)重復(fù)冗余
ACK呢?答案:把三次冗余
ACK作為判定丟失的準(zhǔn)則其本身就是概率估計(jì)值所得出的(換句話說(shuō),出現(xiàn)三次冗余ACK大概率是分組丟失)對(duì)詳細(xì)的探究過(guò)程感興趣的讀者,可以看下這篇文章:TCP的快速重傳機(jī)制
5.3 流量控制
- 為了防止過(guò)高數(shù)據(jù)流量導(dǎo)致接收者的接受緩存爆掉,接收者會(huì)在其
TCP報(bào)文中通過(guò) 接受窗口 指示發(fā)送者還能發(fā)送多少數(shù)據(jù)
接受窗口 (rwnd) 公式:
rwnd = RcvBuffer - [LastByteRead - LastbyteRead]- 且:
LastByteSent - LastByteAcked <= rwnd
5.4 TCP 連接管理
Q1:建立連接(三次握手)
注意:
Server端的ack和data是一起發(fā)送的

- 客戶端發(fā)送
SYN位置 1 的報(bào)文段 - 服務(wù)端返回
SYN為 1,ACK為 1 的報(bào)文段 - 客戶端發(fā)送
ACK為 1,且附帶數(shù)據(jù)的報(bào)文段
形象化地理解:
TCP 三次握手就好比兩個(gè)人在街上隔著50米看見(jiàn)了對(duì)方,但是因?yàn)殪F霾等原因不能100%確認(rèn),所以要通過(guò)招手的方式相互確定對(duì)方是否認(rèn)識(shí)自己。張三首先向李四招手(
syn),李四看到張三向自己招手后,向?qū)Ψ近c(diǎn)了點(diǎn)頭擠出了一個(gè)微笑(ack)。張三看到李四微笑后確認(rèn)了李四成功辨認(rèn)出了自己(進(jìn)入estalished狀態(tài))但是李四還有點(diǎn)狐疑,向四周看了一看,有沒(méi)有可能張三是在看別人呢,他也需要確認(rèn)一下。所以李四也向張三招了招手(
syn),張三看到李四向自己招手后知道對(duì)方是在尋求自己的確認(rèn),于是也點(diǎn)了點(diǎn)頭擠出了微笑(ack),李四看到對(duì)方的微笑后確認(rèn)了張三就是在向自己打招呼(進(jìn)入established狀態(tài))。于是兩人加快步伐,走到了一起,相互擁抱

Q2:斷開(kāi)連接(四次揮手)

- 客戶發(fā)送
FIN為 1 的報(bào)文段 - 服務(wù)端返回
ACK為 1 的報(bào)文段 - 服務(wù)端發(fā)送
FIN為 1 的報(bào)文段 - 客戶端返回
ACK為 1 的報(bào)文段 - 客戶端在一段時(shí)間后,關(guān)閉連接
形象化地理解:
張三揮手(
fin)——李四傷感地微笑(ack)——李四揮手(fin)——張三傷感地微笑

六.擁塞控制
Q1:擁塞的代價(jià)
- 導(dǎo)致分組過(guò)長(zhǎng)的排隊(duì)時(shí)延
- 需要重傳因緩存溢出丟失的分組
- 高延時(shí)導(dǎo)致重送分組
- 丟包導(dǎo)致運(yùn)輸相關(guān)分組的分組交換器所作的工作全部白費(fèi)
Q2:TCP 的擁塞控制
TCP采用端到端的擁塞控制三個(gè)主要問(wèn)題:
- 一個(gè)
TCP的發(fā)送方如何限制自己的發(fā)送流量的速率?
通過(guò)設(shè)置一個(gè)擁塞窗口 (cwnd), 并且保證:LastByteSent - LastByteAcked <= min{cwnd, rwnd}
- 如何感知其發(fā)送路徑擁塞了?
timeout- 收到一次正常
ACK后連續(xù)收到三次冗余ACK
- 感到擁塞時(shí),采用什么樣的算法改變發(fā)送速率?
- 慢啟動(dòng)
cwnd的值從 1MSS開(kāi)始,并且對(duì)每一個(gè)ACK,cwnd值變?yōu)樵瓉?lái)的 2 倍,直到超過(guò)閾值 (ssthresh),轉(zhuǎn)為擁塞避免模式
- 擁塞避免
在每一個(gè)
RRT時(shí)間,cwnd的值增加一個(gè)MSS
- 快速恢復(fù)
cwnd的值降為一半加上重復(fù)收到的重復(fù)ACK的數(shù)量,并且每一個(gè)ACK,cwnd的值增加一個(gè)MSS在實(shí)踐中,一旦
timeout就會(huì)會(huì)到慢啟動(dòng)的狀態(tài),多次重復(fù)ACK則會(huì)進(jìn)入快速恢復(fù)狀態(tài)
Q3:TCP 公平
TCP 的公平性在于保證每個(gè)連接的吞吐量是平均的,而不是應(yīng)用或進(jìn)程間
七.再談握手和揮手
7.1 為啥一定要三次握手,兩次不行嗎?
弄清這個(gè)問(wèn)題,我們需要先弄明白三次握手的目的是什么,能不能只用兩次握手來(lái)達(dá)到同樣的目的。
- 第一次握手:客戶端發(fā)送網(wǎng)絡(luò)包,服務(wù)端收到了。 這樣服務(wù)端就能得出結(jié)論:客戶端的發(fā)送能力、服務(wù)端的接收能力是正常的。
- 第二次握手:服務(wù)端發(fā)包,客戶端收到了。 這樣客戶端就能得出結(jié)論:服務(wù)端的接收、發(fā)送能力,客戶端的接收、發(fā)送能力是正常的。不過(guò)此時(shí)服務(wù)器并不能確認(rèn)客戶端的接收能力是否正常。
- 第三次握手:客戶端發(fā)包,服務(wù)端收到了。 這樣服務(wù)端就能得出結(jié)論:客戶端的接收、發(fā)送能力正常,服務(wù)器自己的發(fā)送、接收能力也正常。
因此,需要三次握手才能雙方確認(rèn)雙方的接收與發(fā)送能力是否正常
如果將發(fā)送比喻為揮手,接收比喻為視力正常的話,就有下面的例子

試想如果是用兩次握手,可能會(huì)出現(xiàn)下面這種情況:
如客戶端發(fā)出連接請(qǐng)求,但因連接請(qǐng)求報(bào)文丟失而未收到確認(rèn),于是客戶端再重傳一次連接請(qǐng)求。后來(lái)收到了確認(rèn),建立了連接。數(shù)據(jù)傳輸完畢后,就釋放了連接,客戶端共發(fā)出了兩個(gè)連接請(qǐng)求報(bào)文段,其中第一個(gè)丟失,第二個(gè)到達(dá)了服務(wù)端,但是第一個(gè)丟失的報(bào)文段只是在某些網(wǎng)絡(luò)結(jié)點(diǎn)長(zhǎng)時(shí)間滯留了,延誤到連接釋放以后的某個(gè)時(shí)間才到達(dá)服務(wù)端,此時(shí)服務(wù)端誤認(rèn)為客戶端又發(fā)出一次新的連接請(qǐng)求,于是就向客戶端發(fā)出確認(rèn)報(bào)文段,同意建立連接,不采用三次握手,只要服務(wù)端發(fā)出確認(rèn),就建立新的連接了,此時(shí)客戶端忽略服務(wù)端發(fā)來(lái)的確認(rèn),也不發(fā)送數(shù)據(jù),則服務(wù)端一直等待客戶端發(fā)送數(shù)據(jù),浪費(fèi)資源

7.2 為啥揮手要四次?
這是因?yàn)榉?wù)端在LISTEN狀態(tài)下,收到建立連接請(qǐng)求的SYN報(bào)文后,把ACK和SYN放在一個(gè)報(bào)文里發(fā)送給客戶端。而關(guān)閉連接時(shí),當(dāng)收到對(duì)方的FIN報(bào)文時(shí),僅僅表示對(duì)方不再發(fā)送數(shù)據(jù)了但是還能接收數(shù)據(jù),所以服務(wù)端可以立即close,也可以發(fā)送一些數(shù)據(jù)給客戶端后,再發(fā)送FIN報(bào)文給客戶端來(lái)表示同意現(xiàn)在關(guān)閉連接,因此,服務(wù)端ACK和FIN一般都會(huì)分開(kāi)發(fā)送。
八.碎碎念
恭喜你,成功看到了這里,現(xiàn)在的你,想必已經(jīng)對(duì)運(yùn)輸層有自己的體會(huì)了;其實(shí),運(yùn)輸層的知識(shí)點(diǎn)遠(yuǎn)不止這些,限于篇幅,把所有運(yùn)輸層的知識(shí)全部塞進(jìn)這篇文章中,也不是特別現(xiàn)實(shí);我們可以嘗試看多幾本相關(guān)的書(shū)籍,從而豐富自己的知識(shí)體系,從而得到更深的見(jiàn)解。
筆者也會(huì)不斷學(xué)習(xí),不斷豐富自己,到時(shí)候(待老師講解到這里了/看了別的書(shū))如果有比較好的觀點(diǎn),本文也會(huì)持續(xù)改進(jìn)更新,感謝您的支持。
最后筆者夾帶一下私貨,附上比較完整的計(jì)網(wǎng)面試題:計(jì)算機(jī)網(wǎng)絡(luò)太難?了解這一篇就夠了
如果文章對(duì)您有一點(diǎn)幫助的話,希望您能點(diǎn)一下贊,您的點(diǎn)贊,是我前進(jìn)的動(dòng)力
本文參考鏈接: