TCP常用命令
了解TCP之前,先了解幾個(gè)命令:
linux查看tcp的狀態(tài)命令:
1)、netstat -nat 查看TCP各個(gè)狀態(tài)的數(shù)量
2)、lsof -i:port 可以檢測(cè)到打開(kāi)套接字的狀況
3)、 sar -n SOCK 查看tcp創(chuàng)建的連接數(shù)
4)、tcpdump -iany tcp port 9000 對(duì)tcp端口為9000的進(jìn)行抓包
網(wǎng)絡(luò)測(cè)試常用命令;
1)ping:檢測(cè)網(wǎng)絡(luò)連接的正常與否,主要是測(cè)試延時(shí)、抖動(dòng)、丟包率。
但是很多服務(wù)器為了防止攻擊,一般會(huì)關(guān)閉對(duì)ping的響應(yīng)。所以ping一般作為測(cè)試連通性使用。ping命令后,會(huì)接收到對(duì)方發(fā)送的回饋信息,其中記錄著對(duì)方的IP地址和TTL。TTL是該字段指定IP包被路由器丟棄之前允許通過(guò)的最大網(wǎng)段數(shù)量。TTL是IPv4包頭的一個(gè)8 bit字段。例如IP包在服務(wù)器中發(fā)送前設(shè)置的TTL是64,你使用ping命令后,得到服務(wù)器反饋的信息,其中的TTL為56,說(shuō)明途中一共經(jīng)過(guò)了8道路由器的轉(zhuǎn)發(fā),每經(jīng)過(guò)一個(gè)路由,TTL減1。
2)traceroute:raceroute 跟蹤數(shù)據(jù)包到達(dá)網(wǎng)絡(luò)主機(jī)所經(jīng)過(guò)的路由工具
traceroute hostname
3)pathping:是一個(gè)路由跟蹤工具,它將 ping 和 tracert 命令的功能與這兩個(gè)工具所不提供的其他信息結(jié)合起來(lái),綜合了二者的功能
pathping www.baidu.com
4)mtr:以結(jié)合ping nslookup tracert 來(lái)判斷網(wǎng)絡(luò)的相關(guān)特性
5) nslookup:用于解析域名,一般用來(lái)檢測(cè)本機(jī)的DNS設(shè)置是否配置正確。
? ? ?TCP狀態(tài)分析
LISTENING:偵聽(tīng)來(lái)自遠(yuǎn)方的TCP端口的連接請(qǐng)求。
首先服務(wù)端需要打開(kāi)一個(gè)socket進(jìn)行監(jiān)聽(tīng),狀態(tài)為L(zhǎng)ISTEN。
有提供某種服務(wù)才會(huì)處于LISTENING狀態(tài),TCP狀態(tài)變化就是某個(gè)端口的狀態(tài)變化,提供一個(gè)服務(wù)就打開(kāi)一個(gè)端口,例如:提供www服務(wù)默認(rèn)開(kāi)的是80端口,提供ftp服務(wù)默認(rèn)的端口為21,當(dāng)提供的服務(wù)沒(méi)有被連接時(shí)就處于LISTENING狀態(tài)。FTP服務(wù)啟動(dòng)后首先處于偵聽(tīng)(LISTENING)狀態(tài)。處于偵聽(tīng)LISTENING狀態(tài)時(shí),該端口是開(kāi)放的,等待連接,但還沒(méi)有被連接。就像你房子的門(mén)已經(jīng)敞開(kāi)的,但還沒(méi)有人進(jìn)來(lái)。
看LISTENING狀態(tài)最主要的是看本機(jī)開(kāi)了哪些端口,這些端口都是哪個(gè)程序開(kāi)的,關(guān)閉不必要的端口是保證安全的一個(gè)非常重要的方面,服務(wù)端口都對(duì)應(yīng)一個(gè)服務(wù)(應(yīng)用程序),停止該服務(wù)就關(guān)閉了該端口,例如要關(guān)閉21端口只要停止IIS服務(wù)中的FTP服務(wù)即可。關(guān)于這方面的知識(shí)請(qǐng)參閱其它文章。
如果你不幸中了服務(wù)端口的木馬,木馬也開(kāi)個(gè)端口處于LISTENING狀態(tài)。
SYN-SENT:客戶(hù)端SYN_SENT狀態(tài):
再發(fā)送連接請(qǐng)求后等待匹配的連接請(qǐng)求:客戶(hù)端通過(guò)應(yīng)用程序調(diào)用connect進(jìn)行active open.于是客戶(hù)端tcp發(fā)送一個(gè)SYN以請(qǐng)求建立一個(gè)連接。之后狀態(tài)置為SYN_SENT. /*The socket is actively attempting to establish a connection. 在發(fā)送連接請(qǐng)求后等待匹配的連接請(qǐng)求 */
當(dāng)請(qǐng)求連接時(shí)客戶(hù)端首先要發(fā)送同步信號(hào)給要訪問(wèn)的機(jī)器,此時(shí)狀態(tài)為SYN_SENT,如果連接成功了就變?yōu)镋STABLISHED,正常情況下SYN_SENT狀態(tài)非常短暫。例如要訪問(wèn)網(wǎng)站http://www.baidu.com,如果是正常連接的話,用TCPView觀察IEXPLORE.EXE(IE)建立的連接會(huì)發(fā)現(xiàn)很快從SYN_SENT變?yōu)镋STABLISHED,表示連接成功。SYN_SENT狀態(tài)快的也許看不到。
如果發(fā)現(xiàn)有很多SYN_SENT出現(xiàn),那一般有這么幾種情況,一是你要訪問(wèn)的網(wǎng)站不存在或線路不好,二是用掃描軟件掃描一個(gè)網(wǎng)段的機(jī)器,也會(huì)出出現(xiàn)很多SYN_SENT,另外就是可能中了病毒了,例如中了“沖擊波”,病毒發(fā)作時(shí)會(huì)掃描其它機(jī)器,這樣會(huì)有很多SYN_SENT出現(xiàn)。
SYN-RECEIVED:服務(wù)器端狀態(tài)SYN_RCVD
再收到和發(fā)送一個(gè)連接請(qǐng)求后等待對(duì)方對(duì)連接請(qǐng)求的確認(rèn)
當(dāng)服務(wù)器收到客戶(hù)端發(fā)送的同步信號(hào)時(shí),將標(biāo)志位ACK和SYN置1發(fā)送給客戶(hù)端,此時(shí)服務(wù)器端處于SYN_RCVD狀態(tài),如果連接成功了就變?yōu)镋STABLISHED,正常情況下SYN_RCVD狀態(tài)非常短暫。
如果發(fā)現(xiàn)有很多SYN_RCVD狀態(tài),那你的機(jī)器有可能被SYN Flood的DoS(拒絕服務(wù)攻擊)攻擊了。
SYN Flood的攻擊原理是:
在進(jìn)行三次握手時(shí),攻擊軟件向被攻擊的服務(wù)器發(fā)送SYN連接請(qǐng)求(握手的第一步),但是這個(gè)地址是偽造的,如攻擊軟件隨機(jī)偽造了51.133.163.104、65.158.99.152等等地址。服務(wù)器在收到連接請(qǐng)求時(shí)將標(biāo)志位ACK和SYN置1發(fā)送給客戶(hù)端(握手的第二步),但是這些客戶(hù)端的IP地址都是偽造的,服務(wù)器根本找不到客戶(hù)機(jī),也就是說(shuō)握手的第三步不可能完成。
這種情況下服務(wù)器端一般會(huì)重試(再次發(fā)送SYN+ACK給客戶(hù)端)并等待一段時(shí)間后丟棄這個(gè)未完成的連接,這段時(shí)間的長(zhǎng)度我們稱(chēng)為SYN Timeout,一般來(lái)說(shuō)這個(gè)時(shí)間是分鐘的數(shù)量級(jí)(大約為30秒-2分鐘);一個(gè)用戶(hù)出現(xiàn)異常導(dǎo)致服務(wù)器的一個(gè)線程等待1分鐘并不是什么很大的問(wèn)題,但如果有一個(gè)惡意的攻擊者大量模擬這種情況,服務(wù)器端將為了維護(hù)一個(gè)非常大的半連接列表而消耗非常多的資源----數(shù)以萬(wàn)計(jì)的半連接,即使是簡(jiǎn)單的保存并遍歷也會(huì)消耗非常多的CPU時(shí)間和內(nèi)存,何況還要不斷對(duì)這個(gè)列表中的IP進(jìn)行SYN+ACK的重試。此時(shí)從正常客戶(hù)的角度看來(lái),服務(wù)器失去響應(yīng),這種情況我們稱(chēng)做:服務(wù)器端受到了SYN Flood攻擊(SYN洪水攻擊)
ESTABLISHED:代表一個(gè)打開(kāi)的連接。
ESTABLISHED狀態(tài)是表示兩臺(tái)機(jī)器正在傳輸數(shù)據(jù),觀察這個(gè)狀態(tài)最主要的就是看哪個(gè)程序正在處于ESTABLISHED狀態(tài)。
服務(wù)器出現(xiàn)很多ESTABLISHED狀態(tài): netstat -nat |grep 9502或者使用lsof -i:9502可以檢測(cè)到。
當(dāng)客戶(hù)端未主動(dòng)close的時(shí)候就斷開(kāi)連接:即客戶(hù)端發(fā)送的FIN丟失或未發(fā)送。
這時(shí)候若客戶(hù)端斷開(kāi)的時(shí)候發(fā)送了FIN包,則服務(wù)端將會(huì)處于CLOSE_WAIT狀態(tài);
這時(shí)候若客戶(hù)端斷開(kāi)的時(shí)候未發(fā)送FIN包,則服務(wù)端處還是顯示ESTABLISHED狀態(tài);
結(jié)果客戶(hù)端重新連接服務(wù)器。
而新連接上來(lái)的客戶(hù)端(也就是剛才斷掉的重新連上來(lái)了)在服務(wù)端肯定是ESTABLISHED; 如果客戶(hù)端重復(fù)的上演這種情況,那么服務(wù)端將會(huì)出現(xiàn)大量的假的ESTABLISHED連接和CLOSE_WAIT連接。
最終結(jié)果就是新的其他客戶(hù)端無(wú)法連接上來(lái),但是利用netstat還是能看到一條連接已經(jīng)建立,并顯示ESTABLISHED,但始終無(wú)法進(jìn)入程序代碼。
FIN-WAIT-1:等待遠(yuǎn)程TCP連接中斷請(qǐng)求,或先前的連接中斷請(qǐng)求的確認(rèn)
主動(dòng)關(guān)閉(active close)端應(yīng)用程序調(diào)用close,于是其TCP發(fā)出FIN請(qǐng)求主動(dòng)關(guān)閉連接,之后進(jìn)入FIN_WAIT1狀態(tài)。/* The socket is closed, and the connection is shutting down. 等待遠(yuǎn)程TCP的連接中斷請(qǐng)求,或先前的連接中斷請(qǐng)求的確認(rèn) */
如果服務(wù)器出現(xiàn)shutdown再重啟,使用netstat -nat查看,就會(huì)看到很多FIN-WAIT-1的狀態(tài)。就是因?yàn)榉?wù)器當(dāng)前有很多客戶(hù)端連接,直接關(guān)閉服務(wù)器后,無(wú)法接收到客戶(hù)端的ACK。
FIN-WAIT-2:從遠(yuǎn)程TCP等待連接中斷請(qǐng)求
主動(dòng)關(guān)閉端接到ACK后,就進(jìn)入了FIN-WAIT-2 。/* Connection is closed, and the socket is waiting for a shutdown from the remote end. 從遠(yuǎn)程TCP等待連接中斷請(qǐng)求 */
這就是著名的半關(guān)閉的狀態(tài)了,這是在關(guān)閉連接時(shí),客戶(hù)端和服務(wù)器兩次握手之后的狀態(tài)。在這個(gè)狀態(tài)下,應(yīng)用程序還有接受數(shù)據(jù)的能力,但是已經(jīng)無(wú)法發(fā)送數(shù)據(jù),但是也有一種可能是,客戶(hù)端一直處于FIN_WAIT_2狀態(tài),而服務(wù)器則一直處于WAIT_CLOSE狀態(tài),而直到應(yīng)用層來(lái)決定關(guān)閉這個(gè)狀態(tài)。
CLOSE-WAIT:等待從本地用戶(hù)發(fā)來(lái)的連接中斷請(qǐng)求
被動(dòng)關(guān)閉(passive close)端TCP接到FIN后,就發(fā)出ACK以回應(yīng)FIN請(qǐng)求(它的接收也作為文件結(jié)束符傳遞給上層應(yīng)用程序),并進(jìn)入CLOSE_WAIT. /* The remote end has shut down, waiting for the socket to close. 等待從本地用戶(hù)發(fā)來(lái)的連接中斷請(qǐng)求 */
CLOSING:等待遠(yuǎn)程TCP對(duì)連接中斷的確認(rèn)
比較少見(jiàn)。/* Both sockets are shut down but we still don‘t have all our data sent. 等待遠(yuǎn)程TCP對(duì)連接中斷的確認(rèn) */
LAST-ACK:等待原來(lái)的發(fā)向遠(yuǎn)程TCP的連接中斷請(qǐng)求的確認(rèn)
被動(dòng)關(guān)閉端一段時(shí)間后,接收到文件結(jié)束符的應(yīng)用程序?qū)⒄{(diào)用CLOSE關(guān)閉連接。這導(dǎo)致它的TCP也發(fā)送一個(gè) FIN,等待對(duì)方的ACK.就進(jìn)入了LAST-ACK 。 /* The remote end has shut down, and the socket is closed. Waiting for acknowledgement. 等待原來(lái)發(fā)向遠(yuǎn)程TCP的連接中斷請(qǐng)求的確認(rèn) */
使用并發(fā)壓力測(cè)試的時(shí)候,突然斷開(kāi)壓力測(cè)試客戶(hù)端,服務(wù)器會(huì)看到很多LAST-ACK。
TIME-WAIT:等待足夠的時(shí)間以確保遠(yuǎn)程TCP接收到連接中斷請(qǐng)求的確認(rèn)
在主動(dòng)關(guān)閉端接收到FIN后,TCP就發(fā)送ACK包,并進(jìn)入TIME-WAIT狀態(tài)。/* The socket is waiting after close to handle packets still in the network.等待足夠的時(shí)間以確保遠(yuǎn)程TCP接收到連接中斷請(qǐng)求的確認(rèn) */
TIME_WAIT等待狀態(tài),這個(gè)狀態(tài)又叫做2MSL狀態(tài),說(shuō)的是在TIME_WAIT2發(fā)送了最后一個(gè)ACK數(shù)據(jù)報(bào)以后,要進(jìn)入TIME_WAIT狀態(tài),這個(gè)狀態(tài)是防止最后一次握手的數(shù)據(jù)報(bào)沒(méi)有傳送到對(duì)方那里而準(zhǔn)備的(注意這不是四次握手,這是第四次握手的保險(xiǎn)狀態(tài))。這個(gè)狀態(tài)在很大程度上保證了雙方都可以正常結(jié)束,但是,問(wèn)題也來(lái)了。
由于插口的2MSL狀態(tài)(插口是IP和端口對(duì)的意思,socket),使得應(yīng)用程序在2MSL時(shí)間內(nèi)是無(wú)法再次使用同一個(gè)插口的,對(duì)于客戶(hù)程序還好一些,但是對(duì)于服務(wù)程序,例如httpd,它總是要使用同一個(gè)端口來(lái)進(jìn)行服務(wù),而在2MSL時(shí)間內(nèi),啟動(dòng)httpd就會(huì)出現(xiàn)錯(cuò)誤(插口被使用)。為了避免這個(gè)錯(cuò)誤,服務(wù)器給出了一個(gè)平靜時(shí)間的概念,這是說(shuō)在2MSL時(shí)間內(nèi),雖然可以重新啟動(dòng)服務(wù)器,但是這個(gè)服務(wù)器還是要平靜的等待2MSL時(shí)間的過(guò)去才能進(jìn)行下一次連接。
CLOSED:沒(méi)有任何連接狀態(tài)
被動(dòng)關(guān)閉端在接受到ACK包后,就進(jìn)入了closed的狀態(tài)。連接結(jié)束。/* The socket is not being used. 沒(méi)有任何連接狀態(tài) */
TCP 連接斷鏈分析
在官方的正式文檔中,TCP/IP 協(xié)議簇也稱(chēng)為國(guó)際互聯(lián)網(wǎng)協(xié)議簇。TCP/IP 協(xié)議簇是目前使用最為廣泛的全球互聯(lián)網(wǎng)技術(shù),其分層結(jié)構(gòu)如圖 1 所示:
圖 1. TCP/IP 協(xié)議簇分層結(jié)構(gòu)
如圖 1 所示,數(shù)據(jù)鏈路層主要負(fù)責(zé)處理傳輸媒介等眾多的物理接口細(xì)節(jié);網(wǎng)絡(luò)層負(fù)責(zé)處理數(shù)據(jù)分組在網(wǎng)絡(luò)中的活動(dòng),包括上層數(shù)據(jù)報(bào)文的分割、選路 phost2008-08-21T00:00:00 等;傳輸層則負(fù)責(zé)為兩臺(tái)主機(jī)提供端到端的通信;應(yīng)用層將負(fù)責(zé)處理應(yīng)用程序的特定細(xì)節(jié)。其中,IP 協(xié)議是網(wǎng)絡(luò)層的核心協(xié)議,用來(lái)提供不可靠、無(wú)連接的數(shù)據(jù)傳遞服務(wù);而 TCP 協(xié)議則處于傳輸層,其基于不可靠無(wú)連接的 IP 協(xié)議能夠?yàn)閮膳_(tái)主機(jī)提供面向連接的、可靠的通信。UDP?
由于 TCP 是面向連接的協(xié)議,因此在兩臺(tái)主機(jī)通信之前,需要首先建立起一條連接。下面我們將簡(jiǎn)要介紹 TCP 連接的建立以及通信雙方是如何保持已建立的 TCP 連接的。
TCP 連接的建立及保持
一個(gè) TCP 連接的建立需要通過(guò)著名的“三次握手”來(lái)完成。下面的例子將直觀給出一個(gè) TCP 連接的建立過(guò)程。
在本文的下述描述中,客戶(hù)端主機(jī)均為 testClient.cn.ibm.com(Linux),服務(wù)器主機(jī)均為 testServer.cn.ibm.com(AIX)。在 testClient 主機(jī)的一終端上執(zhí)行 tcpdump –i eth0 host testServer 命令,啟動(dòng) tcpdump 監(jiān)聽(tīng)網(wǎng)絡(luò)數(shù)據(jù)(其中,eth0 是客戶(hù)主機(jī)與外部網(wǎng)絡(luò)進(jìn)行通信所使用的網(wǎng)卡);與此同時(shí),在客戶(hù)主機(jī)的另一個(gè)終端上執(zhí)行下述命令: (root@testClient /)》telnet testServer。此時(shí)客戶(hù)主機(jī)上 tcpdump 的輸出如清單 1 所示。
清單 1. 創(chuàng)建一個(gè) TCP 連接的三次握手
# tcpdump –S -i en0 host testServer
1 14:02:38.384918 IP testClient.cn.ibm.com.43370 》
testServer.cn.ibm.com.telnet: S 3392458353:3392458353(0) …
2 14:02:38.629578 IP testServer.cn.ibm.com.telnet 》
testClient.cn.ibm.com.43370: S 881279296:881279296(0) ack 3392458354 …
3 14:02:38.629592 IP testClient.cn.ibm.com.43370 》
testServer.cn.ibm.com.telnet: 。 ack 881279297 …
注意:我們刪除了 tcpdump 輸出結(jié)果中的部分無(wú)關(guān)信息。為了便于理解,我們將上述輸出轉(zhuǎn)換為實(shí)際序列圖 2。
圖 2. TCP 建立創(chuàng)建三次握手的實(shí)際序列
從圖 2 中我們可以清楚地看到,在 testClient 與 testServer 之間建立連接時(shí),要經(jīng)過(guò)以下三次握手過(guò)程:
testClient 向 testServer 主動(dòng)發(fā)送握手協(xié)議,報(bào)文序列號(hào)為 3392458353,大小為 1 個(gè)字節(jié)。
testServer 向 testClient 主動(dòng)發(fā)送握手協(xié)議,報(bào)文序列號(hào)為 881279296,大小為 1 個(gè)字節(jié);同時(shí)返回 ACK 3392458354,作為對(duì) testClient 發(fā)來(lái)的 3392458354 包的應(yīng)答。
testClient 向 testServer 返回 ACK 881279297,作為對(duì) testServer 發(fā)來(lái)的 881279296 包的應(yīng)答。
一個(gè) TCP 連接在完成上述的三次握手之后便建立完畢;此后,連接的兩端即可進(jìn)行信息的相互傳遞。因此,TCP 連接可以認(rèn)為是以?xún)啥?IP 地址和端口進(jìn)行標(biāo)識(shí)的一個(gè)通信信道,而 TCP 連接的建立就是向通信雙方進(jìn)行上述通信信道注冊(cè)的過(guò)程。TCP 連接一旦建立,只要通信雙方之間的中間結(jié)點(diǎn)(包括網(wǎng)關(guān)和交換機(jī)、路由器等網(wǎng)絡(luò)設(shè)備)工作正常,那么在通信雙方中的任何一方主動(dòng)關(guān)閉連接之前,TCP 連接都將被一直保持下去。
TCP 連接的這種特性,使得一個(gè)長(zhǎng)期不交換任何信息的空閑連接可以長(zhǎng)期保持?jǐn)?shù)小時(shí)、數(shù)天甚至數(shù)月。中間路由器可以崩潰、重啟,網(wǎng)線可以被掛斷再連通,只要兩端的主機(jī)沒(méi)有被重啟,TCP 連接就可以被一直保持下來(lái)。
導(dǎo)致 TCP 連接斷連的因素
理想狀態(tài)下,一個(gè) TCP 連接可以被長(zhǎng)期保持。然而,在實(shí)際應(yīng)用中,客戶(hù)端或服務(wù)器端上維持的一個(gè)看似正常的 TCP 連接可能已經(jīng)斷連。TCP 連接主要受到兩個(gè)方面的影響而導(dǎo)致斷連:網(wǎng)絡(luò)中間節(jié)點(diǎn)和客戶(hù)端 / 服務(wù)器節(jié)點(diǎn)參與通信的兩方節(jié)點(diǎn)?
在實(shí)際網(wǎng)絡(luò)應(yīng)用中,兩個(gè)主機(jī)之間的通信往往需要穿越多個(gè)中間節(jié)點(diǎn),例如路由器、網(wǎng)關(guān)、防火墻等。因此,兩個(gè)主機(jī)之間 TCP 連接的保持同樣會(huì)受到中間節(jié)點(diǎn)的影響,尤其是會(huì)受到防火墻(軟件或硬件防火墻)的限制。防火墻是一種裝置,有多種不同的實(shí)現(xiàn)方式(軟件實(shí)現(xiàn)、硬件設(shè)備實(shí)現(xiàn) 或是軟硬件相結(jié)合實(shí)現(xiàn)),它需要依據(jù)一系列規(guī)則對(duì)進(jìn)出的信息流進(jìn)行掃描,并允許安全(符合規(guī)則)的信息交互、阻止不安全(違反規(guī)則)的信息交互。防火墻的 工作特性決定了要維護(hù)一個(gè)網(wǎng)絡(luò)連接就需要耗費(fèi)較多的資源,并且企業(yè)防火墻常常位于企業(yè)網(wǎng)絡(luò)的出入口,長(zhǎng)時(shí)間維護(hù)非活躍的 TCP 連接必將導(dǎo)致網(wǎng)絡(luò)性能的下降。因此,大部分防火墻默認(rèn)會(huì)關(guān)閉長(zhǎng)時(shí)間處于非活躍狀態(tài)的連接而導(dǎo)致 TCP 連接斷連。類(lèi)似的,如果中間節(jié)點(diǎn)異常導(dǎo)致來(lái)自客戶(hù)端關(guān)閉連接的請(qǐng)求無(wú)法傳遞到服務(wù)器端,也將導(dǎo)致服務(wù)器端的相應(yīng)連接發(fā)生斷連。
另一方面,對(duì)于一個(gè) TCP 連接兩端的主機(jī)而言,創(chuàng)建 TCP 連接需要耗費(fèi)一定的系統(tǒng)資源。如果不再使用某個(gè)連接,那么我們總是希望進(jìn)行通信的兩個(gè)主機(jī)能夠主動(dòng)關(guān)閉相應(yīng)的連接,以便釋放所占用的系統(tǒng)資源。然而,如果 由于客戶(hù)端出現(xiàn)異常 ( 例如崩潰或異常重啟 ) 而導(dǎo)致連接未能正常關(guān)閉,這將導(dǎo)致服務(wù)器端的連接斷連。
無(wú)論是客戶(hù)端節(jié)點(diǎn)或是服務(wù)器端節(jié)點(diǎn),斷連的 TCP 連接已經(jīng)不能傳遞任何信息,因此,維護(hù)大量斷連的 TCP 連接將導(dǎo)致系統(tǒng)資源的浪費(fèi)。這種系統(tǒng)資源的浪費(fèi)可能并不會(huì)對(duì)客戶(hù)端節(jié)點(diǎn)帶來(lái)太大問(wèn)題;然而,對(duì)于服務(wù)器主機(jī)而言,這可能會(huì)導(dǎo)致系統(tǒng)資源(尤指內(nèi)存資源和 socket 資源)被耗盡而拒絕為新的用戶(hù)請(qǐng)求提供服務(wù)。因此在實(shí)際應(yīng)用中,服務(wù)器端需要采取相應(yīng)的方法來(lái)探測(cè) TCP 連接是否已經(jīng)斷連。
探測(cè) TCP 連接斷連的三種常用方法
探測(cè) TCP 連接是否斷連或是工作正常的原理比較簡(jiǎn)單:定期向連接的遠(yuǎn)程通信節(jié)點(diǎn)發(fā)送一定格式的信息并等待遠(yuǎn)程通信節(jié)點(diǎn)的反饋,如果在規(guī)定時(shí)間內(nèi)收到來(lái)自遠(yuǎn)程節(jié)點(diǎn)的正 確的反饋信息,那么該連接就是正常的,否則該連接已經(jīng)斷連。依據(jù)該原理,目前常用的探測(cè)方法有以下三種。
應(yīng)用程序的自我探測(cè)
應(yīng)用程序本身附帶探測(cè)其自身建立的 TCP 連接的功能。這種方法具有極大的靈活性,可以依據(jù)應(yīng)用本身的特點(diǎn)選擇相應(yīng)的探測(cè)機(jī)制和功能實(shí)現(xiàn)。然而,實(shí)際應(yīng)用中,大部分應(yīng)用程序均沒(méi)有附帶自我探測(cè)的功能。
第三方應(yīng)用程序的探測(cè)
此種方法就是在服務(wù)節(jié)點(diǎn)上安裝相應(yīng)的第三方應(yīng)用程序來(lái)探測(cè)該節(jié)點(diǎn)上所有的 TCP 連接是否正常或是已經(jīng)斷連。該方法最大的不足就是需要所有支持探測(cè)的客戶(hù)端能夠識(shí)別來(lái)自該探測(cè)應(yīng)用的數(shù)據(jù)報(bào)文,因此,實(shí)際應(yīng)用中比較少見(jiàn)。
TCP 協(xié)議層的保活探測(cè)
最常用的探測(cè)方法就是采用 TCP 協(xié)議層提供的保活探測(cè)功能即 TCP 連接保活定時(shí)器。盡管該功能并不是 RFC 規(guī)范的一部分,但是幾乎所有的類(lèi) Unix 系統(tǒng)均實(shí)現(xiàn)了該功能,所以使得該探測(cè)方法被廣泛使用。
接下來(lái)的部分,我們將重點(diǎn)討論來(lái)自 TCP 協(xié)議層的保活探測(cè)方法。
類(lèi) Unix 系統(tǒng)上的 TCP 連接保活定時(shí)器
TCP 連接的保活定時(shí)器可以在應(yīng)用層實(shí)現(xiàn),也可以在 TCP 中提供。這個(gè)問(wèn)題存在爭(zhēng)議,因此 TCP 連接的保活探測(cè)并不是 TCP 規(guī)范中的一部分。但為了方便,幾乎所有類(lèi) Unix 系統(tǒng)均在 TCP 中提供了相應(yīng)的功能。
清單 2. 常見(jiàn) Unix 系統(tǒng)上的保活定時(shí)器
操作系統(tǒng) 保活定時(shí)器
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=…
不同系統(tǒng)上的各參數(shù)的時(shí)間單位不盡相同。在 AIX 上,tcp_keeidle/tcp_keepinit/tcp_keepintvl 的時(shí)間單位是 0.5 秒;而在 Linux 上,net.ipv4.tcp_keepalive_intvl 和 net.ipv4.tcp_keepalive_time 的時(shí)間單位則為秒。并且,上述參數(shù)僅對(duì)運(yùn)行在其上的服務(wù)器應(yīng)用連接有效。
注:在 Solaris 上可通過(guò)“ndd /dev/tcp \?”命令顯示上述類(lèi)似參數(shù)信息,而在 HP Unix 上則可通過(guò) nettune 或 ndd 命令進(jìn)行查詢(xún)。
由于所有類(lèi) Unix 系統(tǒng)上均支持這種功能,因此,在接下來(lái)的部分中我們將基于 AIX 系統(tǒng)具體講述上述參數(shù)的意義和作用機(jī)制。
AIX 中的 TCP 連接保活探測(cè)機(jī)制及原理
正如清單 2 中列出的一樣,AIX 上的保活探測(cè)機(jī)制由 4 個(gè)參數(shù)來(lái)控制,其具體意義見(jiàn)清單 3:
清單 3. AIX 上的保活定時(shí)器控制參數(shù)
控制參數(shù) 參數(shù)說(shuō)明
tcp_keepcnt關(guān)閉一個(gè)非活躍連接之前進(jìn)行探測(cè)的最大次數(shù),默認(rèn)為 8 次
tcp_keepidle對(duì)一個(gè)連接進(jìn)行有效性探測(cè)之前運(yùn)行的最大非活躍時(shí)間間隔,默認(rèn)值為 14400(即 2 個(gè)小時(shí))
tcp_keepintvl兩個(gè)探測(cè)的時(shí)間間隔,默認(rèn)值為 150 即 75 秒
我們來(lái)看一個(gè)具體的例子。在 testServer 端(AIX 主機(jī))采用 tcp_keepidel=240(即 2 分鐘):tcp_keepcnt=8:tcp_keepintvl=150(即 75 秒)的參數(shù)值;啟動(dòng) testServer 上的 tcpdump 查看網(wǎng)絡(luò)包的交互情況;從 testClient 端發(fā)起請(qǐng)求建立和 testServer 之間的一個(gè) telnet 連接。在連接建立完成之后,拔出 testClient 端的網(wǎng)線并觀察服務(wù)器端的數(shù)據(jù)輸出(見(jiàn)清單 4)。
清單 4. telnet 連接在服務(wù)器端的 tcpdump 輸出
1 # tcpdump -i en1 host testServer.cn.ibm.com
2 04:51:51.379716 IP testClient.cn.ibm.com.telnet.40621 》
testServer.cn.ibm.com.telnet: S 4097149880:4097149880(0)
3 04:51:51.379755 IP testServer.cn.ibm.com.telnet 》
testClient.cn.ibm.com.40621: S 2543529892:2543529892(0) ack 4097149881
4 04:51:51.380609 IP testClient.cn.ibm.com.telnet.40621 》
testServer.cn.ibm.com.telnet: 。 ack 1
5 。。。
6 04:51:54.924058 IP testServer.cn.ibm.com.telnet 》
testClient.cn.ibm.com.40621: P 676:696(20) ack 87
7 04:51:54.924909 IP testClient.cn.ibm.com.telnet.40621 》
testServer.cn.ibm.com.telnet: 。 ack 696
8 04:53:54.550192 IP testServer.cn.ibm.com.telnet 》
testClient.cn.ibm.com.40621: 。 695:696(1) ack 86
9 04:55:09.550997 IP testServer.cn.ibm.com.telnet 》
testClient.cn.ibm.com.40621: 。 695:696(1) ack 86
10 04:56:24.552053 IP testServer.cn.ibm.com.telnet 》
testClient.cn.ibm.com.40621: 。 695:696(1) ack 86
11 04:57:39.552615 IP testServer.cn.ibm.com.telnet 》
testClient.cn.ibm.com.40621: 。 695:696(1) ack 86
12 04:58:54.553446 IP testServer.cn.ibm.com.telnet 》
testClient.cn.ibm.com.40621: 。 695:696(1) ack 86
13 05:00:09.554287 IP testServer.cn.ibm.com.telnet 》
testClient.cn.ibm.com.40621: 。 695:696(1) ack 86
14 05:01:24.555117 IP testServer.cn.ibm.com.telnet 》
testClient.cn.ibm.com.40621: 。 695:696(1) ack 86
15 05:02:39.555958 IP testServer.cn.ibm.com.telnet 》
testClient.cn.ibm.com.40621: 。 695:696(1) ack 86
16 05:03:54.557282 IP testServer.cn.ibm.com.telnet 》
testClient.cn.ibm.com.40621: 。 695:696(1) ack 86
17 05:05:09.559795 IP testServer.cn.ibm.com.telnet 》
testClient.cn.ibm.com.40621: R 696:696(0) ack 87
從清單 4 中可以看出,第 6 行的報(bào)文是本連接發(fā)送的最后數(shù)據(jù),而第 7 行則是對(duì)第 6 行數(shù)據(jù)的確認(rèn)。其后,該連接上沒(méi)有任何數(shù)據(jù)交互,從而使得該連接一直處于非活躍狀態(tài)。經(jīng)過(guò) 2 分鐘(第 8 行數(shù)據(jù)報(bào)時(shí)間 04:53:54 和第 7 行數(shù)據(jù)報(bào)時(shí)間 04:51:54 之差,即 tcp_keepidle 的值)的非活躍時(shí)間后,第 8 行是服務(wù)器端發(fā)起第一個(gè)保活探測(cè)數(shù)據(jù)報(bào)。由于服務(wù)器端沒(méi)有收到客戶(hù)端關(guān)于探測(cè)報(bào)文的相應(yīng),因此再經(jīng)過(guò) tcp_keepintvl 的時(shí)間間隔(75 秒)之后,第 9 行顯示服務(wù)器端再次發(fā)起保活探測(cè)數(shù)據(jù)報(bào)。服務(wù)器端持續(xù)發(fā)送了 tcp_keepcnt 個(gè)探測(cè)報(bào)文(上面結(jié)果顯示,在 AIX 上是持續(xù)發(fā)送 tcp_keepcnt+1 個(gè)探測(cè)報(bào)文)之后,仍然沒(méi)有收到來(lái)自客戶(hù)端的任何回應(yīng),所以服務(wù)器在第 17 行向客戶(hù)端發(fā)送復(fù)位報(bào)文同時(shí)在服務(wù)器端關(guān)閉了該連接。
需要注意的是,保活探測(cè)雖然通過(guò)發(fā)送 TCP 探測(cè)報(bào)文,但探測(cè)報(bào)文不會(huì)對(duì)正常的 TCP 連接產(chǎn)生任何影響。從清單 4 可以看出,第 8 行發(fā)送數(shù)據(jù)的 TCP 報(bào)文序號(hào)為 695 起始的 1Byte 數(shù)據(jù),而該數(shù)據(jù)在第 6 行已經(jīng)發(fā)送并被客戶(hù)端確認(rèn)。對(duì)于正常狀態(tài)的連接,客戶(hù)端在收到探測(cè)報(bào)文之后將返回一個(gè)第 7 行所示的 ACK 報(bào)文并借此向服務(wù)器端表明連接工作正常。
接下來(lái),我們將通過(guò)一個(gè)實(shí)際的 TCP 斷連的例子來(lái)分析上述機(jī)制對(duì) TCP 連接保持的影響,并針對(duì)需要長(zhǎng)時(shí)間保持 TCP 連接的應(yīng)用提出兩種可選的解決方案。
AIX 上的 TCP 斷連及數(shù)據(jù)分析
圖 3. 出現(xiàn) TCP 斷連的網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)示意圖
所有服務(wù)器主機(jī)均劃為一個(gè)局域網(wǎng),并處于防火墻 B 之后。由于工作需要,來(lái)自工作區(qū)局域網(wǎng)的主機(jī) testClient 需和服務(wù)器局域網(wǎng)內(nèi)的 testServer 上的數(shù)據(jù)庫(kù)使用 TCP/IP 建立一個(gè)連接,testClient 上的上層應(yīng)用將通過(guò)該連接對(duì) testServer 上的數(shù)據(jù)庫(kù)進(jìn)行相應(yīng)操作。
在實(shí)際測(cè)試中,我們發(fā)現(xiàn),在 testClient 和 testServer 均工作正常的情況下,testClient 上的客戶(hù)端在事先沒(méi)有收到任何異常信息的情況下,所持有的連接會(huì)出現(xiàn)非預(yù)期的斷連現(xiàn)象(在試圖通過(guò)連接進(jìn)行數(shù)據(jù)庫(kù)操作時(shí),會(huì)被告知 connection is reset by foreign host 的錯(cuò)誤)。
由于該現(xiàn)象不斷出現(xiàn),并且網(wǎng)絡(luò)內(nèi)的中間節(jié)點(diǎn)(路由器和交換機(jī)等)均工作正常,因此可以排除物理因素(如掉電、宕機(jī)等)的可能。為了便于分析斷連原因,我們首先查看了 testServer 機(jī)器上的默認(rèn)保活設(shè)置:
# no -a | grep keep
tcp_keepcnt = 8
tcp_keepidle = 14400
tcp_keepintvl = 150
testServer 上的 tcp_keepidle 為 14400,即 2 個(gè)小時(shí)。既然中間節(jié)點(diǎn)工作正常,為什么保活機(jī)制沒(méi)有其作用呢?為了進(jìn)行分析,我們采用 tcpdump 工具捕獲 testClient 和 testServer 上的報(bào)文信息,見(jiàn)清單 5 和清單 6 所示。
清單 5. 服務(wù)器端的 tcpdump 數(shù)據(jù)輸出
1 10:18:58.881950 IP testClient.cn.ibm.com.59098 》
testServer.cn.ibm.com.telnet: S 1182666808:1182666808(0) 。。。
2 10:18:58.882001 IP testServer.cn.ibm.com.telnet 》
testClient.cn.ibm.com.59098: S 3333341833:3333341833(0) ack 1182666809 。。。
3 10:18:58.882845 IP testClient.cn.ibm.com.59098 》
testServer.cn.ibm.com.telnet: 。 ack 1 。。。
4 。。。
5 10:19:03.165568 IP testServer.cn.ibm.com.telnet 》
testClient.cn.ibm.com.59098: P 1010:1032(22) ack 87 。。。
6 10:19:03.166457 IP testClient.cn.ibm.com.59098 》
testServer.cn.ibm.com.telnet: 。 ack 1032 。。。
7 12:19:05.445336 IP testServer.cn.ibm.com.telnet 》
testClient.cn.ibm.com.59098: 。 1031:1032(1) ack 86 。。。
8 12:19:05.445464 IP testClient.cn.ibm.com.59098 》
testServer.cn.ibm.com.telnet: R 86:87(1) ack 1031 。。。
清單 6. 客戶(hù)端的 tcpdump 數(shù)據(jù)輸出
1 # tcpdump -e -i eth0 host testServer.cn.ibm.com
2 10:18:55.800553 IP testClient.cn.ibm.com.59098 》
testServer.cn.ibm.com.telnet: S 1182666808:1182666808(0) 。。。
3 10:18:55.801778 IP testServer.cn.ibm.com.telnet 》
testClient.cn.ibm.com.59098: S 3333341833:3333341833(0) ack 1182666809 。。。
4 10:18:55.801799 IP testClient.cn.ibm.com.59098 》
testServer.cn.ibm.com.telnet: 。 ack 1 。。。
5 。。。
6 10:19:00.084662 IP testServer.cn.ibm.com.telnet 》
testClient.cn.ibm.com.59098: P 1010:1032(22) ack 87 。。。
7 10:19:00.084678 IP testClient.cn.ibm.com.59098 》
testServer.cn.ibm.com.telnet: 。 ack 1032 。。。
從清單 5 中可以看出,在該連接處于非活躍狀態(tài)的時(shí)間達(dá)到 tcp_keepidle 設(shè)定的 2 小時(shí)時(shí),服務(wù)器主機(jī)發(fā)出了第一個(gè)連接保活的探測(cè)報(bào)文(清單 5 中的第 7 行)。緊接著,服務(wù)器主機(jī)就收到了來(lái)自 testClient 的連接復(fù)位報(bào)文(清單 5 中的第 8 行)。之后,服務(wù)器便關(guān)閉了該連接(可以通過(guò) netstat –ni 來(lái)查看)。然而,從清單 6 的 tcpdump 數(shù)據(jù)可以看出, testClient 端并未發(fā)送任何報(bào)文。那么,是誰(shuí)向 testServer 發(fā)送了復(fù)位報(bào)文呢?
為了查看上述復(fù)位報(bào)文的發(fā)送者,同樣采用上述 tcpdump 命令再次捕獲服務(wù)器端和防火墻 B 的報(bào)文信息(注意:通常需要捕獲防火墻主機(jī)上網(wǎng)絡(luò)數(shù)據(jù)的出口網(wǎng)卡和入口網(wǎng)卡數(shù)據(jù)),結(jié)果顯示,防火墻 B 在收到來(lái)自 testServer 的第一個(gè)探測(cè)報(bào)文之后就立刻向 testServer 發(fā)送了一個(gè)復(fù)位報(bào)文。
上述分析說(shuō)明,在連接傳遞完最后一個(gè)交互數(shù)據(jù)之后到服務(wù)器端發(fā)送第一個(gè)保活探測(cè)之間,該連接已經(jīng)被防火墻 B 終止;在此之后,基于該連接的任何報(bào)文傳遞在試圖穿過(guò)防火墻的時(shí)候均會(huì)被防火墻丟棄并發(fā)送復(fù)位報(bào)文。
兩種常用的解決方案
針對(duì)上述 TCP 斷連現(xiàn)象,有兩種常用的解決方案可供選擇:
方案 1、延長(zhǎng)防火墻終止非活躍的 TCP 連接的時(shí)間。例如,針對(duì)上述案例,可以調(diào)節(jié)防火墻設(shè)置,將時(shí)間設(shè)置為大于服務(wù)器端設(shè)定的 2 小時(shí)。
方案 2、縮短服務(wù)器端的 TCP 連接保活時(shí)間。縮短該時(shí)間的目的是為了在連接被防火墻終止之前發(fā)送保活探測(cè)報(bào)文,既可以探測(cè)客戶(hù)端狀態(tài),又可以使連接變?yōu)榛钴S狀態(tài)。
對(duì)于第一種方案而言,延長(zhǎng) TCP 連接的保持時(shí)間可能會(huì)導(dǎo)致防火墻性能的降低,尤其是在維持大量長(zhǎng)時(shí)間處于非活躍狀態(tài)的連接的情況下更是如此;而對(duì)于第二種方案,如果縮短服務(wù)器端的 TCP 連接保活時(shí)間,意味著會(huì)增加網(wǎng)絡(luò)中的數(shù)據(jù)報(bào)文數(shù)而占用額外的網(wǎng)絡(luò)帶寬。因此,兩種方案各有利弊,需要依據(jù)不同的實(shí)際應(yīng)用情況進(jìn)行選擇。
總結(jié)
本文介紹了 TCP 連接的建立和保持的相關(guān)概念以及影響 TCP 連接保持的常見(jiàn)因素。給出了常見(jiàn)的類(lèi) Unix 系統(tǒng)上 TCP 連接保活探測(cè)的相關(guān)配置參數(shù),并基于 AIX 借助 tcpdump 工具分析了一個(gè)實(shí)際的 TCP 斷連的案例。最后,針對(duì) TCP 斷連的情況給出了兩種可行的解決方案。
評(píng)論