日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當前位置:首頁 > 單片機 > 架構師社區(qū)
[導讀]每日一句英語學習,每天進步一點點: 前言 “哈?啥是大白鯊?” 咳咳,主要是因為網絡分析工具 Wireshark 的圖標特別像大白鯊頂部的角。 不信你看: Wireshark “為什么拖了怎么久才發(fā)文?” 為了讓大家更容易「看得見」 TCP,我搭建不少測試環(huán)境,并且數據

每日一句英語學習,每天進步一點點:
實戰(zhàn)!我用“大白鯊”讓你看見 TCP

前言

“哈?啥是大白鯊?”

咳咳,主要是因為網絡分析工具 Wireshark 的圖標特別像大白鯊頂部的角。

不信你看:

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

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

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

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

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

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

正文

顯形“不可見”的網絡包

網絡世界中的數據包交互我們肉眼是看不見的,它們就好像隱形了一樣,我們對著課本學習計算機網絡的時候就會覺得非常的抽象,加大了學習的難度。

還別說,我自己在大學的時候,也是如此。

直到工作后,認識了兩大分析網絡的利器:tcpdump 和 Wireshark,這兩大利器把我們“看不見”的數據包,呈現在我們眼前,一目了然。

唉,當初大學學習計網的時候,要是能知道這兩個工具,就不會學的一臉懵逼。

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

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

  • tcpdump 僅支持命令行格式使用,常用在 Linux 服務器中抓取和分析網絡包。

  • Wireshark 除了可以抓包外,還提供了可視化分析網絡包的圖形頁面。

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

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

tcpdump 在 Linux 下如何抓包?

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

假設我們要抓取下面的 ping 的數據包:

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

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

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

那么當 tcpdump 抓取到 icmp 數據包后, 輸出格式如下:

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

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

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

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

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

接下來,我們再來看看常用的過濾表用法,在上面的 ping 例子中,我們用過的是 icmp and host 183.232.231.174,表示抓取 icmp 協(xié)議的數據包,以及源地址或目標地址為 183.232.231.174 的包。其他常用的過濾選項,我也整理成了下面這個表格。

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

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

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

Wireshark 工具如何分析數據包?

Wireshark 除了可以抓包外,還提供了可視化分析網絡包的圖形頁面,同時,還內置了一系列的匯總分析工具。

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

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

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

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

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

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

實戰(zhàn)!我用“大白鯊”讓你看見 TCP
ping 網絡包

  • 可以在數據鏈路層,看到 MAC 包頭信息,如源 MAC 地址和目標 MAC 地址等字段;

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

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

Wireshark 用了分層的方式,展示了各個層的包頭信息,把“不可見”的數據包,清清楚楚的展示了給我們,還有理由學不好計算機網絡嗎?是不是相見恨晚?

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

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

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

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

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

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

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

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

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

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

實戰(zhàn)!我用“大白鯊”讓你看見 TCP
HTTP 網絡包

我們都知道 HTTP 是基于 TCP 協(xié)議進行傳輸的,那么:

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

  • 中間是 HTTP 請求和響應的包

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

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

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

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

實際上是因為 Wireshark 工具幫我們做了優(yōu)化,它默認顯示的是序列號 seq 是相對值,而不是真實值。

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

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

取消后,Seq 顯示的就是真實值了:

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

可見,客戶端和服務端的序列號實際上是不同的,序列號是一個隨機值。

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

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

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

因為服務器端收到客戶端的 FIN 后,服務器端同時也要關閉連接,這樣就可以把 ACKFIN 合并到一起發(fā)送,節(jié)省了一個包,變成了“三次揮手”。

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

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

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

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

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

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

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

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

有的小伙伴可能說:“很簡單呀,包丟了就會重傳嘛。”

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

  • 那會重傳幾次?

  • 超時重傳的時間 RTO 會如何變化?

  • 在 Linux 下如何設置重傳次數?

  • ….

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

不知道沒關系,接下里我用三個實驗案例,帶大家一起探究探究這三種異常。

實驗場景

本次實驗用了兩臺虛擬機,一臺作為服務端,一臺作為客戶端,它們的關系如下:

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

  • 客戶端和服務端都是 CentOs 6.5 Linux,Linux 內核版本 2.6.32

  • 服務端 192.168.12.36,apache web 服務

  • 客戶端 192.168.12.37

實驗一:TCP 第一次握手 SYN 丟包

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

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

其間 tcpdump 抓包的命令如下:

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

過了一會, curl 返回了超時連接的錯誤:

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

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

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

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

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

  • 第一次是在 1 秒超時重傳

  • 第二次是在 3 秒超時重傳

  • 第三次是在 7 秒超時重傳

  • 第四次是在 15 秒超時重傳

  • 第五次是在 31 秒超時重傳

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

在 Linux 中,第一次握手的 SYN 超時重傳次數,是如下內核參數指定的:

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

tcp_syn_retries 默認值為 5,也就是 SYN 最大重傳次數是 5 次。

接下來,我們繼續(xù)做實驗,把 tcp_syn_retries 設置為 2 次:

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

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

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

實驗一的實驗小結

通過實驗一的實驗結果,我們可以得知,當客戶端發(fā)起的 TCP 第一次握手 SYN 包,在超時時間內沒收到服務端的 ACK,就會在超時重傳 SYN 數據包,每次超時重傳的 RTO 是翻倍上漲的,直到 SYN 包的重傳次數到達 tcp_syn_retries 值后,客戶端不再發(fā)送 SYN 包。

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

實驗二:TCP 第二次握手 SYN、ACK 丟包

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

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

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

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

date 返回的時間前后,可以算出大概 1 分鐘后,curl 報錯退出了。

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

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

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

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

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

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

所以,我們可以發(fā)現,當第二次握手的 SYN、ACK 丟包時,客戶端會超時重發(fā) SYN 包,服務端也會超時重傳 SYN、ACK 包。

咦?客戶端設置了防火墻,屏蔽了服務端的網絡包,為什么 tcpdump 還能抓到服務端的網絡包?

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

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

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

網絡包進入主機后的順序如下:

  • 進來的順序 Wire -> NIC -> tcpdump -> netfilter/iptables

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


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

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

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

是的,TCP 第二次握手 SYN、ACK 包的最大重傳次數默認值是 5 次。

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

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

  1. 客戶端配置防火墻屏蔽服務端的數據包

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

把抓取的數據包,用 Wireshark 打開分析,顯示的時序圖如下:

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

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

  • 客戶端的 SYN 只超時重傳了 1 次,因為 tcp_syn_retries 值為 1

  • 服務端應答了客戶端超時重傳的 SYN 包后,由于一直收不到客戶端的 ACK 包,所以服務端一直在超時重傳 SYN、ACK 包,每次的 RTO 也是指數上漲的,一共超時重傳了 5 次,因為 tcp_synack_retries 值為 5

接著,我把 tcp_synack_retries 設置為 2,tcp_syn_retries 依然設置為 1:

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

依然保持一樣的實驗步驟進行操作,接著把抓取的數據包,用 Wireshark 打開分析,顯示的時序圖如下:

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

可見:

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

  • 服務端的 SYN、ACK 超時重傳了 2 次,符合 tcp_synack_retries 設置的值


實驗二的實驗小結

通過實驗二的實驗結果,我們可以得知,當 TCP 第二次握手 SYN、ACK 包丟了后,客戶端 SYN 包會發(fā)生超時重傳,服務端 SYN、ACK 也會發(fā)生超時重傳。

客戶端 SYN 包超時重傳的最大次數,是由 tcp_syn_retries 決定的,默認值是 5 次;服務端 SYN、ACK 包時重傳的最大次數,是由 tcp_synack_retries 決定的,默認值是 5 次。

實驗三:TCP 第三次握手 ACK 丟包

為了模擬 TCP 第三次握手 ACK 包丟,我的實驗方法是在服務端配置防火墻,屏蔽客戶端 TCP 報文中標志位是 ACK 的包,也就是當服務端收到客戶端的 TCP ACK 的報文時就會丟棄,iptables 配置命令如下:

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

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

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

然后,客戶端向服務端發(fā)起 telnet,因為 telnet 命令是會發(fā)起 TCP 連接,所以用此命令做測試:

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

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

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

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

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

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

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

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

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

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

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

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

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

以上就是本次的實現三的現象,這里存在兩個疑點:

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

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

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

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

上圖的流程:

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

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

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

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

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

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

通過這一波分析,剛才的兩個疑點已經解除了:

  • 服務端在重傳 SYN、ACK 包時,超過了最大重傳次數 tcp_synack_retries,于是服務端的 TCP 連接主動斷開了。

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


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

TCP 建立連接后的數據包傳輸,最大超時重傳次數是由 tcp_retries2 指定,默認值是 15 次,如下:

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

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

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

這里就需要提到 TCP 的 ?;顧C制。這個機制的原理是這樣的:

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

在 Linux 內核可以有對應的參數可以設置?;顣r間、?;钐綔y的次數、?;钐綔y的時間間隔,以下都為默認值:

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


  • tcp_keepalive_time=7200:表示?;顣r間是 7200 秒(2小時),也就 2 小時內如果沒有任何連接相關的活動,則會啟動保活機制

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

  • tcp_keepalive_probes=9:表示檢測 9 次無響應,認為對方是不可達的,從而中斷本次的連接。

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

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

這個時間是有點長的,所以如果我抓包足夠久,或許能抓到探測報文。

實驗三的實驗小結

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

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

而客戶端則會有兩種情況:

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

  • 如果客戶端發(fā)送了數據包,一直沒有收到服務端對該數據包的確認報文,則會一直重傳該數據包,直到重傳次數超過 tcp_retries2 值(默認值 15 次)后,客戶端就會斷開 TCP 連接。


TCP 快速建立連接

客戶端在向服務端發(fā)起 HTTP GET 請求時,一個完整的交互過程,需要 2.5 個 RTT 的時延。

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

但是在下一次(不是同個 TCP 連接的下一次)發(fā)起 HTTP GET 請求時,經歷的 RTT 也是一樣,如下圖:

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

在 Linux 3.7 內核版本中,提供了 TCP Fast Open 功能,這個功能可以減少 TCP 連接建立的時延。

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

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

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

注:客戶端在請求并存儲了 Fast Open Cookie 之后,可以不斷重復 TCP Fast Open 直至服務器認為 Cookie 無效(通常為過期)

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

可以通過設置 net.ipv4.tcp_fastopn 內核參數,來打開 Fast Open 功能。

net.ipv4.tcp_fastopn 各個值的意義:

  • 0 關閉

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

  • 2 作為服務端使用 Fast Open 功能

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


TCP Fast Open 抓包分析

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

服務端收到后,校驗 Cooike 合法,于是就回了 SYN、ACK 包,并且確認應答收到了客戶端的數據包,ACK = 5 + 1 = 6

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

TCP 重復確認和快速重傳

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

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

TCP 重復確認和快速重傳的一個案例,用 Wireshark 分析,顯示如下:

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

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

  • 數據包 4 和 6 依然是亂序的數據包,于是依然回了重復的 ACK;

  • 當對方收到三次重復的 ACK 后,于是就快速重傳了 Seq = 1 、Len = 1368 的數據包 8;

  • 當收到重傳的數據包后,發(fā)現 Seq = 1 是期望的數據包,于是就發(fā)送了確認報文 ACK;

注意:快速重傳和重復 ACK 標記信息是 Wireshark 的功能,非數據包本身的信息。

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

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


TCP 流量控制

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

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

  • 如果應用程序讀取了緩沖區(qū)的數據,那么緩沖空間區(qū)的就會把被讀取的數據移除

  • 如果應用程序沒有讀取數據,則數據會一直滯留在緩沖區(qū)。

接收窗口的大小,是在 TCP 三次握手中協(xié)商好的,后續(xù)數據傳輸時,接收方發(fā)送確認應答 ACK 報文時,會攜帶當前的接收窗口的大小,以此來告知發(fā)送方。

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

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

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

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

零窗口通知與窗口探測

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

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

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

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

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

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

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

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

  • 當接收方收到窗口探測報文后,就立馬回一個窗口通知,但是窗口大小還是 0;

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

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

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

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

發(fā)送窗口的分析

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

這不是發(fā)送窗口,而是在向對方聲明自己的接收窗口。

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

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

對應的下圖案例,也就是 32 * 2048 = 65536。

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

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

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

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

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

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

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

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

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

不一定,因為 TCP 有累計確認機制,所以當收到多個數據包時,只需要應答最后一個數據包的 ACK 報文就可以了。


TCP 延遲確認與 Nagle 算法

當我們 TCP 報文的承載的數據非常小的時候,例如幾個字節(jié),那么整個網絡的效率是很低的,因為每個 TCP 報文中都有會 20 個字節(jié)的 TCP 頭部,也會有 20 個字節(jié)的 IP 頭部,而數據只有幾個字節(jié),所以在整個報文中有效數據占有的比重就會非常低。

這就好像快遞員開著大貨車送一個小包裹一樣浪費。

那么就出現了常見的兩種策略,來減少小報文的傳輸,分別是:

  • Nagle 算法

  • 延遲確認


Nagle 算法是如何避免大量 TCP 小數據報文的傳輸?

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

Nagle 算法的策略:

  • 沒有已發(fā)送未確認報文時,立刻發(fā)送數據。

  • 存在未確認報文時,直到「沒有已發(fā)送未確認報文」或「數據長度達到 MSS 大小」時,再發(fā)送數據。

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

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

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

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

  • 接著,在還沒收到對 H 字符的確認報文時,發(fā)送方就一直在囤積數據,直到收到了確認報文后,此時就沒有已發(fā)送未確認的報文,于是就把囤積后的 ELL 字符一起發(fā)給了接收方;

  • 待收到對 ELL 字符的確認報文后,于是把最后一個 O 字符發(fā)送出去

可以看出,Nagle 算法一定會有一個小報文,也就是在最開始的時候。

另外,Nagle 算法默認是打開的,如果對于一些需要小數據包交互的場景的程序,比如,telnet 或 ssh 這樣的交互性比較強的程序,則需要關閉 Nagle 算法。

可以在 Socket 設置 TCP_NODELAY 選項來關閉這個算法(關閉 Nagle 算法沒有全局參數,需要根據每個應用自己的特點來關閉)。

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

那延遲確認又是什么?

事實上當沒有攜帶數據的 ACK,他的網絡效率也是很低的,因為它也有 40 個字節(jié)的 IP 頭 和 TCP 頭,但沒有攜帶數據。

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

TCP 延遲確認的策略:

  • 當有響應數據要發(fā)送時,ACK 會隨著響應數據一起立刻發(fā)送給對方

  • 當沒有響應數據要發(fā)送時,ACK 將會延遲一段時間,以等待是否有響應數據可以一起發(fā)送

  • 如果在延遲等待發(fā)送 ACK 期間,對方的第二個數據報文又到達了,這時就會立刻發(fā)送 ACK


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

延遲等待的時間是在 Linux 內核中的定義的,如下圖:

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

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

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

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

  • 最大延遲確認時間是 200 ms (1000/5)

  • 最短延遲確認時間是 40 ms (1000/25)

TCP 延遲確認可以在 Socket 設置 TCP_QUICKACK 選項來關閉這個算法。

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

延遲確認 和 Nagle 算法混合使用時,會產生新的問題

當 TCP 延遲確認 和 Nagle 算法混合使用時,會導致時耗增長,如下圖:

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

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

  • 發(fā)送方先發(fā)出一個小報文,接收方收到后,由于延遲確認機制,自己又沒有要發(fā)送的數據,只能干等著發(fā)送方的下一個報文到達;

  • 而發(fā)送方由于 Nagle 算法機制,在未收到第一個報文的確認前,是不會發(fā)送后續(xù)的數據;

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

很明顯,這兩個同時使用會造成額外的時延,這就會使得網絡"很慢"的感覺。

要解決這個問題,只有兩個辦法:

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

  • 要么接收方關閉 TCP 延遲確認


巨人的肩膀

[1] Wireshark網絡分析的藝術.林沛滿.人民郵電出版社.

[2] Wireshark網絡分析就這么簡單.林沛滿.人民郵電出版社.

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

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

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

長按訂閱更多精彩▼

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

如有收獲,點個在看,誠摯感謝

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

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

LED驅動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關鍵字: 驅動電源

在工業(yè)自動化蓬勃發(fā)展的當下,工業(yè)電機作為核心動力設備,其驅動電源的性能直接關系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護是驅動電源設計中至關重要的兩個環(huán)節(jié),集成化方案的設計成為提升電機驅動性能的關鍵。

關鍵字: 工業(yè)電機 驅動電源

LED 驅動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設備的使用壽命。然而,在實際應用中,LED 驅動電源易損壞的問題卻十分常見,不僅增加了維護成本,還影響了用戶體驗。要解決這一問題,需從設計、生...

關鍵字: 驅動電源 照明系統(tǒng) 散熱

根據LED驅動電源的公式,電感內電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關鍵字: LED 設計 驅動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產業(yè)的重要發(fā)展方向。電動汽車的核心技術之一是電機驅動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機驅動系統(tǒng)中的關鍵元件,其性能直接影響到電動汽車的動力性能和...

關鍵字: 電動汽車 新能源 驅動電源

在現代城市建設中,街道及停車場照明作為基礎設施的重要組成部分,其質量和效率直接關系到城市的公共安全、居民生活質量和能源利用效率。隨著科技的進步,高亮度白光發(fā)光二極管(LED)因其獨特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關鍵字: 發(fā)光二極管 驅動電源 LED

LED通用照明設計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數校正(PFC)、空間受限和可靠性等。

關鍵字: LED 驅動電源 功率因數校正

在LED照明技術日益普及的今天,LED驅動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關鍵字: LED照明技術 電磁干擾 驅動電源

開關電源具有效率高的特性,而且開關電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機重量也有所下降,所以,現在的LED驅動電源

關鍵字: LED 驅動電源 開關電源

LED驅動電源是把電源供應轉換為特定的電壓電流以驅動LED發(fā)光的電壓轉換器,通常情況下:LED驅動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關鍵字: LED 隧道燈 驅動電源
關閉