www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > 公眾號(hào)精選 > 架構(gòu)師社區(qū)
[導(dǎo)讀]每日一句英語學(xué)習(xí),每天進(jìn)步一點(diǎn)點(diǎn): 前言 “哈?啥是大白鯊?” 咳咳,主要是因?yàn)榫W(wǎng)絡(luò)分析工具 Wireshark 的圖標(biāo)特別像大白鯊頂部的角。 不信你看: Wireshark “為什么拖了怎么久才發(fā)文?” 為了讓大家更容易「看得見」 TCP,我搭建不少測試環(huán)境,并且數(shù)據(jù)

每日一句英語學(xué)習(xí),每天進(jìn)步一點(diǎn)點(diǎn):
實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

前言

“哈?啥是大白鯊?”

咳咳,主要是因?yàn)榫W(wǎng)絡(luò)分析工具 Wireshark 的圖標(biāo)特別像大白鯊頂部的角。

不信你看:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
Wireshark

“為什么拖了怎么久才發(fā)文?”

為了讓大家更容易「看得見」 TCP,我搭建不少測試環(huán)境,并且數(shù)據(jù)包抓很多次,花費(fèi)了不少時(shí)間,才抓到比較容易分析的數(shù)據(jù)包。

接下來丟包、亂序、超時(shí)重傳、快速重傳、選擇性確認(rèn)、流量控制等等 TCP 的特性,都能「一覽無云」。

沒錯(cuò),我把 TCP 的"衣服扒光"了,就為了給大家看的清楚,嘻嘻。

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
提綱

正文

顯形“不可見”的網(wǎng)絡(luò)包

網(wǎng)絡(luò)世界中的數(shù)據(jù)包交互我們?nèi)庋凼强床灰姷模鼈兙秃孟耠[形了一樣,我們對(duì)著課本學(xué)習(xí)計(jì)算機(jī)網(wǎng)絡(luò)的時(shí)候就會(huì)覺得非常的抽象,加大了學(xué)習(xí)的難度。

還別說,我自己在大學(xué)的時(shí)候,也是如此。

直到工作后,認(rèn)識(shí)了兩大分析網(wǎng)絡(luò)的利器:tcpdump 和 Wireshark,這兩大利器把我們“看不見”的數(shù)據(jù)包,呈現(xiàn)在我們眼前,一目了然。

唉,當(dāng)初大學(xué)學(xué)習(xí)計(jì)網(wǎng)的時(shí)候,要是能知道這兩個(gè)工具,就不會(huì)學(xué)的一臉懵逼。

tcpdump 和 Wireshark 有什么區(qū)別?

tcpdump 和 Wireshark 就是最常用的網(wǎng)絡(luò)抓包和分析工具,更是分析網(wǎng)絡(luò)性能必不可少的利器。

  • tcpdump 僅支持命令行格式使用,常用在 Linux 服務(wù)器中抓取和分析網(wǎng)絡(luò)包。

  • Wireshark 除了可以抓包外,還提供了可視化分析網(wǎng)絡(luò)包的圖形頁面。

所以,這兩者實(shí)際上是搭配使用的,先用 tcpdump 命令在 Linux 服務(wù)器上抓包,接著把抓包的文件拖出到 Windows 電腦后,用 Wireshark 可視化分析。

當(dāng)然,如果你是在 Windows 上抓包,只需要用 Wireshark 工具就可以。

tcpdump 在 Linux 下如何抓包?

tcpdump 提供了大量的選項(xiàng)以及各式各樣的過濾表達(dá)式,來幫助你抓取指定的數(shù)據(jù)包,不過不要擔(dān)心,只需要掌握一些常用選項(xiàng)和過濾表達(dá)式,就可以滿足大部分場景的需要了。

假設(shè)我們要抓取下面的 ping 的數(shù)據(jù)包:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

要抓取上面的 ping 命令數(shù)據(jù)包,首先我們要知道 ping 的數(shù)據(jù)包是 icmp 協(xié)議,接著在使用 tcpdump 抓包的時(shí)候,就可以指定只抓 icmp 協(xié)議的數(shù)據(jù)包:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

那么當(dāng) tcpdump 抓取到 icmp 數(shù)據(jù)包后, 輸出格式如下:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

從 tcpdump 抓取的 icmp 數(shù)據(jù)包,我們很清楚的看到 icmp echo 的交互過程了,首先發(fā)送方發(fā)起了 ICMP echo request 請(qǐng)求報(bào)文,接收方收到后回了一個(gè) ICMP echo reply 響應(yīng)報(bào)文,之后 seq 是遞增的。

我在這里也幫你整理了一些最常見的用法,并且繪制成了表格,你可以參考使用。

首先,先來看看常用的選項(xiàng)類,在上面的 ping 例子中,我們用過 -i 選項(xiàng)指定網(wǎng)口,用過 -nn 選項(xiàng)不對(duì) IP 地址和端口名稱解析。其他常用的選項(xiàng),如下表格:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
tcpdump 常用選項(xiàng)類

接下來,我們?cè)賮砜纯闯S玫倪^濾表用法,在上面的 ping 例子中,我們用過的是 icmp and host 183.232.231.174,表示抓取 icmp 協(xié)議的數(shù)據(jù)包,以及源地址或目標(biāo)地址為 183.232.231.174 的包。其他常用的過濾選項(xiàng),我也整理成了下面這個(gè)表格。

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
tcpdump 常用過濾表達(dá)式類

說了這么多,你應(yīng)該也發(fā)現(xiàn)了,tcpdump 雖然功能強(qiáng)大,但是輸出的格式并不直觀。

所以,在工作中 tcpdump 只是用來抓取數(shù)據(jù)包,不用來分析數(shù)據(jù)包,而是把 tcpdump 抓取的數(shù)據(jù)包保存成 pcap 后綴的文件,接著用 Wireshark 工具進(jìn)行數(shù)據(jù)包分析。

Wireshark 工具如何分析數(shù)據(jù)包?

Wireshark 除了可以抓包外,還提供了可視化分析網(wǎng)絡(luò)包的圖形頁面,同時(shí),還內(nèi)置了一系列的匯總分析工具。

比如,拿上面的 ping 例子來說,我們可以使用下面的命令,把抓取的數(shù)據(jù)包保存到 ping.pcap 文件

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

接著把 ping.pcap 文件拖到電腦,再用 Wireshark 打開它。打開后,你就可以看到下面這個(gè)界面:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

是吧?在 Wireshark 的頁面里,可以更加直觀的分析數(shù)據(jù)包,不僅展示各個(gè)網(wǎng)絡(luò)包的頭部信息,還會(huì)用不同的顏色來區(qū)分不同的協(xié)議,由于這次抓包只有 ICMP 協(xié)議,所以只有紫色的條目。

接著,在網(wǎng)絡(luò)包列表中選擇某一個(gè)網(wǎng)絡(luò)包后,在其下面的網(wǎng)絡(luò)包詳情中,可以更清楚的看到,這個(gè)網(wǎng)絡(luò)包在協(xié)議棧各層的詳細(xì)信息。比如,以編號(hào) 1 的網(wǎng)絡(luò)包為例子:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
ping 網(wǎng)絡(luò)包

  • 可以在數(shù)據(jù)鏈路層,看到 MAC 包頭信息,如源 MAC 地址和目標(biāo) MAC 地址等字段;

  • 可以在 IP 層,看到 IP 包頭信息,如源 IP 地址和目標(biāo) IP 地址、TTL、IP 包長度、協(xié)議等 IP 協(xié)議各個(gè)字段的數(shù)值和含義;

  • 可以在 ICMP 層,看到 ICMP 包頭信息,比如 Type、Code 等 ICMP 協(xié)議各個(gè)字段的數(shù)值和含義;

Wireshark 用了分層的方式,展示了各個(gè)層的包頭信息,把“不可見”的數(shù)據(jù)包,清清楚楚的展示了給我們,還有理由學(xué)不好計(jì)算機(jī)網(wǎng)絡(luò)嗎?是不是相見恨晚?

從 ping 的例子中,我們可以看到網(wǎng)絡(luò)分層就像有序的分工,每一層都有自己的責(zé)任范圍和信息,上層協(xié)議完成工作后就交給下一層,最終形成一個(gè)完整的網(wǎng)絡(luò)包。

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

解密 TCP 三次握手和四次揮手

既然學(xué)會(huì)了 tcpdump 和 Wireshark 兩大網(wǎng)絡(luò)分析利器,那我們快馬加鞭,接下用它倆抓取和分析 HTTP 協(xié)議網(wǎng)絡(luò)包,并理解 TCP 三次握手和四次揮手的工作原理。

本次例子,我們將要訪問的 http://192.168.3.200 服務(wù)端。在終端一用 tcpdump 命令抓取數(shù)據(jù)包:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

接著,在終端二執(zhí)行下面的 curl 命令:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

最后,回到終端一,按下 Ctrl+C 停止 tcpdump,并把得到的 http.pcap 取出到電腦。

使用 Wireshark 打開 http.pcap 后,你就可以在 Wireshark 中,看到如下的界面:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
HTTP 網(wǎng)絡(luò)包

我們都知道 HTTP 是基于 TCP 協(xié)議進(jìn)行傳輸?shù)?,那么?/p>

  • 最開始的 3 個(gè)包就是 TCP 三次握手建立連接的包

  • 中間是 HTTP 請(qǐng)求和響應(yīng)的包

  • 而最后的 3 個(gè)包則是 TCP 斷開連接的揮手包

Wireshark 可以用時(shí)序圖的方式顯示數(shù)據(jù)包交互的過程,從菜單欄中,點(diǎn)擊 統(tǒng)計(jì) (Statistics) -> 流量圖 (Flow Graph),然后,在彈出的界面中的「流量類型」選擇 「TCP Flows」,你可以更清晰的看到,整個(gè)過程中 TCP 流的執(zhí)行過程:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
TCP 流量圖

你可能會(huì)好奇,為什么三次握手連接過程的 Seq 是 0 ?

實(shí)際上是因?yàn)?Wireshark 工具幫我們做了優(yōu)化,它默認(rèn)顯示的是序列號(hào) seq 是相對(duì)值,而不是真實(shí)值。

如果你想看到實(shí)際的序列號(hào)的值,可以右鍵菜單, 然后找到「協(xié)議首選項(xiàng)」,接著找到「Relative Seq」后,把它給取消,操作如下:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
取消序列號(hào)相對(duì)值顯示

取消后,Seq 顯示的就是真實(shí)值了:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
TCP 流量圖

可見,客戶端和服務(wù)端的序列號(hào)實(shí)際上是不同的,序列號(hào)是一個(gè)隨機(jī)值。

這其實(shí)跟我們書上看到的 TCP 三次握手和四次揮手很類似,作為對(duì)比,你通??吹降?TCP 三次握手和四次揮手的流程,基本是這樣的:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
TCP 三次握手和四次揮手的流程

為什么抓到的 TCP 揮手是三次,而不是書上說的四次?

因?yàn)榉?wù)器端收到客戶端的 FIN 后,服務(wù)器端同時(shí)也要關(guān)閉連接,這樣就可以把 ACKFIN 合并到一起發(fā)送,節(jié)省了一個(gè)包,變成了“三次揮手”。

而通常情況下,服務(wù)器端收到客戶端的 FIN 后,很可能還沒發(fā)送完數(shù)據(jù),所以就會(huì)先回復(fù)客戶端一個(gè) ACK 包,稍等一會(huì)兒,完成所有數(shù)據(jù)包的發(fā)送后,才會(huì)發(fā)送 FIN 包,這也就是四次揮手了。

如下圖,就是四次揮手的過程:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
四次揮手

TCP 三次握手異常情況實(shí)戰(zhàn)分析

TCP 三次握手的過程相信大家都背的滾瓜爛熟,那么你有沒有想過這三個(gè)異常情況:

  • TCP 第一次握手的 SYN 丟包了,會(huì)發(fā)生了什么?

  • TCP 第二次握手的 SYN、ACK 丟包了,會(huì)發(fā)生什么?

  • TCP 第三次握手的 ACK 包丟了,會(huì)發(fā)生什么?

有的小伙伴可能說:“很簡單呀,包丟了就會(huì)重傳嘛?!?/p>

那我在繼續(xù)問你:

  • 那會(huì)重傳幾次?

  • 超時(shí)重傳的時(shí)間 RTO 會(huì)如何變化?

  • 在 Linux 下如何設(shè)置重傳次數(shù)?

  • ….

是不是啞口無言,無法回答?

不知道沒關(guān)系,接下里我用三個(gè)實(shí)驗(yàn)案例,帶大家一起探究探究這三種異常。

實(shí)驗(yàn)場景

本次實(shí)驗(yàn)用了兩臺(tái)虛擬機(jī),一臺(tái)作為服務(wù)端,一臺(tái)作為客戶端,它們的關(guān)系如下:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
實(shí)驗(yàn)環(huán)境

  • 客戶端和服務(wù)端都是 CentOs 6.5 Linux,Linux 內(nèi)核版本 2.6.32

  • 服務(wù)端 192.168.12.36,apache web 服務(wù)

  • 客戶端 192.168.12.37

實(shí)驗(yàn)一:TCP 第一次握手 SYN 丟包

為了模擬 TCP 第一次握手 SYN 丟包的情況,我是在拔掉服務(wù)器的網(wǎng)線后,立刻在客戶端執(zhí)行 curl 命令:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

其間 tcpdump 抓包的命令如下:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

過了一會(huì), curl 返回了超時(shí)連接的錯(cuò)誤:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

date 返回的時(shí)間,可以發(fā)現(xiàn)在超時(shí)接近 1 分鐘的時(shí)間后,curl 返回了錯(cuò)誤。

接著,把 tcp_sys_timeout.pcap 文件用 Wireshark 打開分析,顯示如下圖:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
SYN 超時(shí)重傳五次

從上圖可以發(fā)現(xiàn), 客戶端發(fā)起了 SYN 包后,一直沒有收到服務(wù)端的 ACK ,所以一直超時(shí)重傳了 5 次,并且每次 RTO 超時(shí)時(shí)間是不同的:

  • 第一次是在 1 秒超時(shí)重傳

  • 第二次是在 3 秒超時(shí)重傳

  • 第三次是在 7 秒超時(shí)重傳

  • 第四次是在 15 秒超時(shí)重傳

  • 第五次是在 31 秒超時(shí)重傳

可以發(fā)現(xiàn),每次超時(shí)時(shí)間 RTO 是指數(shù)(翻倍)上漲的,當(dāng)超過最大重傳次數(shù)后,客戶端不再發(fā)送 SYN 包。

在 Linux 中,第一次握手的 SYN 超時(shí)重傳次數(shù),是如下內(nèi)核參數(shù)指定的:

$ cat /proc/sys/net/ipv4/tcp_syn_retries
5

tcp_syn_retries 默認(rèn)值為 5,也就是 SYN 最大重傳次數(shù)是 5 次。

接下來,我們繼續(xù)做實(shí)驗(yàn),把 tcp_syn_retries 設(shè)置為 2 次:

echo 2 > /proc/sys/net/ipv4/tcp_syn_retries

重傳抓包后,用 Wireshark 打開分析,顯示如下圖:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
SYN 超時(shí)重傳兩次

實(shí)驗(yàn)一的實(shí)驗(yàn)小結(jié)

通過實(shí)驗(yàn)一的實(shí)驗(yàn)結(jié)果,我們可以得知,當(dāng)客戶端發(fā)起的 TCP 第一次握手 SYN 包,在超時(shí)時(shí)間內(nèi)沒收到服務(wù)端的 ACK,就會(huì)在超時(shí)重傳 SYN 數(shù)據(jù)包,每次超時(shí)重傳的 RTO 是翻倍上漲的,直到 SYN 包的重傳次數(shù)到達(dá) tcp_syn_retries 值后,客戶端不再發(fā)送 SYN 包。

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
SYN 超時(shí)重傳

實(shí)驗(yàn)二:TCP 第二次握手 SYN、ACK 丟包

為了模擬客戶端收不到服務(wù)端第二次握手 SYN、ACK 包,我的做法是在客戶端加上防火墻限制,直接粗暴的把來自服務(wù)端的數(shù)據(jù)都丟棄,防火墻的配置如下:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

接著,在客戶端執(zhí)行 curl 命令:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

date 返回的時(shí)間前后,可以算出大概 1 分鐘后,curl 報(bào)錯(cuò)退出了。

客戶端在這其間抓取的數(shù)據(jù)包,用 Wireshark 打開分析,顯示的時(shí)序圖如下:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

從圖中可以發(fā)現(xiàn):

  • 客戶端發(fā)起 SYN 后,由于防火墻屏蔽了服務(wù)端的所有數(shù)據(jù)包,所以 curl 是無法收到服務(wù)端的 SYN、ACK 包,當(dāng)發(fā)生超時(shí)后,就會(huì)重傳 SYN 包

  • 服務(wù)端收到客戶的 SYN 包后,就會(huì)回 SYN、ACK 包,但是客戶端一直沒有回 ACK,服務(wù)端在超時(shí)后,重傳了 SYN、ACK 包,接著一會(huì),客戶端超時(shí)重傳的 SYN 包又抵達(dá)了服務(wù)端,服務(wù)端收到后,超時(shí)定時(shí)器就重新計(jì)時(shí),然后回了 SYN、ACK 包,所以相當(dāng)于服務(wù)端的超時(shí)定時(shí)器只觸發(fā)了一次,又被重置了。

  • 最后,客戶端 SYN 超時(shí)重傳次數(shù)達(dá)到了 5 次(tcp_syn_retries 默認(rèn)值 5 次),就不再繼續(xù)發(fā)送 SYN 包了。

所以,我們可以發(fā)現(xiàn),當(dāng)?shù)诙挝帐值?SYN、ACK 丟包時(shí),客戶端會(huì)超時(shí)重發(fā) SYN 包,服務(wù)端也會(huì)超時(shí)重傳 SYN、ACK 包。

咦?客戶端設(shè)置了防火墻,屏蔽了服務(wù)端的網(wǎng)絡(luò)包,為什么 tcpdump 還能抓到服務(wù)端的網(wǎng)絡(luò)包?

添加 iptables 限制后, tcpdump 是否能抓到包 ,這要看添加的 iptables 限制條件:

  • 如果添加的是 INPUT 規(guī)則,則可以抓得到包

  • 如果添加的是 OUTPUT 規(guī)則,則抓不到包

網(wǎng)絡(luò)包進(jìn)入主機(jī)后的順序如下:

  • 進(jìn)來的順序 Wire -> NIC -> tcpdump -> netfilter/iptables

  • 出去的順序 iptables -> tcpdump -> NIC -> Wire


tcp_syn_retries 是限制 SYN 重傳次數(shù),那第二次握手 SYN、ACK 限制最大重傳次數(shù)是多少?

TCP 第二次握手 SYN、ACK 包的最大重傳次數(shù)是通過 tcp_synack_retries 內(nèi)核參數(shù)限制的,其默認(rèn)值如下:

$ cat /proc/sys/net/ipv4/tcp_synack_retries
5

是的,TCP 第二次握手 SYN、ACK 包的最大重傳次數(shù)默認(rèn)值是 5 次。

為了驗(yàn)證 SYN、ACK 包最大重傳次數(shù)是 5 次,我們繼續(xù)做下實(shí)驗(yàn),我們先把客戶端的 tcp_syn_retries 設(shè)置為 1,表示客戶端 SYN 最大超時(shí)次數(shù)是 1 次,目的是為了防止多次重傳 SYN,把服務(wù)端 SYN、ACK 超時(shí)定時(shí)器重置。

接著,還是如上面的步驟:

  1. 客戶端配置防火墻屏蔽服務(wù)端的數(shù)據(jù)包

  2. 客戶端 tcpdump 抓取 curl 執(zhí)行時(shí)的數(shù)據(jù)包

把抓取的數(shù)據(jù)包,用 Wireshark 打開分析,顯示的時(shí)序圖如下:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

從上圖,我們可以分析出:

  • 客戶端的 SYN 只超時(shí)重傳了 1 次,因?yàn)?tcp_syn_retries 值為 1

  • 服務(wù)端應(yīng)答了客戶端超時(shí)重傳的 SYN 包后,由于一直收不到客戶端的 ACK 包,所以服務(wù)端一直在超時(shí)重傳 SYN、ACK 包,每次的 RTO 也是指數(shù)上漲的,一共超時(shí)重傳了 5 次,因?yàn)?tcp_synack_retries 值為 5

接著,我把 tcp_synack_retries 設(shè)置為 2,tcp_syn_retries 依然設(shè)置為 1:

echo 2 > /proc/sys/net/ipv4/tcp_synack_retries
echo 1 > /proc/sys/net/ipv4/tcp_syn_retries

依然保持一樣的實(shí)驗(yàn)步驟進(jìn)行操作,接著把抓取的數(shù)據(jù)包,用 Wireshark 打開分析,顯示的時(shí)序圖如下:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

可見:

  • 客戶端的 SYN 包只超時(shí)重傳了 1 次,符合 tcp_syn_retries 設(shè)置的值;

  • 服務(wù)端的 SYN、ACK 超時(shí)重傳了 2 次,符合 tcp_synack_retries 設(shè)置的值


實(shí)驗(yàn)二的實(shí)驗(yàn)小結(jié)

通過實(shí)驗(yàn)二的實(shí)驗(yàn)結(jié)果,我們可以得知,當(dāng) TCP 第二次握手 SYN、ACK 包丟了后,客戶端 SYN 包會(huì)發(fā)生超時(shí)重傳,服務(wù)端 SYN、ACK 也會(huì)發(fā)生超時(shí)重傳。

客戶端 SYN 包超時(shí)重傳的最大次數(shù),是由 tcp_syn_retries 決定的,默認(rèn)值是 5 次;服務(wù)端 SYN、ACK 包時(shí)重傳的最大次數(shù),是由 tcp_synack_retries 決定的,默認(rèn)值是 5 次。

實(shí)驗(yàn)三:TCP 第三次握手 ACK 丟包

為了模擬 TCP 第三次握手 ACK 包丟,我的實(shí)驗(yàn)方法是在服務(wù)端配置防火墻,屏蔽客戶端 TCP 報(bào)文中標(biāo)志位是 ACK 的包,也就是當(dāng)服務(wù)端收到客戶端的 TCP ACK 的報(bào)文時(shí)就會(huì)丟棄,iptables 配置命令如下:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

接著,在客戶端執(zhí)行如下 tcpdump 命令:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

然后,客戶端向服務(wù)端發(fā)起 telnet,因?yàn)?telnet 命令是會(huì)發(fā)起 TCP 連接,所以用此命令做測試:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

此時(shí),由于服務(wù)端收不到第三次握手的 ACK 包,所以一直處于 SYN_RECV 狀態(tài):

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

而客戶端是已完成 TCP 連接建立,處于 ESTABLISHED 狀態(tài):

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

過了 1 分鐘后,觀察發(fā)現(xiàn)服務(wù)端的 TCP 連接不見了:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

過了 30 分別,客戶端依然還是處于 ESTABLISHED 狀態(tài):

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

接著,在剛才客戶端建立的 telnet 會(huì)話,輸入 123456 字符,進(jìn)行發(fā)送:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

持續(xù)「好長」一段時(shí)間,客戶端的 telnet 才斷開連接:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

以上就是本次的實(shí)現(xiàn)三的現(xiàn)象,這里存在兩個(gè)疑點(diǎn):

  • 為什么服務(wù)端原本處于 SYN_RECV 狀態(tài)的連接,過 1 分鐘后就消失了?

  • 為什么客戶端 telnet 輸入 123456 字符后,過了好長一段時(shí)間,telnet 才斷開連接?

不著急,我們把剛抓的數(shù)據(jù)包,用 Wireshark 打開分析,顯示的時(shí)序圖如下:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

上圖的流程:

  • 客戶端發(fā)送 SYN 包給服務(wù)端,服務(wù)端收到后,回了個(gè) SYN、ACK 包給客戶端,此時(shí)服務(wù)端的 TCP 連接處于 SYN_RECV 狀態(tài);

  • 客戶端收到服務(wù)端的  SYN、ACK 包后,給服務(wù)端回了個(gè) ACK 包,此時(shí)客戶端的 TCP 連接處于 ESTABLISHED 狀態(tài);

  • 由于服務(wù)端配置了防火墻,屏蔽了客戶端的 ACK 包,所以服務(wù)端一直處于 SYN_RECV 狀態(tài),沒有進(jìn)入  ESTABLISHED 狀態(tài),tcpdump 之所以能抓到客戶端的 ACK 包,是因?yàn)閿?shù)據(jù)包進(jìn)入系統(tǒng)的順序是先進(jìn)入 tcpudmp,后經(jīng)過 iptables;

  • 接著,服務(wù)端超時(shí)重傳了 SYN、ACK 包,重傳了 5 次后,也就是超過 tcp_synack_retries 的值(默認(rèn)值是 5),然后就沒有繼續(xù)重傳了,此時(shí)服務(wù)端的 TCP 連接主動(dòng)中止了,所以剛才處于 SYN_RECV 狀態(tài)的 TCP 連接斷開了,而客戶端依然處于ESTABLISHED 狀態(tài);

  • 雖然服務(wù)端 TCP 斷開了,但過了一段時(shí)間,發(fā)現(xiàn)客戶端依然處于ESTABLISHED 狀態(tài),于是就在客戶端的 telnet 會(huì)話輸入了 123456 字符;

  • 此時(shí)由于服務(wù)端已經(jīng)斷開連接,客戶端發(fā)送的數(shù)據(jù)報(bào)文,一直在超時(shí)重傳,每一次重傳,RTO 的值是指數(shù)增長的,所以持續(xù)了好長一段時(shí)間,客戶端的 telnet 才報(bào)錯(cuò)退出了,此時(shí)共重傳了 15 次。

通過這一波分析,剛才的兩個(gè)疑點(diǎn)已經(jīng)解除了:

  • 服務(wù)端在重傳 SYN、ACK 包時(shí),超過了最大重傳次數(shù) tcp_synack_retries,于是服務(wù)端的 TCP 連接主動(dòng)斷開了。

  • 客戶端向服務(wù)端發(fā)送數(shù)據(jù)包時(shí),由于服務(wù)端的 TCP 連接已經(jīng)退出了,所以數(shù)據(jù)包一直在超時(shí)重傳,共重傳了 15 次, telnet 就 斷開了連接。


TCP 第一次握手的 SYN 包超時(shí)重傳最大次數(shù)是由 tcp_syn_retries 指定,TCP 第二次握手的 SYN、ACK 包超時(shí)重傳最大次數(shù)是由 tcp_synack_retries 指定,那 TCP 建立連接后的數(shù)據(jù)包最大超時(shí)重傳次數(shù)是由什么參數(shù)指定呢?

TCP 建立連接后的數(shù)據(jù)包傳輸,最大超時(shí)重傳次數(shù)是由 tcp_retries2 指定,默認(rèn)值是 15 次,如下:

$ cat /proc/sys/net/ipv4/tcp_retries2
15

如果 15 次重傳都做完了,TCP 就會(huì)告訴應(yīng)用層說:“搞不定了,包怎么都傳不過去!”

那如果客戶端不發(fā)送數(shù)據(jù),什么時(shí)候才會(huì)斷開處于 ESTABLISHED 狀態(tài)的連接?

這里就需要提到 TCP 的 ?;顧C(jī)制。這個(gè)機(jī)制的原理是這樣的:

定義一個(gè)時(shí)間段,在這個(gè)時(shí)間段內(nèi),如果沒有任何連接相關(guān)的活動(dòng),TCP ?;顧C(jī)制會(huì)開始作用,每隔一個(gè)時(shí)間間隔,發(fā)送一個(gè)「探測報(bào)文」,該探測報(bào)文包含的數(shù)據(jù)非常少,如果連續(xù)幾個(gè)探測報(bào)文都沒有得到響應(yīng),則認(rèn)為當(dāng)前的 TCP 連接已經(jīng)死亡,系統(tǒng)內(nèi)核將錯(cuò)誤信息通知給上層應(yīng)用程序。

在 Linux 內(nèi)核可以有對(duì)應(yīng)的參數(shù)可以設(shè)置?;顣r(shí)間、?;钐綔y的次數(shù)、?;钐綔y的時(shí)間間隔,以下都為默認(rèn)值:

net.ipv4.tcp_keepalive_time=7200
net.ipv4.tcp_keepalive_intvl=75  
net.ipv4.tcp_keepalive_probes=9


  • tcp_keepalive_time=7200:表示保活時(shí)間是 7200 秒(2小時(shí)),也就 2 小時(shí)內(nèi)如果沒有任何連接相關(guān)的活動(dòng),則會(huì)啟動(dòng)?;顧C(jī)制

  • tcp_keepalive_intvl=75:表示每次檢測間隔 75 秒;

  • tcp_keepalive_probes=9:表示檢測 9 次無響應(yīng),認(rèn)為對(duì)方是不可達(dá)的,從而中斷本次的連接。

也就是說在 Linux 系統(tǒng)中,最少需要經(jīng)過 2 小時(shí) 11 分 15 秒才可以發(fā)現(xiàn)一個(gè)「死亡」連接。

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

這個(gè)時(shí)間是有點(diǎn)長的,所以如果我抓包足夠久,或許能抓到探測報(bào)文。

實(shí)驗(yàn)三的實(shí)驗(yàn)小結(jié)

在建立 TCP 連接時(shí),如果第三次握手的 ACK,服務(wù)端無法收到,則服務(wù)端就會(huì)短暫處于 SYN_RECV 狀態(tài),而客戶端會(huì)處于 ESTABLISHED 狀態(tài)。

由于服務(wù)端一直收不到 TCP 第三次握手的 ACK,則會(huì)一直重傳 SYN、ACK 包,直到重傳次數(shù)超過 tcp_synack_retries 值(默認(rèn)值 5 次)后,服務(wù)端就會(huì)斷開 TCP 連接。

而客戶端則會(huì)有兩種情況:

  • 如果客戶端沒發(fā)送數(shù)據(jù)包,一直處于 ESTABLISHED 狀態(tài),然后經(jīng)過 2 小時(shí) 11 分 15 秒才可以發(fā)現(xiàn)一個(gè)「死亡」連接,于是客戶端連接就會(huì)斷開連接。

  • 如果客戶端發(fā)送了數(shù)據(jù)包,一直沒有收到服務(wù)端對(duì)該數(shù)據(jù)包的確認(rèn)報(bào)文,則會(huì)一直重傳該數(shù)據(jù)包,直到重傳次數(shù)超過 tcp_retries2 值(默認(rèn)值 15 次)后,客戶端就會(huì)斷開 TCP 連接。


TCP 快速建立連接

客戶端在向服務(wù)端發(fā)起 HTTP GET 請(qǐng)求時(shí),一個(gè)完整的交互過程,需要 2.5 個(gè) RTT 的時(shí)延。

由于第三次握手是可以攜帶數(shù)據(jù)的,這時(shí)如果在第三次握手發(fā)起 HTTP GET 請(qǐng)求,需要 2 個(gè) RTT 的時(shí)延。

但是在下一次(不是同個(gè) TCP 連接的下一次)發(fā)起 HTTP GET 請(qǐng)求時(shí),經(jīng)歷的 RTT 也是一樣,如下圖:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
常規(guī) HTTP 請(qǐng)求

在 Linux 3.7 內(nèi)核版本中,提供了 TCP Fast Open 功能,這個(gè)功能可以減少 TCP 連接建立的時(shí)延。

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
常規(guī) HTTP 請(qǐng)求 與 Fast  Open HTTP 請(qǐng)求

  • 在第一次建立連接的時(shí)候,服務(wù)端在第二次握手產(chǎn)生一個(gè) Cookie (已加密)并通過 SYN、ACK 包一起發(fā)給客戶端,于是客戶端就會(huì)緩存這個(gè) Cookie,所以第一次發(fā)起 HTTP Get 請(qǐng)求的時(shí)候,還是需要 2 個(gè) RTT 的時(shí)延;

  • 在下次請(qǐng)求的時(shí)候,客戶端在 SYN 包帶上 Cookie 發(fā)給服務(wù)端,就提前可以跳過三次握手的過程,因?yàn)?Cookie 中維護(hù)了一些信息,服務(wù)端可以從 Cookie 獲取 TCP 相關(guān)的信息,這時(shí)發(fā)起的 HTTP GET 請(qǐng)求就只需要 1 個(gè) RTT 的時(shí)延;

注:客戶端在請(qǐng)求并存儲(chǔ)了 Fast Open Cookie 之后,可以不斷重復(fù) TCP Fast Open 直至服務(wù)器認(rèn)為 Cookie 無效(通常為過期)

在 Linux 上如何打開 Fast Open 功能?

可以通過設(shè)置 net.ipv4.tcp_fastopn 內(nèi)核參數(shù),來打開 Fast Open 功能。

net.ipv4.tcp_fastopn 各個(gè)值的意義:

  • 0 關(guān)閉

  • 1 作為客戶端使用 Fast Open 功能

  • 2 作為服務(wù)端使用 Fast Open 功能

  • 3 無論作為客戶端還是服務(wù)器,都可以使用 Fast Open 功能


TCP Fast Open 抓包分析

在下圖,數(shù)據(jù)包 7 號(hào),客戶端發(fā)起了第二次 TCP 連接時(shí),SYN 包會(huì)攜帶 Cooike,并且有長度為 5 的數(shù)據(jù)。

服務(wù)端收到后,校驗(yàn) Cooike 合法,于是就回了 SYN、ACK 包,并且確認(rèn)應(yīng)答收到了客戶端的數(shù)據(jù)包,ACK = 5 + 1 = 6

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
TCP Fast Open 抓包分析

TCP 重復(fù)確認(rèn)和快速重傳

當(dāng)接收方收到亂序數(shù)據(jù)包時(shí),會(huì)發(fā)送重復(fù)的 ACK,以使告知發(fā)送方要重發(fā)該數(shù)據(jù)包,當(dāng)發(fā)送方收到 3 個(gè)重復(fù) ACK 時(shí),就會(huì)觸發(fā)快速重傳,立該重發(fā)丟失數(shù)據(jù)包。

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
快速重傳機(jī)制

TCP 重復(fù)確認(rèn)和快速重傳的一個(gè)案例,用 Wireshark 分析,顯示如下:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

  • 數(shù)據(jù)包 1 期望的下一個(gè)數(shù)據(jù)包 Seq 是 1,但是數(shù)據(jù)包 2 發(fā)送的 Seq 卻是 10945,說明收到的是亂序數(shù)據(jù)包,于是回了數(shù)據(jù)包 3 ,還是同樣的 Seq = 1,Ack = 1,這表明是重復(fù)的 ACK;

  • 數(shù)據(jù)包 4 和 6 依然是亂序的數(shù)據(jù)包,于是依然回了重復(fù)的 ACK;

  • 當(dāng)對(duì)方收到三次重復(fù)的 ACK 后,于是就快速重傳了 Seq = 1 、Len = 1368 的數(shù)據(jù)包 8;

  • 當(dāng)收到重傳的數(shù)據(jù)包后,發(fā)現(xiàn) Seq = 1 是期望的數(shù)據(jù)包,于是就發(fā)送了確認(rèn)報(bào)文 ACK;

注意:快速重傳和重復(fù) ACK 標(biāo)記信息是 Wireshark 的功能,非數(shù)據(jù)包本身的信息。

以上案例在 TCP 三次握手時(shí)協(xié)商開啟了選擇性確認(rèn) SACK,因此一旦數(shù)據(jù)包丟失并收到重復(fù) ACK ,即使在丟失數(shù)據(jù)包之后還成功接收了其他數(shù)據(jù)包,也只需要重傳丟失的數(shù)據(jù)包。如果不啟用 SACK,就必須重傳丟失包之后的每個(gè)數(shù)據(jù)包。

如果要支持 SACK,必須雙方都要支持。在 Linux 下,可以通過 net.ipv4.tcp_sack 參數(shù)打開這個(gè)功能(Linux 2.4 后默認(rèn)打開)。


TCP 流量控制

TCP 為了防止發(fā)送方無腦的發(fā)送數(shù)據(jù),導(dǎo)致接收方緩沖區(qū)被填滿,所以就有了滑動(dòng)窗口的機(jī)制,它可利用接收方的接收窗口來控制發(fā)送方要發(fā)送的數(shù)據(jù)量,也就是流量控制。

接收窗口是由接收方指定的值,存儲(chǔ)在 TCP 頭部中,它可以告訴發(fā)送方自己的 TCP 緩沖空間區(qū)大小,這個(gè)緩沖區(qū)是給應(yīng)用程序讀取數(shù)據(jù)的空間:

  • 如果應(yīng)用程序讀取了緩沖區(qū)的數(shù)據(jù),那么緩沖空間區(qū)的就會(huì)把被讀取的數(shù)據(jù)移除

  • 如果應(yīng)用程序沒有讀取數(shù)據(jù),則數(shù)據(jù)會(huì)一直滯留在緩沖區(qū)。

接收窗口的大小,是在 TCP 三次握手中協(xié)商好的,后續(xù)數(shù)據(jù)傳輸時(shí),接收方發(fā)送確認(rèn)應(yīng)答 ACK 報(bào)文時(shí),會(huì)攜帶當(dāng)前的接收窗口的大小,以此來告知發(fā)送方。

假設(shè)接收方接收到數(shù)據(jù)后,應(yīng)用層能很快的從緩沖區(qū)里讀取數(shù)據(jù),那么窗口大小會(huì)一直保持不變,過程如下:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
理想狀態(tài)下的窗口變化

但是現(xiàn)實(shí)中服務(wù)器會(huì)出現(xiàn)繁忙的情況,當(dāng)應(yīng)用程序讀取速度慢,那么緩存空間會(huì)慢慢被占滿,于是為了保證發(fā)送方發(fā)送的數(shù)據(jù)不會(huì)超過緩沖區(qū)大小,則服務(wù)器會(huì)調(diào)整窗口大小的值,接著通過 ACK 報(bào)文通知給對(duì)方,告知現(xiàn)在的接收窗口大小,從而控制發(fā)送方發(fā)送的數(shù)據(jù)大小。

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
服務(wù)端繁忙狀態(tài)下的窗口變化

零窗口通知與窗口探測

假設(shè)接收方處理數(shù)據(jù)的速度跟不上接收數(shù)據(jù)的速度,緩存就會(huì)被占滿,從而導(dǎo)致接收窗口為 0,當(dāng)發(fā)送方接收到零窗口通知時(shí),就會(huì)停止發(fā)送數(shù)據(jù)。

如下圖,可以接收方的窗口大小在不斷的收縮至 0:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
窗口大小在收縮

接著,發(fā)送方會(huì)定時(shí)發(fā)送窗口大小探測報(bào)文,以便及時(shí)知道接收方窗口大小的變化。

以下圖 Wireshark 分析圖作為例子說明:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
零窗口 與 窗口探測

  • 發(fā)送方發(fā)送了數(shù)據(jù)包 1 給接收方,接收方收到后,由于緩沖區(qū)被占滿,回了個(gè)零窗口通知;

  • 發(fā)送方收到零窗口通知后,就不再發(fā)送數(shù)據(jù)了,直到過了 3.4 秒后,發(fā)送了一個(gè) TCP Keep-Alive 報(bào)文,也就是窗口大小探測報(bào)文;

  • 當(dāng)接收方收到窗口探測報(bào)文后,就立馬回一個(gè)窗口通知,但是窗口大小還是 0;

  • 發(fā)送方發(fā)現(xiàn)窗口還是 0,于是繼續(xù)等待了 6.8(翻倍) 秒后,又發(fā)送了窗口探測報(bào)文,接收方依然還是回了窗口為 0 的通知;

  • 發(fā)送方發(fā)現(xiàn)窗口還是 0,于是繼續(xù)等待了 13.5(翻倍) 秒后,又發(fā)送了窗口探測報(bào)文,接收方依然還是回了窗口為 0 的通知;

可以發(fā)現(xiàn),這些窗口探測報(bào)文以 3.4s、6.5s、13.5s 的間隔出現(xiàn),說明超時(shí)時(shí)間會(huì)翻倍遞增。

這連接暫停了 25s,想象一下你在打王者的時(shí)候,25s 的延遲你還能上王者嗎?

發(fā)送窗口的分析

在 Wireshark 看到的 Windows size 也就是 " win = ",這個(gè)值表示發(fā)送窗口嗎?

這不是發(fā)送窗口,而是在向?qū)Ψ铰暶髯约旱慕邮沾翱凇?/p>

你可能會(huì)好奇,抓包文件里有「Window size scaling factor」,它其實(shí)是算出實(shí)際窗口大小的乘法因子,「Windos size value」實(shí)際上并不是真實(shí)的窗口大小,真實(shí)窗口大小的計(jì)算公式如下:

「Windos size value」 * 「Window size scaling factor」 = 「Caculated window size 」

對(duì)應(yīng)的下圖案例,也就是 32 * 2048 = 65536。

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

實(shí)際上是 Caculated window size 的值是 Wireshark 工具幫我們算好的,Window size scaling factor 和 Windos size value 的值是在 TCP 頭部中,其中 Window size scaling factor 是在三次握手過程中確定的,如果你抓包的數(shù)據(jù)沒有 TCP 三次握手,那可能就無法算出真實(shí)的窗口大小的值,如下圖:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

如何在包里看出發(fā)送窗口的大???

很遺憾,沒有簡單的辦法,發(fā)送窗口雖然是由接收窗口決定,但是它又可以被網(wǎng)絡(luò)因素影響,也就是擁塞窗口,實(shí)際上發(fā)送窗口是值是 min(擁塞窗口,接收窗口)。

發(fā)送窗口和 MSS 有什么關(guān)系?

發(fā)送窗口決定了一口氣能發(fā)多少字節(jié),而 MSS 決定了這些字節(jié)要分多少包才能發(fā)完。

舉個(gè)例子,如果發(fā)送窗口為 16000 字節(jié)的情況下,如果 MSS 是 1000 字節(jié),那就需要發(fā)送 1600/1000 = 16 個(gè)包。

發(fā)送方在一個(gè)窗口發(fā)出 n 個(gè)包,是不是需要 n 個(gè) ACK 確認(rèn)報(bào)文?

不一定,因?yàn)?TCP 有累計(jì)確認(rèn)機(jī)制,所以當(dāng)收到多個(gè)數(shù)據(jù)包時(shí),只需要應(yīng)答最后一個(gè)數(shù)據(jù)包的 ACK 報(bào)文就可以了。


TCP 延遲確認(rèn)與 Nagle 算法

當(dāng)我們 TCP 報(bào)文的承載的數(shù)據(jù)非常小的時(shí)候,例如幾個(gè)字節(jié),那么整個(gè)網(wǎng)絡(luò)的效率是很低的,因?yàn)槊總€(gè) TCP 報(bào)文中都有會(huì) 20 個(gè)字節(jié)的 TCP 頭部,也會(huì)有 20 個(gè)字節(jié)的 IP 頭部,而數(shù)據(jù)只有幾個(gè)字節(jié),所以在整個(gè)報(bào)文中有效數(shù)據(jù)占有的比重就會(huì)非常低。

這就好像快遞員開著大貨車送一個(gè)小包裹一樣浪費(fèi)。

那么就出現(xiàn)了常見的兩種策略,來減少小報(bào)文的傳輸,分別是:

  • Nagle 算法

  • 延遲確認(rèn)


Nagle 算法是如何避免大量 TCP 小數(shù)據(jù)報(bào)文的傳輸?

Nagle 算法做了一些策略來避免過多的小數(shù)據(jù)報(bào)文發(fā)送,這可提高傳輸效率。

Nagle 算法的策略:

  • 沒有已發(fā)送未確認(rèn)報(bào)文時(shí),立刻發(fā)送數(shù)據(jù)。

  • 存在未確認(rèn)報(bào)文時(shí),直到「沒有已發(fā)送未確認(rèn)報(bào)文」或「數(shù)據(jù)長度達(dá)到 MSS 大小」時(shí),再發(fā)送數(shù)據(jù)。

只要沒滿足上面條件中的一條,發(fā)送方一直在囤積數(shù)據(jù),直到滿足上面的發(fā)送條件。

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
禁用 Nagle 算法 與 啟用 Nagle 算法

上圖右側(cè)啟用了 Nagle 算法,它的發(fā)送數(shù)據(jù)的過程:

  • 一開始由于沒有已發(fā)送未確認(rèn)的報(bào)文,所以就立刻發(fā)了 H 字符;

  • 接著,在還沒收到對(duì) H 字符的確認(rèn)報(bào)文時(shí),發(fā)送方就一直在囤積數(shù)據(jù),直到收到了確認(rèn)報(bào)文后,此時(shí)就沒有已發(fā)送未確認(rèn)的報(bào)文,于是就把囤積后的 ELL 字符一起發(fā)給了接收方;

  • 待收到對(duì) ELL 字符的確認(rèn)報(bào)文后,于是把最后一個(gè) O 字符發(fā)送出去

可以看出,Nagle 算法一定會(huì)有一個(gè)小報(bào)文,也就是在最開始的時(shí)候。

另外,Nagle 算法默認(rèn)是打開的,如果對(duì)于一些需要小數(shù)據(jù)包交互的場景的程序,比如,telnet 或 ssh 這樣的交互性比較強(qiáng)的程序,則需要關(guān)閉 Nagle 算法。

可以在 Socket 設(shè)置 TCP_NODELAY 選項(xiàng)來關(guān)閉這個(gè)算法(關(guān)閉 Nagle 算法沒有全局參數(shù),需要根據(jù)每個(gè)應(yīng)用自己的特點(diǎn)來關(guān)閉)。

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
關(guān)閉 Nagle 算法

那延遲確認(rèn)又是什么?

事實(shí)上當(dāng)沒有攜帶數(shù)據(jù)的 ACK,他的網(wǎng)絡(luò)效率也是很低的,因?yàn)樗灿?40 個(gè)字節(jié)的 IP 頭 和 TCP 頭,但沒有攜帶數(shù)據(jù)。

為了解決 ACK 傳輸效率低問題,所以就衍生出了 TCP 延遲確認(rèn)。

TCP 延遲確認(rèn)的策略:

  • 當(dāng)有響應(yīng)數(shù)據(jù)要發(fā)送時(shí),ACK 會(huì)隨著響應(yīng)數(shù)據(jù)一起立刻發(fā)送給對(duì)方

  • 當(dāng)沒有響應(yīng)數(shù)據(jù)要發(fā)送時(shí),ACK 將會(huì)延遲一段時(shí)間,以等待是否有響應(yīng)數(shù)據(jù)可以一起發(fā)送

  • 如果在延遲等待發(fā)送 ACK 期間,對(duì)方的第二個(gè)數(shù)據(jù)報(bào)文又到達(dá)了,這時(shí)就會(huì)立刻發(fā)送 ACK


實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
TCP 延遲確認(rèn)

延遲等待的時(shí)間是在 Linux 內(nèi)核中的定義的,如下圖:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

關(guān)鍵就需要 HZ 這個(gè)數(shù)值大小,HZ 是跟系統(tǒng)的時(shí)鐘頻率有關(guān),每個(gè)操作系統(tǒng)都不一樣,在我的 Linux 系統(tǒng)中 HZ 大小是 1000,如下圖:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

知道了 HZ 的大小,那么就可以算出:

  • 最大延遲確認(rèn)時(shí)間是 200 ms (1000/5)

  • 最短延遲確認(rèn)時(shí)間是 40 ms (1000/25)

TCP 延遲確認(rèn)可以在 Socket 設(shè)置 TCP_QUICKACK 選項(xiàng)來關(guān)閉這個(gè)算法。

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
關(guān)閉 TCP 延遲確認(rèn)

延遲確認(rèn) 和 Nagle 算法混合使用時(shí),會(huì)產(chǎn)生新的問題

當(dāng) TCP 延遲確認(rèn) 和 Nagle 算法混合使用時(shí),會(huì)導(dǎo)致時(shí)耗增長,如下圖:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP
TCP 延遲確認(rèn) 和 Nagle 算法混合使用

發(fā)送方使用了 Nagle 算法,接收方使用了 TCP 延遲確認(rèn)會(huì)發(fā)生如下的過程:

  • 發(fā)送方先發(fā)出一個(gè)小報(bào)文,接收方收到后,由于延遲確認(rèn)機(jī)制,自己又沒有要發(fā)送的數(shù)據(jù),只能干等著發(fā)送方的下一個(gè)報(bào)文到達(dá);

  • 而發(fā)送方由于 Nagle 算法機(jī)制,在未收到第一個(gè)報(bào)文的確認(rèn)前,是不會(huì)發(fā)送后續(xù)的數(shù)據(jù);

  • 所以接收方只能等待最大時(shí)間 200 ms 后,才回 ACK 報(bào)文,發(fā)送方收到第一個(gè)報(bào)文的確認(rèn)報(bào)文后,也才可以發(fā)送后續(xù)的數(shù)據(jù)。

很明顯,這兩個(gè)同時(shí)使用會(huì)造成額外的時(shí)延,這就會(huì)使得網(wǎng)絡(luò)"很慢"的感覺。

要解決這個(gè)問題,只有兩個(gè)辦法:

  • 要么發(fā)送方關(guān)閉 Nagle 算法

  • 要么接收方關(guān)閉 TCP 延遲確認(rèn)


巨人的肩膀

[1] Wireshark網(wǎng)絡(luò)分析的藝術(shù).林沛滿.人民郵電出版社.

[2] Wireshark網(wǎng)絡(luò)分析就這么簡單.林沛滿.人民郵電出版社.

[3] Wireshark數(shù)據(jù)包分析實(shí)戰(zhàn).Chris Sanders .人民郵電出版社.

特別推薦一個(gè)分享架構(gòu)+算法的優(yōu)質(zhì)內(nèi)容,還沒關(guān)注的小伙伴,可以長按關(guān)注一下:

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

長按訂閱更多精彩▼

實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP

如有收獲,點(diǎn)個(gè)在看,誠摯感謝

免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場,如有問題,請(qǐng)聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動(dòng)力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉