1. 程式人生 > >TCP狀態轉換圖解析

TCP狀態轉換圖解析

new ping命令 滿足 決定 網絡 pen dns設置 所有 netstat

本文參考Unix網絡編程卷1,對TCP狀態轉換進行總結,方便掌握TCP鏈接中各個狀態及故障分析。

1.Linux下TCP相關工具

  基於Linux系統查看網絡狀態,首先了解幾個基本查看指令。

Linux查看網絡狀態的命令:

  1. netstat -nat 查看TCP各個狀態的數量
  2. lsof -i:port , 可以檢測到打開套接字的狀況。lsof(list open files)列出當前系統打開的文本的工具。
  3. tcpdump -iany tcp port 9000 ,對tcp端口為9000的進行抓包。 tcpdump為Linux下的抓包工具。
  4. sar -n SOCK 查看tcp創建的連接數

網絡測試使用的Linux命令:、

  1.ping:檢測網絡連接的正常與否,主要是測試延時、抖動、丟包率。

    ping命令使用ICMP協議,用於測試網絡的連通性,可以通過接受到的返回值簡單查看測試網絡經過的路由數(由TTL值判斷)及網絡延遲時間。

  2.traceroute: 跟蹤數據包到達網絡主機所經過的路由工具

    使用方法:traceroute hostname

  3.pathping:是一個路由跟蹤工具,它將 ping 和 tracert 命令的功能與這兩個工具所不提供的其他信息結合起來,綜合了二者的功能。

    使用方法:pathping www.baidu.com

  4.mtr:以結合ping nslookup tracert 來判斷網絡的相關特性。

  5.nslookup:用於解析域名,一般用來檢測本機的DNS設置是否配置正確。

2.TCP狀態

  使用netstat命令查看TCP連接,在每個連接後會顯示連接狀態,各個狀態說明如下:

  1.LISTEN:偵聽來自遠方的TCP端口的連接請求(服務器端進入監聽狀態)     首先TCP連接服務器打開一個socket連接,在進行Listen函數調用後,綁定端口編程LISTEN狀態。     處於偵聽LISTENING狀態時,該端口是開放的,等待連接,但還沒有被連接。就像你房子的門已經敞開的,但還沒有人進來。

  2.SYN-SENT:再發送連接請求後等待匹配的連接請求(客戶端發送連接請求後)
     客戶端在發送連接請求後等待匹配的連接請求:客戶端通過應用程序調用connect進行active open.於是客戶端tcp發送一個SYN以請求建立一個連接.之後狀態置為SYN_SENT.

  3.SYN-RECEIVED:再收到和發送一個連接請求後等待對方對連接請求的確認(服務端接收到SYN後發送確認,等待客戶端對此確認的確認)
     在收到和發送一個連接請求後等待對方對連接請求的確認。    當服務器收到客戶端發送的同步信號時,將標誌位ACK和
    如果發現有很多SYN_RCVD狀態,那你的機器有可能被SYN Flood的DoS(拒絕服務攻擊)攻擊了。
  SYN Flood的攻擊原理是:   在進行三次握手時,攻擊軟件向被攻擊的服務器發送SYN連接請求(握手的第一步),但是這個地址是偽造的,如攻擊軟件隨機偽造了51.133.163.104、65.158.99.152等等地址。服務器在收到連接請求時將標誌位ACK和SYN置1發送給客戶端(握手的第二步),但是這些客戶端的IP地址都是偽造的,服務器根本找不到客戶機,也就是說握手的第三步不可能完成。    這種情況下服務器端一般會重試(再次發送SYN+ACK給客戶端)並等待一段時間後丟棄這個未完成的連接,這段時間的長度我們稱為SYN Timeout,一般來說這個時間是分鐘的數量級(大約為30秒-2分鐘);一個用戶出現異常導致服務器的一個線程等待1分鐘並不是什麽很大的問題,但如果有一個惡意的攻擊者大量模擬這種情況,服務器端將為了維護一個非常大的半連接列表而消耗非常多的資源----數以萬計的半連接,即使是簡單的保存並遍歷也會消耗非常多的   4.ESTABLISHED:代表一個打開的連接(三次握手進行完畢)
    狀態為ESTABLISHED表示此端口處於連接狀態,正在進行數據傳輸。     異常及原因:
    客戶端正常斷開時會發送FIN報給服務端,此後服務端處於CLOSE_WAIT狀態。     客戶端非正常斷開時不會發送FIN報給服務端,服務端將長期處於ESTABLISHED狀態。     如果客戶端不斷重復掉線-連接過程,服務端將會出現大量的無效的ESTABLISHED和CLOSE_WAIT,導致資源耗盡,新的客戶端無法連接(netstat仍可看到ESTABLISHED狀態但是無法進行數據傳輸)   5.FIN-WAIT-1:等待遠程TCP連接中斷請求,或先前的連接中斷請求的確認(主動發送FIN報後)
     主動關閉(active close)端應用程序調用close,於是其TCP發出FIN請求主動關閉連接,之後進入FIN_WAIT1狀態。      如果服務器出現shutdown再重啟,使用netstat -nat查看,就會看到很多FIN-WAIT-1的狀態。就是因為服務器當前有很多客戶端連接,直接關閉服務器後,無法接收到客戶端的ACK。
  6.FIN-WAIT-2:從遠程TCP等待連接中斷請求(接收到FIN的ACK後)
     主動關閉端接到ACK後,就進入了FIN-WAIT-2 狀態。      這就是著名的半關閉的狀態了,這是在關閉連接時,客戶端和服務器兩次握手之後的狀態。在這個狀態下,應用程序還有接受數據的能力,但是已經無法發送數據,但是也有一種可能是,客戶端一直處於    FIN_WAIT_2狀態,而服務器則一直處於WAIT_CLOSE狀態,而直到應用層來決定關閉這個狀態。
  7.CLOSE-WAIT:等待從本地用戶發來的連接中斷請求(服務端接收到FIN並發送ACK後)
    服務端接收到遠程客戶端發送的FIN報並發送ACK進行確認後等待本地用戶發送的中斷請求期間處於CLOSE-WAIT狀態。
  8.CLOSING:等待遠程TCP對連接中斷的確認(尚不清楚狀態)
    不常見
  9.LAST-ACK:等待原來的發向遠程TCP的連接中斷請求的確認(服務端發送FIN後等待客戶端的ACK)
    被動關閉端(服務端)一段時間後,接收到文件結束符的應用程序將調用CLOSE關閉連接。這導致它的TCP也發送一個 FIN,等待對方的ACK.就進入了LAST-ACK
  10.TIME-WAIT:等待足夠的時間以確保遠程TCP接收到連接中斷請求的確認(客戶端接收到FIN後發送ACK,等待確保服務端接收到此ACK)
    在客戶端接收到FIN後,TCP就發送ACK包,並進入TIME-WAIT狀態。     此等待時間可能造成的問題:     TIME_WAIT等待狀態,這個狀態又叫做2MSL狀態,說的是在TIME_WAIT2發送了最後一個ACK數據報以後,要進入TIME_WAIT狀態,這個狀態是防止最後一次握手的數據報沒有傳送到對方那裏而準備的(註  意這不是四次握手,這是第四次握手的保險狀態)。這個狀態在很大程度上保證了雙方都可以正常結束,但是,問題也來了。   由於插口的2MSL狀態(插口是IP和端口對的意思,socket),使得應用程序在2MSL時間內是無法再次使用同一個插口的,對於客戶程序還好一些,但是對於服務程序,例如httpd,它總是要使用同一個端口來進  行服務,而在2MSL時間內,啟動httpd就會出現錯誤(插口被使用)。為了避免這個錯誤,服務器給出了一個平靜時間的概念,這是說在2MSL時間內,雖然可以重新啟動服務器,但是這個服務器還是要平靜的等  待2MSL時間的過去才能進行下一次連接。
  11.CLOSED:沒有任何連接狀態(服務端接收到ACK後進入)

3.TCP狀態轉換圖

  如下轉換圖展示了服務端和客戶端的狀態轉換關系。

    技術分享

TCP連接中的3次握手及4次揮手示意圖:

      技術分享

客戶端應用程序的狀態遷移圖 客戶端的狀態可以用如下的流程來表示: CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED 以上流程是在程序正常的情況下應該有的流程,從書中的圖中可以看到,在建立連接時,當客戶端收到SYN報文的ACK以後,客戶端就打開了數據交互地連接。而結束連接則通常是客戶端主動結束的,客戶端結束應用程序以後,需要經歷FIN_WAIT_1,FIN_WAIT_2等狀態,這些狀態的遷移就是前面提到的結束連接的四次握手。
服務器的狀態遷移圖 服務器的狀態可以用如下的流程來表示: CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED 在建立連接的時候,服務器端是在第三次握手之後才進入數據交互狀態,而關閉連接則是在關閉連接的第二次握手以後(註意不是第四次)。而關閉以後還要等待客戶端給出最後的ACK包才能進入初始的狀態。

4.TCP狀態轉換中部分難點

  1.什麽是半打開連接?什麽是半關閉連接?

    TCP的半開連接(half-open)是指TCP連接的一端崩潰,或者在未通知對端的情況下移除socket,不可以正常收發數據,否則會產生RST

    TCP的半關閉是指TCP連接的一端調用shutdown操作使數據只能往一個方向流動,只有一方發送了FIN,仍然可以正常收(或發)數據。

  2..為什麽建立連接協議是三次握手,而關閉連接卻是四次握手呢?

    這是因為服務端的LISTEN狀態下的SOCKET當收到SYN報文的建連請求後,它可以把ACK和SYN(ACK起應答作用,而SYN起同步作用)放在一個報文裏來發送。但關閉連接時,當收到對方的FIN報文通知時,它僅僅表示對方沒有數據發    送給你了;但未必你所有的數據都全部發送給對方了,所以你可以未必會馬上會關閉SOCKET,也即你可能還需要發送一些數據給對方之後,再發送FIN報文給對方來表示你同意現在可以關閉連接了,所以它這裏的ACK報文和FIN報文多數情況下    都是分開發送的。

  3.為什麽TIME_WAIT狀態還需要等2MSL後才能返回到CLOSED狀態?

      這是因為雖然雙方都同意關閉連接了,而且握手的4個報文也都協調和發送完畢,按理可以直接回到CLOSED狀態(就好比從SYN_SEND狀態到ESTABLISH狀態那樣):

     一方面是可靠的實現TCP全雙工連接的終止,也就是當最後的ACK丟失後,被動關閉端會重發FIN,因此主動關閉端需要維持狀態信息,以允許它重新發送最終的ACK。

      另一方面,但是因為我們必須要假想網絡是不可靠的,你無法保證你最後發送的ACK報文會一定被對方收到,因此對方處於LAST_ACK狀態下的SOCKET可能會因為超時未收到ACK報文,而重發FIN報文,所以這個TIME_WAIT狀態的作用    就是用來重發可能丟失的ACK報文。

     TCP在2MSL等待期間,定義這個連接(4元組)不能再使用,任何遲到的報文都會丟棄。設想如果沒有2MSL的限制,恰好新到的連接正好滿足原先的4元組,這時候連接就可能接收到網絡上的延遲報文就可能    幹擾最新建立的連接。

  4.發現系統存在大量TIME_WAIT狀態的連接,可以通過調整內核參數解決:vi /etc/sysctl.conf 加入以下內容:
    net.ipv4.tcp_syncookies = 1
    net.ipv4.tcp_tw_reuse = 1
    net.ipv4.tcp_tw_recycle = 1
    net.ipv4.tcp_fin_timeout = 30
     然後執行 /sbin/sysctl -p 讓參數生效。
    net.ipv4.tcp_syncookies = 1 表示開啟SYN Cookies。當出現SYN等待隊列溢出時,啟用cookies來處理,可防範少量SYN攻擊,默認為0,表示關閉;
    net.ipv4.tcp_tw_reuse = 1 表示開啟重用。允許將TIME-WAIT sockets重新用於新的TCP連接,默認為0,表示關閉;
    net.ipv4.tcp_tw_recycle = 1 表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉。
    net.ipv4.tcp_fin_timeout 修改系統默認的 TIMEOUT 時間

TCP狀態轉換圖解析