1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        知乎千贊的 TCP 文章,我寫錯了一個點(diǎn)。。。

        共 6275字,需瀏覽 13分鐘

         ·

        2021-10-18 01:15

        ?

        ?
        大家好,我是小林。
        之前我在「實(shí)戰(zhàn)!我用“大白鯊”讓你看見 TCP」這篇文章里做了 TCP 三次握手的三個實(shí)驗(yàn):
        • 實(shí)驗(yàn)一:模擬 TCP 第一次握手的 SYN 丟包;

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

        • 實(shí)驗(yàn)三:模擬 TCP 第三次握手的 ACK 包丟;

        這篇文章在知乎還挺高贊的,超過 1000 贊了。
        不過,實(shí)驗(yàn)二分析的過程中,之前有個讀者反饋給我說,我說的有問題。
        實(shí)驗(yàn)二我是在客戶端的防火墻加入了屏蔽服務(wù)端所有的數(shù)據(jù)包來模擬第二次握手丟失的現(xiàn)象,先給大家看看當(dāng)時的實(shí)驗(yàn)圖,以及我說分析過程。
        圖中紅色框起來的那句話有問題,正確來說:第二次握手的 SYN、ACK 報文的重傳定時器并不會因?yàn)槭盏?SYN 包后被重置,因?yàn)榈诙挝帐值陌枰坏谌挝帐值?ACK 確認(rèn)后,才會重置重傳定時器
        我也把 TCP 三次握手模擬異常情況的實(shí)驗(yàn)過程整理了下,大家有興趣可以模仿我這篇文章的實(shí)驗(yàn)步驟來做實(shí)驗(yàn)。
        5000字的車,坐穩(wěn)了!

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

        TCP 三次握手的過程相信大家都背的滾瓜爛熟,那么你有沒有想過這三個異常情況:
        • TCP 第一次握手的 SYN 丟包了,會發(fā)生了什么?

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

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

        有的小伙伴可能說:“很簡單呀,包丟了就會重傳嘛?!?/section>
        那我在繼續(xù)問你:
        • 那會重傳幾次?

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

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

        • ….

        是不是啞口無言,無法回答?
        不知道沒關(guān)系,接下里我用三個實(shí)驗(yàn)案例,帶大家一起探究探究這三種異常。

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

        本次實(shí)驗(yàn)用了兩臺虛擬機(jī),一臺作為服務(wù)端,一臺作為客戶端,它們的關(guān)系如下:
        實(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 命令:
        其間 tcpdump 抓包的命令如下:
        過了一會, curl 返回了超時連接的錯誤:
        date 返回的時間,可以發(fā)現(xiàn)在超時接近 1 分鐘的時間后,curl 返回了錯誤。
        接著,把 tcp_sys_timeout.pcap 文件用 Wireshark 打開分析,顯示如下圖:
        SYN 超時重傳五次
        從上圖可以發(fā)現(xiàn), 客戶端發(fā)起了 SYN 包后,一直沒有收到服務(wù)端的 ACK ,所以一直超時重傳了 5 次,并且每次 RTO 超時時間是不同的:
        • 第一次是在 1 秒超時重傳

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

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

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

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

        可以發(fā)現(xiàn),每次超時時間 RTO 是指數(shù)(翻倍)上漲的,當(dāng)超過最大重傳次數(shù)后,客戶端不再發(fā)送 SYN 包。
        在 Linux 中,第一次握手的 SYN 超時重傳次數(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 打開分析,顯示如下圖:
        SYN 超時重傳兩次
        實(shí)驗(yàn)一的實(shí)驗(yàn)小結(jié)
        通過實(shí)驗(yàn)一的實(shí)驗(yàn)結(jié)果,我們可以得知,當(dāng)客戶端發(fā)起的 TCP 第一次握手 SYN 包,在超時時間內(nèi)沒收到服務(wù)端的 ACK,就會在超時重傳 SYN 數(shù)據(jù)包,每次超時重傳的 RTO 是翻倍上漲的,直到 SYN 包的重傳次數(shù)到達(dá) tcp_syn_retries 值后,客戶端不再發(fā)送 SYN 包。
        SYN 超時重傳

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

        為了模擬客戶端收不到服務(wù)端第二次握手 SYN、ACK 包,我的做法是在客戶端加上防火墻限制,直接粗暴的把來自服務(wù)端的數(shù)據(jù)都丟棄,防火墻的配置如下:
        接著,在客戶端執(zhí)行 curl 命令:
        date 返回的時間前后,可以算出大概 1 分鐘后,curl 報錯退出了。
        客戶端在這其間抓取的數(shù)據(jù)包,用 Wireshark 打開分析,顯示的時序圖如下:
        從圖中可以發(fā)現(xiàn):
        • 客戶端發(fā)起 SYN 后,由于防火墻屏蔽了服務(wù)端的所有數(shù)據(jù)包,所以 curl 是無法收到服務(wù)端的 SYN、ACK 包,當(dāng)發(fā)生超時后,就會重傳 SYN 包

        • 服務(wù)端收到客戶的 SYN 包后,就會回 SYN、ACK 包,但是客戶端一直沒有回 ACK,服務(wù)端在超時后,重傳了 SYN、ACK 包,接著一會,客戶端超時重傳的 SYN 包又抵達(dá)了服務(wù)端,服務(wù)端收到后,然后回了 SYN、ACK 包,但是SYN、ACK包的重傳定時器并沒有重置,還持續(xù)在重傳,因?yàn)榈诙挝帐衷跊]收到第三次握手的 ACK 確認(rèn)報文時,就會重傳到最大次數(shù)。

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

        所以,我們可以發(fā)現(xiàn),當(dāng)?shù)诙挝帐值?SYN、ACK 丟包時,客戶端會超時重發(fā) SYN 包,服務(wù)端也會超時重傳 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ù)是 1 次,目的是為了防止多次重傳 SYN,把服務(wù)端 SYN、ACK 超時定時器重置。
        接著,還是如上面的步驟:
        1. 客戶端配置防火墻屏蔽服務(wù)端的數(shù)據(jù)包

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

        把抓取的數(shù)據(jù)包,用 Wireshark 打開分析,顯示的時序圖如下:
        從上圖,我們可以分析出:
        • 客戶端的 SYN 只超時重傳了 1 次,因?yàn)?tcp_syn_retries 值為 1

        • 服務(wù)端應(yīng)答了客戶端超時重傳的 SYN 包后,由于一直收不到客戶端的 ACK 包,所以服務(wù)端一直在超時重傳 SYN、ACK 包,每次的 RTO 也是指數(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 打開分析,顯示的時序圖如下:
        可見:
        • 客戶端的 SYN 包只超時重傳了 1 次,符合 tcp_syn_retries 設(shè)置的值;

        • 服務(wù)端的 SYN、ACK 超時重傳了 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 包會發(fā)生超時重傳,服務(wù)端 SYN、ACK 也會發(fā)生超時重傳。
        客戶端 SYN 包超時重傳的最大次數(shù),是由 tcp_syn_retries 決定的,默認(rèn)值是 5 次;服務(wù)端 SYN、ACK 包時重傳的最大次數(shù),是由 tcp_synack_retries 決定的,默認(rèn)值是 5 次。

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

        為了模擬 TCP 第三次握手 ACK 包丟,我的實(shí)驗(yàn)方法是在服務(wù)端配置防火墻,屏蔽客戶端 TCP 報文中標(biāo)志位是 ACK 的包,也就是當(dāng)服務(wù)端收到客戶端的 TCP ACK 的報文時就會丟棄,iptables 配置命令如下:
        接著,在客戶端執(zhí)行如下 tcpdump 命令:
        然后,客戶端向服務(wù)端發(fā)起 telnet,因?yàn)?telnet 命令是會發(fā)起 TCP 連接,所以用此命令做測試:
        此時,由于服務(wù)端收不到第三次握手的 ACK 包,所以一直處于 SYN_RECV 狀態(tài):
        而客戶端是已完成 TCP 連接建立,處于 ESTABLISHED 狀態(tài):
        過了 1 分鐘后,觀察發(fā)現(xiàn)服務(wù)端的 TCP 連接不見了:
        過了 30 分別,客戶端依然還是處于 ESTABLISHED 狀態(tài):
        接著,在剛才客戶端建立的 telnet 會話,輸入 123456 字符,進(jìn)行發(fā)送:
        持續(xù)「好長」一段時間,客戶端的 telnet 才斷開連接:
        以上就是本次的實(shí)現(xiàn)三的現(xiàn)象,這里存在兩個疑點(diǎn):
        • 為什么服務(wù)端原本處于 SYN_RECV 狀態(tài)的連接,過 1 分鐘后就消失了?

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

        不著急,我們把剛抓的數(shù)據(jù)包,用 Wireshark 打開分析,顯示的時序圖如下:
        上圖的流程:
        • 客戶端發(fā)送 SYN 包給服務(wù)端,服務(wù)端收到后,回了個 SYN、ACK 包給客戶端,此時服務(wù)端的 TCP 連接處于 SYN_RECV 狀態(tài);

        • 客戶端收到服務(wù)端的 ?SYN、ACK 包后,給服務(wù)端回了個 ACK 包,此時客戶端的 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ù)端超時重傳了 SYN、ACK 包,重傳了 5 次后,也就是超過 tcp_synack_retries 的值(默認(rèn)值是 5),然后就沒有繼續(xù)重傳了,此時服務(wù)端的 TCP 連接主動中止了,所以剛才處于 SYN_RECV 狀態(tài)的 TCP 連接斷開了,而客戶端依然處于ESTABLISHED 狀態(tài);

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

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

        通過這一波分析,剛才的兩個疑點(diǎn)已經(jīng)解除了:
        • 服務(wù)端在重傳 SYN、ACK 包時,超過了最大重傳次數(shù) tcp_synack_retries,于是服務(wù)端的 TCP 連接主動斷開了。

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

        TCP 第一次握手的 SYN 包超時重傳最大次數(shù)是由 tcp_syn_retries 指定,TCP 第二次握手的 SYN、ACK 包超時重傳最大次數(shù)是由 tcp_synack_retries 指定,那 TCP 建立連接后的數(shù)據(jù)包最大超時重傳次數(shù)是由什么參數(shù)指定呢?
        TCP 建立連接后的數(shù)據(jù)包傳輸,最大超時重傳次數(shù)是由 tcp_retries2 指定,默認(rèn)值是 15 次,如下:
        $?cat?/proc/sys/net/ipv4/tcp_retries2
        15
        如果 15 次重傳都做完了,TCP 就會告訴應(yīng)用層說:“搞不定了,包怎么都傳不過去!”
        那如果客戶端不發(fā)送數(shù)據(jù),什么時候才會斷開處于 ESTABLISHED 狀態(tài)的連接?
        這里就需要提到 TCP 的 保活機(jī)制。這個機(jī)制的原理是這樣的:
        定義一個時間段,在這個時間段內(nèi),如果沒有任何連接相關(guān)的活動,TCP ?;顧C(jī)制會開始作用,每隔一個時間間隔,發(fā)送一個「探測報文」,該探測報文包含的數(shù)據(jù)非常少,如果連續(xù)幾個探測報文都沒有得到響應(yīng),則認(rèn)為當(dāng)前的 TCP 連接已經(jīng)死亡,系統(tǒng)內(nèi)核將錯誤信息通知給上層應(yīng)用程序。
        在 Linux 內(nèi)核可以有對應(yīng)的參數(shù)可以設(shè)置?;顣r間、?;钐綔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:表示?;顣r間是 7200 秒(2小時),也就 2 小時內(nèi)如果沒有任何連接相關(guān)的活動,則會啟動保活機(jī)制

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

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

        也就是說在 Linux 系統(tǒng)中,最少需要經(jīng)過 2 小時 11 分 15 秒才可以發(fā)現(xiàn)一個「死亡」連接。
        這個時間是有點(diǎn)長的,所以如果我抓包足夠久,或許能抓到探測報文。
        實(shí)驗(yàn)三的實(shí)驗(yàn)小結(jié)
        在建立 TCP 連接時,如果第三次握手的 ACK,服務(wù)端無法收到,則服務(wù)端就會短暫處于 SYN_RECV 狀態(tài),而客戶端會處于 ESTABLISHED 狀態(tài)。
        由于服務(wù)端一直收不到 TCP 第三次握手的 ACK,則會一直重傳 SYN、ACK 包,直到重傳次數(shù)超過 tcp_synack_retries 值(默認(rèn)值 5 次)后,服務(wù)端就會斷開 TCP 連接。
        而客戶端則會有兩種情況:
        • 如果客戶端沒發(fā)送數(shù)據(jù)包,一直處于 ESTABLISHED 狀態(tài),然后經(jīng)過 2 小時 11 分 15 秒才可以發(fā)現(xiàn)一個「死亡」連接,于是客戶端連接就會斷開連接。

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


        好了,這次就分享到這了。
        小林周末會寫一篇協(xié)程,大家敬請期待哈。
        ?

        ?

        瀏覽 42
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            鲁一鲁A片久久久久 | 插下面网站 | 宅男噜噜噜66国产精品免费 | 直接看的毛片 | 想操逼 | 日韩无码视频专区 | 欧美老妇另类XXXX | 性孕妇free特大另类 | AⅤ在线视频观看 | 色戒未删减版在线观看完整 |