TCP狀態變化分析

1,查看tcp狀態工具服務器

工欲善其事必先利其器,先了解下查看tcp狀態的工具cookie

1),netstat 網絡

Netstat 命令用於顯示各類網絡相關信息,如網絡鏈接,路由表,接口狀態 (Interface Statistics),masquerade 鏈接,多播成員 (Multicast Memberships) 等等。併發

-a (all)顯示全部選項,默認不顯示LISTEN相關
-t (tcp)僅顯示tcp相關選項
-u (udp)僅顯示udp相關選項
-n 拒絕顯示別名,能顯示數字的所有轉化成數字。
-l 僅列出有在 Listen (監聽) 的服務狀態socket

-p 顯示創建相關連接的程序名
-r 顯示路由信息,路由表
-e 顯示擴展信息,例如uid等
-s 按各個協議進行統計
-c 每隔一個固定時間,執行該netstat命令。tcp

2)、lsof  -i:port  能夠檢測到打開套接字的情況函數

lsof(list open files)是一個列出當前系統打開文件的工具工具

3)、  sar -n SOCK 查看tcp建立的鏈接數 (System Activity Reporter)測試

4)、tcpdump -iany tcp port 9000 對tcp端口爲9000的進行抓包ui

5)traceroute:raceroute 跟蹤數據包到達網絡主機所通過的路由工具

2 tcp狀態

LISTENING:偵聽來自遠方的TCP端口的鏈接請求

   Server端調用bind操做,將監聽套接字與指定的地址和端口關聯,而後又調用listen函數,系統會爲其分配未完成隊列和完成隊列,此時的監聽套接字能夠接受Client的鏈接,監聽套接字狀態處於LISTEN狀態。

SYN_SEND:客戶端經過應用程序調用connect進行active open.因而客戶端tcp發送一個SYN以請求創建一個鏈接.以後狀態置爲SYN_SENT

SYN_RCVD: 服務端收到SYN,將標誌位SYN和ACK置1,發送給客戶端, 此時爲SYN_RCVD狀態。

    SYN Flood的攻擊原理是:
   在進行三次握手時,攻擊軟件向被攻擊的服務器發送SYN鏈接請求(握手的第一步),可是這個地址是僞造的,如攻擊軟件隨機僞造了51.133.163.10四、65.158.99.152等等地址。服務器在收到鏈接請求時將標誌位ACK和SYN置1發送給客戶端(握手的第二步),可是這些客戶端的IP地址都是僞造的,服務器根本找不到客戶機,也就是說握手的第三步不可能完成。

ESTABLISHED:表明一個打開的鏈接。

   netstat -nat |grep 9502或者使用lsof  -i:9502能夠檢測到。

 當客戶端未主動close的時候就斷開鏈接:即客戶端發送的FIN丟失或未發送。
        這時候若客戶端斷開的時候發送了FIN包,則服務端將會處於CLOSE_WAIT狀態;

         這時候若客戶端斷開的時候未發送FIN包,則服務端處仍是顯示ESTABLISHED狀態;

          結果客戶端從新鏈接服務器。

          而新鏈接上來的客戶端(也就是剛纔斷掉的從新連上來了)在服務端確定是ESTABLISHED; 若是客戶端重複的上演這種狀況,那麼服務端將會出現大量的假的ESTABLISHED鏈接和CLOSE_WAIT鏈接。

         最終結果就是新的其餘客戶端沒法鏈接上來,可是利用netstat仍是能看到一條鏈接已經創建,並顯示ESTABLISHED,但始終沒法進入程序代碼。

關閉(四次揮手)

FIN_WAIT1:

      主動關閉(active close)端應用程序調用close,因而其TCP發出FIN請求主動關閉鏈接,以後進入FIN_WAIT1狀態./* The socket is closed, and the connection is shutting down. 等待遠程TCP的鏈接中斷請求,或先前的鏈接中斷請求的確認 */
      若是服務器出現shutdown再重啓,使用netstat -nat查看,就會看到不少FIN-WAIT-1的狀態。就是由於服務器當前有不少客戶端鏈接,直接關閉服務器後,沒法接收到客戶端的ACK。

CLOSE-WAIT:等待從本地用戶發來的鏈接中斷請求
         被動關閉(passive close)端TCP接到FIN後,就發出ACK以迴應FIN請求(它的接收也做爲文件結束符傳遞給上層應用程序),並進入CLOSE_WAIT. /* The remote end has shut down, waiting for the socket to close. 等待從本地用戶發來的鏈接中斷請求 */

FIN-WAIT-2:從遠程TCP等待鏈接中斷請求
       主動關閉端接到ACK後,就進入了FIN-WAIT-2 ./* Connection is closed, and the socket is waiting for a shutdown from the remote end. 從遠程TCP等待鏈接中斷請求 */
        這就是著名的半關閉的狀態了,這是在關閉鏈接時,客戶端和服務器兩次握手以後的狀態。在這個狀態下,應用程序還有接受數據的能力,可是已經沒法發送數據,可是也有一種多是,客戶端一直處於FIN_WAIT_2狀態,而服務器則一直處於WAIT_CLOSE狀態,而直到應用層來決定關閉這個狀態

LAST-ACK:等待原來的發向遠程TCP的鏈接中斷請求的確認
       被動關閉端一段時間後,接收到文件結束符的應用程序將調用CLOSE關閉鏈接。這致使它的TCP也發送一個 FIN,等待對方的ACK.就進入了LAST-ACK . /* The remote end has shut down, and the socket is closed. Waiting for acknowledgement. 等待原來發向遠程TCP的鏈接中斷請求的確認 */
使用併發壓力測試的時候,忽然斷開壓力測試客戶端,服務器會看到不少LAST-ACK。

TIME-WAIT:等待足夠的時間以確保遠程TCP接收到鏈接中斷請求的確認
在主動關閉端接收到FIN後,TCP就發送ACK包,並進入TIME-WAIT狀態。/* The socket is waiting after close to handle packets still in the network.等待足夠的時間以確保遠程TCP接收到鏈接中斷請求的確認 */
            TIME_WAIT等待狀態,這個狀態又叫作2MSL狀態,說的是在TIME_WAIT2發送了最後一個ACK數據報之後,要進入TIME_WAIT狀態,這個狀態是防止最後一次握手的數據報沒有傳送到對方那裏而準備的(注意這不是四次握手,這是第四次握手的保險狀態)。這個狀態在很大程度上保證了雙方均可以正常結束,可是,問題也來了。
因爲插口的2MSL狀態(插口是IP和端口對的意思,socket),使得應用程序在2MSL時間內是沒法再次使用同一個插口的,對於客戶程序還好一些,可是對於服務程序,例如httpd,它老是要使用同一個端口來進行服務,而在2MSL時間內,啓動httpd就會出現錯誤(插口被使用)。爲了不這個錯誤,服務器給出了一個平靜時間的概念,這是說在2MSL時間內,雖然能夠從新啓動服務器,可是這個服務器仍是要平靜的等待2MSL時間的過去才能進行下一次鏈接。

 client/server兩條路線講述TCP狀態遷移路線圖:

 

 

1.爲何創建鏈接協議是三次握手,而關閉鏈接倒是四次握手呢?

        這是由於服務端的LISTEN狀態下的SOCKET當收到SYN報文的建連請求後,它能夠把ACK和SYN(ACK起應答做用,而SYN起同步做用)放在一個報文裏來發送。但關閉鏈接時,當收到對方的FIN報文通知時,它僅僅表示對方沒有數據發送給你了;但未必你全部的數據都所有發送給對方了,因此你能夠未必會立刻會關閉SOCKET,也即你可能還須要發送一些數據給對方以後,再發送FIN報文給對方來表示你贊成如今能夠關閉鏈接了,因此它這裏的ACK報文和FIN報文多數狀況下都是分開發送的。

2.爲何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元組,這時候鏈接就可能接收到網絡上的延遲報文就可能干擾最新創建的鏈接。

三、發現系統存在大量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 時間

 服務器端主動關閉:

   1)當服務器的服務由於某種緣由,進程提早終止時會向客戶 TCP 發送 FIN 分節,服務器端處於FIN_WAIT1狀態。

   2)客戶TCP迴應ACK後,服務TCP將轉入FIN_WAIT2狀態。

   3)此時若是客戶進程沒有處理該 FIN (如阻塞在其它調用上而沒有關閉 Socket 時),則客戶TCP將處於CLOSE_WAIT狀態。

   4)當客戶進程再次向 FIN_WAIT2 狀態的服務 TCP 發送數據時,則服務 TCP 將馬上響應 RST。

TIME_WAIT狀態存在的理由:
1)可靠地實現TCP全雙工鏈接的終止:(即在TIME_WAIT下等待2MSL,只是爲了盡最大努力保證四次握手正常關閉)。

      TCP協議規定,對於已經創建的鏈接,網絡雙方要進行四次握手才能成功斷開鏈接,若是缺乏了其中某個步驟,將會使鏈接處於假死狀態,鏈接自己佔用的資源不會被釋放。

    在進行關閉鏈接四路握手協議時,最後的ACK是由主動關閉端發出的,若是這個最終的ACK丟失,服務器將重發最終的FIN,所以客戶端必須維護狀態信息容許它重發最終的ACK。若是不維持這個狀態信息,那麼客戶端將響應RST分節,於是,要實現TCP全雙工鏈接的正常終止,必須處理終止序列四個分節中任何一個分節的丟失狀況,主動關閉的客戶端必須維持狀態信息進入TIME_WAIT狀態。

    咱們看客戶端主動關閉服務器被動關閉四次握手的流程:


一、 客戶端發送FIN報文段,進入FIN_WAIT_1狀態。

二、 服務器端收到FIN報文段,發送ACK表示確認,進入CLOSE_WAIT狀態。

三、 客戶端收到FIN的確認報文段,進入FIN_WAIT_2狀態。

四、 服務器端發送FIN報文端,進入LAST_ACK狀態。

五、 客戶端收到FIN報文端,發送FIN的ACK,同時進入TIME_WAIT狀態,啓動TIME_WAIT定時器,超時時間設爲2MSL。

六、 服務器端收到FIN的ACK,進入CLOSED狀態。

七、 客戶端在2MSL時間內沒收到對端的任何響應,TIME_WAIT超時,進入CLOSED狀態。

      若是不考慮報文延遲、丟失,確認延遲、丟失等狀況,TIME_WAIT的確沒有存在的必要。當網絡在不理想的狀況下一般會有報文的丟失延遲發生,讓咱們看下面的一個特例:

     客戶端進入發送收到四次握手關閉的最後一個ACK後,進入TIME_WAIT同時發送ACK,若是其不停留2MSL時間,而是立刻關閉鏈接,銷燬鏈接上的資源,當發送以下狀況時,將不能正常的完成四次握手關閉:

客戶端發送的ACK在網路上丟失,這樣服務器端收不到最後的ACK,重傳定時器超時,將重傳FIN到客戶端,因爲客戶端關於該鏈接的全部資源都釋放,收到重傳的FIN後,它沒有關於這個FIN的任何信息,因此向服務器端發送一個RST報文端,服務器端收到RST後,認爲搞鏈接出現了異常(而非正常關閉)。

因此,在TIME_WAIT狀態下等待2MSL時間端,是爲了可以正確處理第一個ACK(最長生存時間爲MSL)丟失的狀況下,可以收到對端重傳的FIN(最長生存時間爲MSL),而後重傳ACK。

     是否只要主動關閉方在TIME_WAIT狀態下停留2MSL,四次握手關閉就必定正常完成呢?

     答案是否認的?能夠考慮以下的狀況, 

     TIME_WAIT狀態下發送的ACK丟失,LAST_ACK時刻設定的重傳定時器超時,發送重傳的FIN,很不幸,這個FIN也丟失,主動關閉方在TIME_WAIT狀態等待2MSL沒收到任何報文段,進入CLOSED狀態,當此時被動關閉方並無收到最後的ACK。因此即便要主動關閉方在TIME_WAIT狀態下停留2MSL,也不必定表示四次握手關閉就必定正常完成。


2)確保老的報文段在網絡中消失,不會影響新創建的鏈接 
        考慮以下的狀況,主動關閉方在TIME_WAIT狀態下發送的ACK因爲網絡延遲的緣由沒有按時到底(但並無超過MSL的時間),致使被動關閉方重傳FIN,在FIN重傳後,延遲的ACK到達,被動關閉方進入CLOSED狀態,若是主動關閉方在TIME_WAIT狀態下發送ACK後立刻進入CLOSED狀態(也就是沒有等待)2MSL時間,則上述的鏈接已不存在:

       如今考慮下面的狀況,假設客戶端(192.186.0.1:23) 到服務器192.168.1.1:6380)的TCP鏈接, 因爲鏈接已關閉,咱們能夠立刻創建一個相同的IP地址和端口之間的TCP鏈接,而且這個鏈接也是客戶端(192.186.0.1:23) 到服務器192.168.1.1:6380),那麼當上一個鏈接的重傳FIN到達主動關閉方時,被新的鏈接所接受,這將致使新的鏈接被複位,很顯然,這不是咱們但願看到的事情。

 

引用:https://blog.csdn.net/hguisu/article/details/38700899

相關文章
相關標籤/搜索