TCP 協(xié)議面試靈魂 12 問 !


001. 能不能說一說 TCP 和 UDP 的區(qū)別?
UDP?相比,TCP?有三大核心特性:面向連接。所謂的連接,指的是客戶端和服務(wù)器的連接,在雙方互相通信之前,TCP 需要三次握手建立連接,而 UDP 沒有相應(yīng)建立連接的過程。
可靠性。TCP 花了非常多的功夫保證連接的可靠,這個(gè)可靠性體現(xiàn)在哪些方面呢?一個(gè)是有狀態(tài),另一個(gè)是可控制。
無(wú)狀態(tài),?不可控的。面向字節(jié)流。UDP 的數(shù)據(jù)傳輸是基于數(shù)據(jù)報(bào)的,這是因?yàn)閮H僅只是繼承了 IP 層的特性,而 TCP 為了維護(hù)狀態(tài),將一個(gè)個(gè) IP 包變成了字節(jié)流。
002: 說說 TCP 三次握手的過程?為什么是三次而不是兩次、四次?
戀愛模擬
愛的能力。愛和被愛的能力。被愛的能力。愛和被愛的能力,兩人開始一段甜蜜的愛情。真實(shí)握手
發(fā)送的能力和接收的能力。于是便會(huì)有下面的三次握手的過程:
CLOSED狀態(tài)。然后服務(wù)端開始監(jiān)聽某個(gè)端口,進(jìn)入了LISTEN狀態(tài)。SYN-SENT狀態(tài)。SYN和ACK(對(duì)應(yīng)客戶端發(fā)來(lái)的SYN),自己變成了SYN-REVD。ACK給服務(wù)端,自己變成了ESTABLISHED狀態(tài);服務(wù)端收到ACK之后,也變成了ESTABLISHED狀態(tài)。凡是需要對(duì)端確認(rèn)的,一定消耗TCP報(bào)文的序列號(hào)。
為什么不是兩次?
為什么不是四次?
發(fā)送和接收的能力,那四次握手可以嘛?三次握手過程中可以攜帶數(shù)據(jù)么?
ESTABLISHED狀態(tài),并且已經(jīng)能夠確認(rèn)服務(wù)器的接收、發(fā)送能力正常,這個(gè)時(shí)候相對(duì)安全了,可以攜帶數(shù)據(jù)。同時(shí)打開會(huì)怎樣?
SYN報(bào)文,狀態(tài)變化會(huì)是怎樣的呢?
SYN報(bào)文的同時(shí),接收方也給發(fā)送方發(fā)SYN報(bào)文,兩個(gè)人剛上了!SYN,兩者的狀態(tài)都變?yōu)?code>SYN-SENT。SYN后,兩者狀態(tài)都變?yōu)?code>SYN-REVD。ACK + SYN,這個(gè)報(bào)文在對(duì)方接收之后,兩者狀態(tài)一起變?yōu)?code>ESTABLISHED。003: 說說 TCP 四次揮手的過程
過程拆解

ESTABLISHED狀態(tài)。FIN?報(bào)文,在 TCP 報(bào)文中的位置如下圖:
FIN-WAIT-1狀態(tài)。注意, 這時(shí)候客戶端同時(shí)也變成了half-close(半關(guān)閉)狀態(tài),即無(wú)法向服務(wù)端發(fā)送報(bào)文,只能接收。CLOSED-WAIT狀態(tài)。FIN-WAIT2狀態(tài)。FIN,自己進(jìn)入LAST-ACK狀態(tài),FIN后,自己變成了TIME-WAIT狀態(tài),然后發(fā)送 ACK 給服務(wù)端。MSL(Maximum Segment Lifetime,報(bào)文最大生存時(shí)間), 在這段時(shí)間內(nèi)如果客戶端沒有收到服務(wù)端的重發(fā)請(qǐng)求,那么表示 ACK 成功到達(dá),揮手結(jié)束,否則客戶端重發(fā) ACK。等待2MSL的意義
1 個(gè) MSL 確保四次揮手中主動(dòng)關(guān)閉方最后的 ACK 報(bào)文最終能達(dá)到對(duì)端 1 個(gè) MSL 確保對(duì)端沒有收到 ACK 重傳的 FIN 報(bào)文可以到達(dá)
為什么是四次揮手而不是三次?
FIN, 往往不會(huì)立即返回FIN, 必須等到服務(wù)端所有的報(bào)文都發(fā)送完畢了,才能發(fā)FIN。因此先發(fā)一個(gè)ACK表示已經(jīng)收到客戶端的FIN,延遲一段時(shí)間才發(fā)FIN。這就造成了四次揮手。ACK和FIN的發(fā)送合并為一次揮手,這個(gè)時(shí)候長(zhǎng)時(shí)間的延遲可能會(huì)導(dǎo)致客戶端誤以為FIN沒有到達(dá)客戶端,從而讓客戶端不斷的重發(fā)FIN。同時(shí)關(guān)閉會(huì)怎樣?

004: 說說半連接隊(duì)列和 SYN Flood 攻擊的關(guān)系
CLOSED變?yōu)?code>LISTEN, 同時(shí)在內(nèi)部創(chuàng)建了兩個(gè)隊(duì)列:半連接隊(duì)列和全連接隊(duì)列,即SYN隊(duì)列和ACCEPT隊(duì)列。半連接隊(duì)列
SYN到服務(wù)端,服務(wù)端收到以后回復(fù)ACK和SYN,狀態(tài)由LISTEN變?yōu)?code>SYN_RCVD,此時(shí)這個(gè)連接就被推入了SYN隊(duì)列,也就是半連接隊(duì)列。全連接隊(duì)列
ACK, 服務(wù)端接收后,三次握手完成。這個(gè)時(shí)候連接等待被具體的應(yīng)用取走,在被取走之前,它會(huì)被推入另外一個(gè) TCP 維護(hù)的隊(duì)列,也就是全連接隊(duì)列(Accept Queue)。SYN Flood 攻擊原理
SYN。對(duì)于服務(wù)端而言,會(huì)產(chǎn)生兩個(gè)危險(xiǎn)的后果:處理大量的
SYN包并返回對(duì)應(yīng)ACK, 勢(shì)必有大量連接處于SYN_RCVD狀態(tài),從而占滿整個(gè)半連接隊(duì)列,無(wú)法處理正常的請(qǐng)求。由于是不存在的 IP,服務(wù)端長(zhǎng)時(shí)間收不到客戶端的
ACK,會(huì)導(dǎo)致服務(wù)端不斷重發(fā)數(shù)據(jù),直到耗盡服務(wù)端的資源。
如何應(yīng)對(duì) SYN Flood 攻擊?
增加 SYN 連接,也就是增加半連接隊(duì)列的容量。 減少 SYN + ACK 重試次數(shù),避免大量的超時(shí)重發(fā)。 利用 SYN Cookie 技術(shù),在服務(wù)端接收到 SYN后不立即分配連接資源,而是根據(jù)這個(gè)SYN計(jì)算出一個(gè)Cookie,連同第二次握手回復(fù)給客戶端,在客戶端回復(fù)ACK的時(shí)候帶上這個(gè)Cookie值,服務(wù)端驗(yàn)證 Cookie 合法之后才分配連接資源。
005: 介紹一下 TCP 報(bào)文頭部的字段

源端口、目標(biāo)端口
四元組——源 IP、源端口、目標(biāo) IP 和目標(biāo)端口。序列號(hào)
Sequence number, 指的是本報(bào)文段第一個(gè)字節(jié)的序列號(hào)。在 SYN 報(bào)文中交換彼此的初始序列號(hào)。 保證數(shù)據(jù)包按正確的順序組裝。
ISN
Initial Sequence Number(初始序列號(hào)),在三次握手的過程當(dāng)中,雙方會(huì)用過SYN報(bào)文來(lái)交換彼此的?ISN。確認(rèn)號(hào)
ACK(Acknowledgment number)。用來(lái)告知對(duì)方下一個(gè)期望接收的序列號(hào),小于ACK的所有字節(jié)已經(jīng)全部收到。標(biāo)記位
SYN,ACK,FIN,RST,PSH。FIN:即 Finish,表示發(fā)送方準(zhǔn)備斷開連接。RST:即 Reset,用來(lái)強(qiáng)制斷開連接。PSH:即 Push, 告知對(duì)方這些數(shù)據(jù)包收到后應(yīng)該馬上交給上層的應(yīng)用,不能緩存。窗口大小
校驗(yàn)和
可選項(xiàng)

TimeStamp: TCP 時(shí)間戳,后面詳細(xì)介紹。 MSS: 指的是 TCP 允許的從對(duì)方接收的最大報(bào)文段。 SACK: 選擇確認(rèn)選項(xiàng)。 Window Scale:窗口縮放選項(xiàng)。
006: 說說 TCP 快速打開的原理(TFO)
Cookie, 用它同樣可以實(shí)現(xiàn) TFO。TFO 流程
首輪三次握手
SYN給服務(wù)端,服務(wù)端接收到。SYN Cookie, 將這個(gè)Cookie放到 TCP 報(bào)文的?Fast Open選項(xiàng)中,然后才給客戶端返回。后面的三次握手
Cookie、SYN?和HTTP請(qǐng)求(是的,你沒看錯(cuò))發(fā)送給服務(wù)端,服務(wù)端驗(yàn)證了 Cookie 的合法性,如果不合法直接丟棄;如果是合法的,那么就正常返回SYN + ACK。ACK還得正常傳過來(lái),不然怎么叫三次握手嘛。
TFO 的優(yōu)勢(shì)
007: 能不能說說TCP報(bào)文中時(shí)間戳的作用?
timestamp是 TCP 報(bào)文首部的一個(gè)可選項(xiàng),一共占 10 個(gè)字節(jié),格式如下:kind(1 字節(jié)) + length(1 字節(jié)) + info(8 個(gè)字節(jié))
計(jì)算往返時(shí)延 RTT(Round-Trip Time) 防止序列號(hào)的回繞問題
計(jì)算往返時(shí)延 RTT

step 1:?a 向 b 發(fā)送的時(shí)候, timestamp?中存放的內(nèi)容就是 a 主機(jī)發(fā)送時(shí)的內(nèi)核時(shí)刻?ta1。step 2:?b 向 a 回復(fù) s2 報(bào)文的時(shí)候, timestamp?中存放的是 b 主機(jī)的時(shí)刻?tb,?timestamp echo字段為從 s1 報(bào)文中解析出來(lái)的 ta1。step 3:?a 收到 b 的 s2 報(bào)文之后,此時(shí) a 主機(jī)的內(nèi)核時(shí)刻是 ta2, 而在 s2 報(bào)文中的 timestamp echo 選項(xiàng)中可以得到? ta1, 也就是 s2 對(duì)應(yīng)的報(bào)文最初的發(fā)送時(shí)刻。然后直接采用 ta2 - ta1 就得到了 RTT 的值。
防止序列號(hào)回繞問題
1 ~ 2的數(shù)據(jù)包了,怎么區(qū)分誰(shuí)是誰(shuí)呢?這個(gè)時(shí)候就產(chǎn)生了序列號(hào)回繞的問題。008: TCP 的超時(shí)重傳時(shí)間是如何計(jì)算的?
經(jīng)典方法
SRTT = (α * SRTT) + ((1 - α) * RTT)
0.8,范圍是0.8 ~ 0.9。RTO = min(ubound, max(lbound, β * SRTT))
1.3 ~ 2.0,?lbound?是下界,ubound?是上界。0.8 ~ 0.9, RTT 對(duì)于 RTO 的影響太小。標(biāo)準(zhǔn)方法
Jacobson / Karels 算法。SRTT,公式如下:SRTT = (1 - α) * SRTT + α * RTT
α跟經(jīng)典方法中的α取值不一樣了,建議值是1/8,也就是0.125。RTTVAR(round-trip time variation)這個(gè)中間變量。RTTVAR = (1 - β) * RTTVAR + β * (|RTT - SRTT|)
RTO:RTO = μ * SRTT + ? * RTTVAR
μ建議值取1,??建議值取4。009: 能不能說一說 TCP 的流量控制?
滑動(dòng)窗口的概念。TCP 滑動(dòng)窗口
發(fā)送窗口

已發(fā)送且已確認(rèn) 已發(fā)送但未確認(rèn) 未發(fā)送但可以發(fā)送 未發(fā)送也不可以發(fā)送

send, WND 即window, UNA 即unacknowledged, 表示未被確認(rèn),NXT 即next, 表示下一個(gè)發(fā)送的位置。接收窗口

receive,NXT 表示下一個(gè)接收的位置,WND 表示接收窗口大小。流量控制過程
可用窗口減少了 100 個(gè)字節(jié),這很好理解。60?個(gè)字節(jié)被留在了緩沖隊(duì)列中。010: 能不能說說 TCP 的擁塞控制?
擁塞控制需要處理的問題。擁塞窗口(Congestion Window,cwnd) 慢啟動(dòng)閾值(Slow Start Threshold,ssthresh)
慢啟動(dòng) 擁塞避免 快速重傳和快速恢復(fù)
擁塞窗口
接收窗口(rwnd)是 接收端給的限制擁塞窗口(cwnd)是 發(fā)送端的限制
發(fā)送窗口的大小。發(fā)送窗口?發(fā)送窗口大小 = min(rwnd, cwnd)
cwnd的變化。慢啟動(dòng)
慢啟動(dòng)。運(yùn)作過程如下:首先,三次握手,雙方宣告自己的接收窗口大小 雙方初始化自己的擁塞窗口(cwnd)大小 在開始傳輸?shù)囊欢螘r(shí)間,發(fā)送端每收到一個(gè) ACK,擁塞窗口大小加 1,也就是說,每經(jīng)過一個(gè) RTT,cwnd 翻倍。如果說初始窗口為 10,那么第一輪 10 個(gè)報(bào)文傳完且發(fā)送端收到 ACK 后,cwnd 變?yōu)?20,第二輪變?yōu)?40,第三輪變?yōu)?80,依次類推。
擁塞避免
cwnd翻倍,現(xiàn)在cwnd只是增加 1 而已。快速重傳和快速恢復(fù)
快速重傳
選擇性重傳
SACK這個(gè)屬性,通過left edge和right edge告知發(fā)送端已經(jīng)收到了哪些區(qū)間的數(shù)據(jù)報(bào)。因此,即使第 5 個(gè)包丟包了,當(dāng)收到第 6、7 個(gè)包之后,接收端依然會(huì)告訴發(fā)送端,這兩個(gè)包到了。剩下第 5 個(gè)包沒到,就重傳這個(gè)包。這個(gè)過程也叫做選擇性重傳(SACK,Selective Acknowledgment),它解決的是如何重傳的問題。快速恢復(fù)
擁塞閾值降低為 cwnd 的一半 cwnd 的大小變?yōu)閾砣撝?/section> cwnd 線性增加
011: 能不能說說 Nagle 算法和延遲確認(rèn)?
Nagle 算法
當(dāng)?shù)谝淮伟l(fā)送數(shù)據(jù)時(shí)不用等待,就算是 1byte 的小包也立即發(fā)送 后面發(fā)送滿足下面條件之一就可以發(fā)了: 數(shù)據(jù)包大小達(dá)到最大段大小(Max Segment Size, 即 MSS) 之前所有包的 ACK 都已接收到
延遲確認(rèn)
接收到了大于一個(gè) frame 的報(bào)文,且需要調(diào)整窗口大小 TCP 處于 quickack 模式(通過 tcp_in_quickack_mode設(shè)置)發(fā)現(xiàn)了亂序包
兩者一起使用會(huì)怎樣?
012. 如何理解 TCP 的 keep-alive?
keep-alive, 不過 TCP 層面也是有keep-alive機(jī)制,而且跟應(yīng)用層不太一樣。sudo sysctl -a | grep keepalive
// 每隔 7200 s 檢測(cè)一次
net.ipv4.tcp_keepalive_time = 7200
// 一次最多重傳 9 個(gè)包
net.ipv4.tcp_keepalive_probes = 9
// 每個(gè)包的間隔重傳間隔 75 s
net.ipv4.tcp_keepalive_intvl = 75
keep-alive選項(xiàng),為什么?7200s 也就是兩個(gè)小時(shí)檢測(cè)一次,時(shí)間太長(zhǎng) 時(shí)間再短一些,也難以體現(xiàn)其設(shè)計(jì)的初衷, 即檢測(cè)長(zhǎng)時(shí)間的死連接
---END--- 重磅!碼農(nóng)突圍-技術(shù)交流群已成立 掃碼可添加碼農(nóng)突圍助手,可申請(qǐng)加入碼農(nóng)突圍大群和細(xì)分方向群,細(xì)分方向已涵蓋:Java、Python、機(jī)器學(xué)習(xí)、大數(shù)據(jù)、人工智能等群。 一定要備注:開發(fā)方向+地點(diǎn)+學(xué)校/公司+昵稱(如Java開發(fā)+上海+拼夕夕+猴子),根據(jù)格式備注,可更快被通過且邀請(qǐng)進(jìn)群 ▲長(zhǎng)按加群 推薦閱讀
? ?天天在用 Stream,那你知道如此強(qiáng)大的 Stream 的實(shí)現(xiàn)原理嗎? ???項(xiàng)目是如何死掉的?太過真實(shí)! ???太牛了!高考失利只能進(jìn)清華,35歲成阿里最年輕技術(shù)副總裁,他來(lái)自另一個(gè)平行世界! ???數(shù)據(jù)庫(kù)鏈接池終于搞對(duì)了,這次直接從100ms優(yōu)化到3ms! ?? Google 再見 Java ?? 面試官:我把數(shù)據(jù)庫(kù)部署在Docker容器內(nèi),你覺得如何? 最近面試BAT,整理一份面試資料《Java面試BAT通關(guān)手冊(cè)》,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫(kù)、數(shù)據(jù)結(jié)構(gòu)等等。 獲取方式:點(diǎn)“在看”,關(guān)注公眾號(hào)并回復(fù)?BAT?領(lǐng)取,更多內(nèi)容陸續(xù)奉上。 如有收獲,點(diǎn)個(gè)在看,誠(chéng)摯感謝 明天見(??ω??)??
評(píng)論
圖片
表情

