TCP 連接的保持并不需要任何額外的操作,但在實際應用中,要長時間保持一個 TCP 連接則會受到諸多因素的影響。本文介紹了幾種常見的導致 TCP 連接斷連的原因,并在此基礎上,以 AIX 系統上 TCP 連接的異常斷連為例,借助相應的網絡分析工具,逐步揭開 AIX 上 TCP 斷連的原因,并給出兩種可行的解決方案。<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
在官方的正式文檔中,TCP/IP 協議簇也稱為國際互聯網協議簇。TCP/IP 協議簇是目前使用最為廣泛的全球互聯網技術,其分層結構如圖 1 所示:
圖 1. TCP/IP 協議簇分層結構

如圖 1 所示,數據鏈路層主要負責處理傳輸媒介等眾多的物理接口細節;網絡層負責處理數據分組在網絡中的活動,包括上層數據報文的分割、選路 phost2008-08-21T00:00:00 等;傳輸層則負責為兩臺主機提供端到端的通信;應用層將負責處理應用程序的特定細節。其中,IP 協議是網絡層的核心協議,用來提供不可靠、無連接的數據傳遞服務;而 TCP 協議則處于傳輸層,其基于不可靠無連接的 IP 協議能夠為兩臺主機提供面向連接的、可靠的通信。UDP?
由于 TCP 是面向連接的協議,因此在兩臺主機通信之前,需要首先建立起一條連接。下面我們將簡要介紹 TCP 連接的建立以及通信雙方是如何保持已建立的 TCP 連接的。
一個 TCP 連接的建立需要通過著名的“三次握手”來完成。下面的例子將直觀給出一個 TCP 連接的建立過程。
在本文的下述描述中,客戶端主機均為 testClient.cn.ibm.com(Linux),服務器主機均為 testServer.cn.ibm.com(AIX)。在 testClient 主機的一終端上執行 tcpdump –i eth0 host testServer 命令,啟動 tcpdump 監聽網絡數據(其中,eth0 是客戶主機與外部網絡進行通信所使用的網卡);與此同時,在客戶主機的另一個終端上執行下述命令: (root@testClient /)>telnet testServer。此時客戶主機上 tcpdump 的輸出如清單 1 所示。
清單 1. 創建一個 TCP 連接的三次握手
# tcpdump –S -i en0 host testServer |
注意:我們刪除了 tcpdump 輸出結果中的部分無關信息。為了便于理解,我們將上述輸出轉換為實際序列圖 2。
圖 2. TCP 建立創建三次握手的實際序列

從圖 2 中我們可以清楚地看到,在 testClient 與 testServer 之間建立連接時,要經過以下三次握手過程:
- testClient 向 testServer 主動發送握手協議,報文序列號為 3392458353,大小為 1 個字節。
- testServer 向 testClient 主動發送握手協議,報文序列號為 881279296,大小為 1 個字節;同時返回 ACK 3392458354,作為對 testClient 發來的 3392458354 包的應答。
- testClient 向 testServer 返回 ACK 881279297,作為對 testServer 發來的 881279296 包的應答。
一個 TCP 連接在完成上述的三次握手之后便建立完畢;此后,連接的兩端即可進行信息的相互傳遞。因此,TCP 連接可以認為是以兩端 IP 地址和端口進行標識的一個通信信道,而 TCP 連接的建立就是向通信雙方進行上述通信信道注冊的過程。TCP 連接一旦建立,只要通信雙方之間的中間結點(包括網關和交換機、路由器等網絡設備)工作正常,那么在通信雙方中的任何一方主動關閉連接之前,TCP 連接都將被一直保持下去。
TCP 連接的這種特性,使得一個長期不交換任何信息的空閑連接可以長期保持數小時、數天甚至數月。中間路由器可以崩潰、重啟,網線可以被掛斷再連通,只要兩端的主機沒有被重啟,TCP 連接就可以被一直保持下來。
![]() ![]() |
![]()
|
理想狀態下,一個 TCP 連接可以被長期保持。然而,在實際應用中,客戶端或服務器端上維持的一個看似正常的 TCP 連接可能已經斷連。TCP 連接主要受到兩個方面的影響而導致斷連:網絡中間節點和客戶端 / 服務器節點參與通信的兩方節點?
在實際網絡應用中,兩個主機之間的通信往往需要穿越多個中間節點,例如路由器、網關、防火墻等。因此,兩個主機之間 TCP 連接的保持同樣會受到中間節點的影響,尤其是會受到防火墻(軟件或硬件防火墻)的限制。防火墻是一種裝置,有多種不同的實現方式(軟件實現、硬件設備實現或是軟硬件相結合實現),它需要依據一系列規則對進出的信息流進行掃描,并允許安全(符合規則)的信息交互、阻止不安全(違反規則)的信息交互。防火墻的工作特性決定了要維護一個網絡連接就需要耗費較多的資源,并且企業防火墻常常位于企業網絡的出入口,長時間維護非活躍的 TCP 連接必將導致網絡性能的下降。因此,大部分防火墻默認會關閉長時間處于非活躍狀態的連接而導致 TCP 連接斷連。類似的,如果中間節點異常導致來自客戶端關閉連接的請求無法傳遞到服務器端,也將導致服務器端的相應連接發生斷連。
另一方面,對于一個 TCP 連接兩端的主機而言,創建 TCP 連接需要耗費一定的系統資源。如果不再使用某個連接,那么我們總是希望進行通信的兩個主機能夠主動關閉相應的連接,以便釋放所占用的系統資源。然而,如果由于客戶端出現異常 ( 例如崩潰或異常重啟 ) 而導致連接未能正常關閉,這將導致服務器端的連接斷連。
無論是客戶端節點或是服務器端節點,斷連的 TCP 連接已經不能傳遞任何信息,因此,維護大量斷連的 TCP 連接將導致系統資源的浪費。這種系統資源的浪費可能并不會對客戶端節點帶來太大問題;然而,對于服務器主機而言,這可能會導致系統資源(尤指內存資源和 socket 資源)被耗盡而拒絕為新的用戶請求提供服務。因此在實際應用中,服務器端需要采取相應的方法來探測 TCP 連接是否已經斷連。
![]() ![]() |
![]()
|
探測 TCP 連接是否斷連或是工作正常的原理比較簡單:定期向連接的遠程通信節點發送一定格式的信息并等待遠程通信節點的反饋,如果在規定時間內收到來自遠程節點的正確的反饋信息,那么該連接就是正常的,否則該連接已經斷連。依據該原理,目前常用的探測方法有以下三種。
應用程序本身附帶探測其自身建立的 TCP 連接的功能。這種方法具有極大的靈活性,可以依據應用本身的特點選擇相應的探測機制和功能實現。然而,實際應用中,大部分應用程序均沒有附帶自我探測的功能。
此種方法就是在服務節點上安裝相應的第三方應用程序來探測該節點上所有的 TCP 連接是否正常或是已經斷連。該方法最大的不足就是需要所有支持探測的客戶端能夠識別來自該探測應用的數據報文,因此,實際應用中比較少見。
最常用的探測方法就是采用 TCP 協議層提供的保活探測功能即 TCP 連接保活定時器。盡管該功能并不是 RFC 規范的一部分,但是幾乎所有的類 Unix 系統均實現了該功能,所以使得該探測方法被廣泛使用。
接下來的部分,我們將重點討論來自 TCP 協議層的保活探測方法。
![]() ![]() |
![]()
|
TCP 連接的保活定時器可以在應用層實現,也可以在 TCP 中提供。這個問題存在爭議,因此 TCP 連接的保活探測并不是 TCP 規范中的一部分。但為了方便,幾乎所有類 Unix 系統均在 TCP 中提供了相應的功能。
清單 2. 常見 Unix 系統上的保活定時器
操作系統 保活定時器
AIX |
# no -a | grep keep
tcp_keepcnt = 8 tcp_keepidle = 14400 tcp_keepintvl = 150 |
Linux |
# sysctl -A | grep keep
net.ipv4.tcp_keepalive_intvl = 75 net.ipv4.tcp_keepalive_probes = 9 net.ipv4.tcp_keepalive_time = 7200 |
FreeBSD |
#sysctl -A | grep net.inet.tcp
net.inet.tcp.keepidle=… net.inet.tcp.keepintvl=… |
不同系統上的各參數的時間單位不盡相同。在 AIX 上,tcp_keeidle/tcp_keepinit/tcp_keepintvl 的時間單位是 0.5 秒;而在 Linux 上,net.ipv4.tcp_keepalive_intvl 和 net.ipv4.tcp_keepalive_time 的時間單位則為秒。并且,上述參數僅對運行在其上的服務器應用連接有效。
注:在 Solaris 上可通過“ndd /dev/tcp /?”命令顯示上述類似參數信息,而在 HP Unix 上則可通過 nettune 或 ndd 命令進行查詢。
由于所有類 Unix 系統上均支持這種功能,因此,在接下來的部分中我們將基于 AIX 系統具體講述上述參數的意義和作用機制。
![]() ![]() |
![]()
|
正如清單 2 中列出的一樣,AIX 上的保活探測機制由 4 個參數來控制,其具體意義見清單 3:
清單 3. AIX 上的保活定時器控制參數
控制參數 參數說明
tcp_keepcnt | 關閉一個非活躍連接之前進行探測的最大次數,默認為 8 次 |
tcp_keepidle | 對一個連接進行有效性探測之前運行的最大非活躍時間間隔,默認值為 14400(即 2 個小時) |
tcp_keepintvl | 兩個探測的時間間隔,默認值為 150 即 75 秒 |
我們來看一個具體的例子。在 testServer 端(AIX 主機)采用 tcp_keepidel=240(即 2 分鐘):tcp_keepcnt=8:tcp_keepintvl=150(即 75 秒)的參數值;啟動 testServer 上的 tcpdump 查看網絡包的交互情況;從 testClient 端發起請求建立和 testServer 之間的一個 telnet 連接。在連接建立完成之后,拔出 testClient 端的網線并觀察服務器端的數據輸出(見清單 4)。
清單 4. telnet 連接在服務器端的 tcpdump 輸出
1 # tcpdump -i en1 host testServer.cn.ibm.com |
從清單 4 中可以看出,第 6 行的報文是本連接發送的最后數據,而第 7 行則是對第 6 行數據的確認。其后,該連接上沒有任何數據交互,從而使得該連接一直處于非活躍狀態。經過 2 分鐘(第 8 行數據報時間 04:53:54 和第 7 行數據報時間 04:51:54 之差,即 tcp_keepidle 的值)的非活躍時間后,第 8 行是服務器端發起第一個保活探測數據報。由于服務器端沒有收到客戶端關于探測報文的相應,因此再經過 tcp_keepintvl 的時間間隔(75 秒)之后,第 9 行顯示服務器端再次發起保活探測數據報。服務器端持續發送了 tcp_keepcnt 個探測報文(上面結果顯示,在 AIX 上是持續發送 tcp_keepcnt+1 個探測報文)之后,仍然沒有收到來自客戶端的任何回應,所以服務器在第 17 行向客戶端發送復位報文同時在服務器端關閉了該連接。
需要注意的是,保活探測雖然通過發送 TCP 探測報文,但探測報文不會對正常的 TCP 連接產生任何影響。從清單 4 可以看出,第 8 行發送數據的 TCP 報文序號為 695 起始的 1Byte 數據,而該數據在第 6 行已經發送并被客戶端確認。對于正常狀態的連接,客戶端在收到探測報文之后將返回一個第 7 行所示的 ACK 報文并借此向服務器端表明連接工作正常。
接下來,我們將通過一個實際的 TCP 斷連的例子來分析上述機制對 TCP 連接保持的影響,并針對需要長時間保持 TCP 連接的應用提出兩種可選的解決方案。
![]() ![]() |
![]()
|
圖 3. 出現 TCP 斷連的網絡拓撲結構示意圖

所有服務器主機均劃為一個局域網,并處于防火墻 B 之后。由于工作需要,來自工作區局域網的主機 testClient 需和服務器局域網內的 testServer 上的數據庫使用 TCP/IP 建立一個連接,testClient 上的上層應用將通過該連接對 testServer 上的數據庫進行相應操作。
在實際測試中,我們發現,在 testClient 和 testServer 均工作正常的情況下,testClient 上的客戶端在事先沒有收到任何異常信息的情況下,所持有的連接會出現非預期的斷連現象(在試圖通過連接進行數據庫操作時,會被告知 connection is reset by foreign host 的錯誤)。
由于該現象不斷出現,并且網絡內的中間節點(路由器和交換機等)均工作正常,因此可以排除物理因素(如掉電、宕機等)的可能。為了便于分析斷連原因,我們首先查看了 testServer 機器上的默認保活設置:
# no -a | grep keep |
testServer 上的 tcp_keepidle 為 14400,即 2 個小時。既然中間節點工作正常,為什么保活機制沒有其作用呢?為了進行分析,我們采用 tcpdump 工具捕獲 testClient 和 testServer 上的報文信息,見清單 5 和清單 6 所示。
清單 5. 服務器端的 tcpdump 數據輸出
1 10:18:58.881950 IP testClient.cn.ibm.com.59098 > |
清單 6. 客戶端的 tcpdump 數據輸出
1 # tcpdump -e -i eth0 host testServer.cn.ibm.com |
從清單 5 中可以看出,在該連接處于非活躍狀態的時間達到 tcp_keepidle 設定的 2 小時時,服務器主機發出了第一個連接保活的探測報文(清單 5 中的第 7 行)。緊接著,服務器主機就收到了來自 testClient 的連接復位報文(清單 5 中的第 8 行)。之后,服務器便關閉了該連接(可以通過 netstat –ni 來查看)。然而,從清單 6 的 tcpdump 數據可以看出, testClient 端并未發送任何報文。那么,是誰向 testServer 發送了復位報文呢?
為了查看上述復位報文的發送者,同樣采用上述 tcpdump 命令再次捕獲服務器端和防火墻 B 的報文信息(注意:通常需要捕獲防火墻主機上網絡數據的出口網卡和入口網卡數據),結果顯示,防火墻 B 在收到來自 testServer 的第一個探測報文之后就立刻向 testServer 發送了一個復位報文。
上述分析說明,在連接傳遞完最后一個交互數據之后到服務器端發送第一個保活探測之間,該連接已經被防火墻 B 終止;在此之后,基于該連接的任何報文傳遞在試圖穿過防火墻的時候均會被防火墻丟棄并發送復位報文。
![]() ![]() |
![]()
|
針對上述 TCP 斷連現象,有兩種常用的解決方案可供選擇:
方案 1、延長防火墻終止非活躍的 TCP 連接的時間。例如,針對上述案例,可以調節防火墻設置,將時間設置為大于服務器端設定的 2 小時。
方案 2、縮短服務器端的 TCP 連接保活時間。縮短該時間的目的是為了在連接被防火墻終止之前發送保活探測報文,既可以探測客戶端狀態,又可以使連接變為活躍狀態。
對于第一種方案而言,延長 TCP 連接的保持時間可能會導致防火墻性能的降低,尤其是在維持大量長時間處于非活躍狀態的連接的情況下更是如此;而對于第二種方案,如果縮短服務器端的 TCP 連接保活時間,意味著會增加網絡中的數據報文數而占用額外的網絡帶寬。因此,兩種方案各有利弊,需要依據不同的實際應用情況進行選擇。
![]() ![]() |
![]()
|
本文介紹了 TCP 連接的建立和保持的相關概念以及影響 TCP 連接保持的常見因素。給出了常見的類 Unix 系統上 TCP 連接保活探測的相關配置參數,并基于 AIX 借助 tcpdump 工具分析了一個實際的 TCP 斷連的案例。最后,針對 TCP 斷連的情況給出了兩種可行的解決方案。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
