(二)深入淺出TCPIP之再識TCP,理解TCP三次握手(上)

目錄

1.三次握手

 1.1 三次握手過程

1.2 TCP連接狀態

1.3 TCP狀態遷移路線分析

1.4 查看TCP狀態命令

2. 二次握手和四次握手

2.1 四次握手的過程:  

2.2二次握手的過程:

3.關於三次握手的連環發問(面試常問知識點)


專欄其他文章:

 理論篇:

(一)深入淺出TCPIP之理解TCP報文格式和交互流程

  (二)深入淺出TCPIP之再識TCP,理解TCP三次握手(上)

  (三)深入淺出TCPIP之再識TCP,理解TCP四次揮手(上)

  (四)深入淺出TCPIP之TCP三次握手和四次揮手(下)的抓包分析

  (五)深入淺出TCPIP之TCP流量控制

  (六)深入淺出TCPIP之TCP擁塞控制

  (七)深入淺出TCPIP之深入淺出TCPIP之TCP重傳機制

 (八)深入淺出TCPIP之TCP長連接與短連接詳解

 (九)深入淺出TCPIP之網絡同步異步

 (十)深入淺出TCPIP之網絡阻塞和非阻塞

(十一)深入淺出TCPIP之TCP粘包問題

  (十二)深入淺出TCPIP之Nagle算法

  (十三) 深入淺出TCPIP之TCP套接字參數

  (十四)深入淺出TCPIP之初識UDP理解報文格式和交互流程

  (十五)非常全面的TCPIP面試寶典-進入大廠必備總結

 (十六)深入淺出TCPIP之Hello CDN

 ....

(二十)深入淺出TCPIP之epoll的一些思考

實踐篇:

   深入淺出TCPIP之實戰篇—用c++開發一個http服務器(二十一)

 

其他網絡編程實踐篇+遊戲網絡疑難雜症解讀 文章正在更新中。。。

TCP作爲一種可靠傳輸控制協議,其核心思想:既要保證數據可靠傳輸,又要提高傳輸的效率,而用三次握手恰恰可以滿足以上兩方面的需求!

1.三次握手

         所謂的三次握手即TCP連接的建立。這個連接必須是一方主動打開,另一方被動打開的。TCP協議中,我們把主動發起請求的一端稱爲『客戶端』,被動連接的一端稱爲『服務端』。不管是客戶端還是服務端,TCP連接建立完後都能發送和接收數據。

 1.1 三次握手過程

         握手之前主動打開連接的客戶端結束CLOSED階段,被動打開的服務器端也結束CLOSED階段,並進入LISTEN階段。隨後開始“三次握手”:

第一次握手
客戶端向服務端發送連接請求報文段。該報文段的頭部中SYN=1,ACK=0,seq=x。請求發送後,客戶端便進入SYN-SENT狀態。

  • PS1:SYN=1,ACK=0表示該報文段爲連接請求報文。
  • PS2:x爲本次TCP通信的字節流的初始序號。
    TCP規定:SYN=1的報文段不能有數據部分,但要消耗掉一個序號。

第二次握手
服務端收到連接請求報文段後,如果同意連接,則會發送一個應答:SYN=1,ACK=1,seq=y,ack=x+1。
該應答發送完成後便進入SYN-RCVD狀態。

  • PS1:SYN=1,ACK=1表示該報文段爲連接同意的應答報文。
  • PS2:seq=y表示服務端作爲發送者時,發送字節流的初始序號。
  • PS3:ack=x+1表示服務端希望下一個數據報發送序號從x+1開始的字節。

第三次握手
當客戶端收到連接同意的應答後,還要向服務端發送一個確認報文段,表示:服務端發來的連接同意應答已經成功收到。
該報文段的頭部爲:ACK=1,seq=x+1,ack=y+1。
客戶端發完這個報文段後便進入ESTABLISHED狀態,服務端收到這個應答後也進入ESTABLISHED狀態,此時連接的建立完成! 


在客戶端與服務器端傳輸的TCP報文中,雙方的確認號Ack和序號Seq的值,都是在彼此Ack和Seq值的基礎上進行計算的,這樣做保證了TCP報文傳輸的連貫性。一旦出現某一方發出的TCP報文丟失,便無法繼續"握手",以此確保了"三次握手"的順利完成。

例如:

一句話概括,TCP連接握手握的是啥?  
通信雙方數據原點的序列號!

1.2 TCP連接狀態

CLOSED:沒有任何連接狀態;

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

  首先服務端需要打開一個socket進行監聽,狀態爲LISTEN。

  有提供某種服務纔會處於LISTENING狀態,TCP狀態變化就是某個端口的狀態變化,提供一個服務就打開一個端口,例如:提供www服務默認開的是80端口,提供ftp服務默認的端口爲21,當提供的服務沒有被連接時就處於LISTENING狀態。FTP服務啓動後首先處於偵聽(LISTENING)狀態。處於偵聽LISTENING狀態時,該端口是開放的,等待連接,但還沒有被連接。就像你房子的門已經敞開的,但還沒有人進來。

   看LISTENING狀態最主要的是看本機開了哪些端口,這些端口都是哪個程序開的,關閉不必要的端口是保證安全的一個非常重要的方面,服務端口都對應一個服務(應用程序),停止該服務就關閉了該端口,例如要關閉21端口只要停止IIS服務中的FTP服務即可。關於這方面的知識請參閱其它文章。

   如果你不幸中了服務端口的木馬,木馬也開個端口處於LISTENING狀態。

SYN-SENT:客戶端SYN_SENT狀態:

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

  當請求連接時客戶端首先要發送同步信號給要訪問的機器,此時狀態爲SYN_SENT,如果連接成功了就變爲ESTABLISHED,正常情況下SYN_SENT狀態非常短暫。例如要訪問網站http://www.baidu.com,如果是正常連接的話,用TCPView觀察IE建立的連接會發現很快從SYN_SENT變爲ESTABLISHED,表示連接成功。SYN_SENT狀態快的也許看不到。

  如果發現有很多SYN_SENT出現,那一般有這麼幾種情況,一是你要訪問的網站不存在或線路不好,二是用掃描軟件掃描一個網段的機器,也會出出現很多SYN_SENT,另外就是可能中了病毒了,例如中了"衝擊波",病毒發作時會掃描其它機器,這樣會有很多SYN_SENT出現。

SYN-RECEIVED:服務器端狀態SYN_RCVD

        再收到和發送一個連接請求後等待對方對連接請求的確認

  當服務器收到客戶端發送的同步信號時,將標誌位ACK和SYN置1發送給客戶端,此時服務器端處於SYN_RCVD狀態,如果連接成功了就變爲ESTABLISHED,正常情況下SYN_RCVD狀態非常短暫。

  如果發現有很多SYN_RCVD狀態,那你的機器有可能被SYN Flood的DoS(拒絕服務攻擊)攻擊了。

 

ESTABLISHED:代表一個打開的連接。

 ESTABLISHED狀態是表示兩臺機器正在傳輸數據,觀察這個狀態最主要的就是看哪個程序正在處於ESTABLISHED狀態。

 服務器出現很多ESTABLISHED狀態: netstat -nat |grep 9502或者使用lsof  -i:9502可以檢測到。

 當客戶端未主動close的時候就斷開連接:即客戶端發送的FIN丟失或未發送。

 這時候若客戶端斷開的時候發送了FIN包,則服務端將會處於CLOSE_WAIT狀態;

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

 結果客戶端重新連接服務器。

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

 最終結果就是新的其他客戶端無法連接上來,但是利用netstat還是能看到一條連接已經建立,並顯示ESTABLISHED,但始終無法進入程序代碼

FIN-WAIT-1:等待遠程TCP連接中斷請求,或先前的連接中斷請求的確認

  主動關閉(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。

FIN-WAIT-2:從遠程TCP等待連接中斷請求

  主動關閉端接到ACK後,就進入了FIN-WAIT-2,從遠程TCP等待連接中斷請求

  這就是著名的半關閉的狀態了,這是在關閉連接時,客戶端和服務器兩次握手之後的狀態。在這個狀態下,應用程序還有接受數據的能力,但是已經無法發送數據,但是也有一種可能是,客戶端一直處於FIN_WAIT_2狀態,而服務器則一直處於WAIT_CLOSE狀態,而直到應用層來決定關閉這個狀態。

CLOSE-WAIT:等待從本地用戶發來的連接中斷請求

  被動關閉(passive close)端TCP接到FIN後,就發出ACK以迴應FIN請求(它的接收也作爲文件結束符傳遞給上層應用程序),並進入CLOSE_WAIT.等待從本地用戶發來的連接中斷請求

     

CLOSING:等待遠程TCP對連接中斷的確認

等待遠程TCP對連接中斷的確認

LAST-ACK:等待原來的發向遠程TCP的連接中斷請求的確認

被動關閉端一段時間後,接收到文件結束符的應用程序將調用CLOSE關閉連接。這導致它的TCP也發送一個 FIN,等待對方的ACK.就進入了LAST-ACK 等待原來發向遠程TCP的連接中斷請求的確認

使用併發壓力測試的時候,突然斷開壓力測試客戶端,服務器會看到很多LAST-ACK。

TIME-WAIT:等待足夠的時間以確保遠程TCP接收到連接中斷請求的確認

在主動關閉端接收到FIN後,TCP就發送ACK包,並進入TIME-WAIT狀態,等待足夠的時間以確保遠程TCP接收到連接中斷請求的確認 */

      TIME_WAIT等待狀態,這個狀態又叫做2MSL狀態,說的是在TIME_WAIT2發送了最後一個ACK數據報以後,要進入TIME_WAIT狀態,這個狀態是防止最後一次握手的數據報沒有傳送到對方那裏而準備的(注意這不是四次握手,這是第四次握手的保險狀態)。這個狀態在很大程度上保證了雙方都可以正常結束,但是,問題也來了。由於插口的2MSL狀態(插口是IP和端口對的意思,socket),使得應用程序在2MSL時間內是無法再次使用同一個插口的,對於客戶程序還好一些,但是對於服務程序,例如httpd,它總是要使用同一個端口來進行服務,而在2MSL時間內,啓動httpd就會出現錯誤(插口被使用)。爲了避免這個錯誤,服務器給出了一個平靜時間的概念,這是說在2MSL時間內,雖然可以重新啓動服務器,但是這個服務器還是要平靜的等待2MSL時間的過去才能進行下一次連接。

1.3 TCP狀態遷移路線分析

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

 

這是一個看起來比較複雜的狀態遷移圖,因爲它包含了兩個部分—-服務器的狀態遷移和客戶端的狀態遷移,如果從某一個角度出發來看這個圖,就會清晰許多,這裏面的服務器和客戶端都不是絕對的,發送數據的就是客戶端,接受數據的就是服務器。

客戶端應用程序的狀態遷移圖

客戶端的狀態可以用如下的流程來表示:

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包才能進入初始的狀態。

其他狀態遷移

還有一些其他的狀態遷移,這些狀態遷移針對服務器和客戶端兩方面的總結如下

LISTEN->SYNSENT,對於這個解釋就很簡單了,服務器有時候也要打開連接的嘛。

SYN_SENT->SYN收到,服務器和客戶端在SYN_SENT狀態下如果收到SYN數據報,則都需要發送SYN的ACK數據報並把自己的狀態調整到SYN收到狀態,準備進入ESTABLISHED

SYN_SENT->CLOSED,在發送超時的情況下,會返回到CLOSED狀態。

SYN收到->LISTEN,如果受到RST包,會返回到LISTEN狀態。

SYN_收到->FIN_WAIT_1,這個遷移是說,可以不用到ESTABLISHED狀態,而可以直接跳轉到FIN_WAIT_1狀態並等待關閉。

 

1.4 查看TCP狀態命令

瞭解TCP狀態之後瞭解幾個linux查看tcp的狀態命令:

1) netstat -nat查看TCP各個狀態的數量

2)lsof -i:port可以檢測到打開套接字的狀況

3) sar -n SOCK查看tcp創建的連接數

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

網絡測試常用命令;

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

但是很多服務器爲了防止攻擊,一般會關閉對ping的響應。所以ping一般作爲測試連通性使用。

ping命令後,會接收到對方發送的回饋信息,其中記錄着對方的IP地址和TTL。TTL是該字段指定IP包被路由器丟棄之前允許通過的最大網段數量。

TTL是IPv4包頭的一個8 bit字段。例如IP包在服務器中發送前設置的TTL是64,你使用ping命令後,得到服務器反饋的信息,其中的TTL爲56,說明途中一共經過了8道路由器的轉發,每經過一個路由,TTL減1。

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

traceroute hostname

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

pathping www.baidu.com

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

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

2. 二次握手和四次握手

 

根據三次握手的核心思想我們來分析二、四次握手的過程。  

2.1 四次握手的過程:  


1.發送同步信號SYN+A的初始序列號 
2.B確認收到A的同步信號,並記錄A‘s是到本地,命名B的ACK序列號
3.B發送同步信號SYN+B的初始序列號
4.A確認收到B的同步信號,並記錄B‘s是到本地,命名A的ACK序列號



很顯然2和3這兩個步驟可以合併,只需要三次握手,可以提高連接的速度與效率。

2.2二次握手的過程:


1.A發送同步信號SYN+A的初始序列號
2.B發送同步信號SYN+B的初始序列號+B的ACK序號

這裏有一個問題,A與B就A的初始序列號達成了一致.但是B無法知道A是否已經接收到自己的同步信號,如果這個同步信號丟失了, A和B就B的初始序列號將無法達成一致。

如圖:


於是tcp的設計者將SYN這個同步標誌位SYN設計成佔用一個字節的編號(FIN標誌位也是),既然是一個字節的數據,按照tcp對有數據的tcp段必須確認的原則,所以在這裏A必須給B一個確認,以確認A已經接收到B的同步信號。

有童鞋會說,如果A發給B的確認丟了,該如何?會超時重傳這個ack嗎?不會!Tcp不會爲沒有數據的ack超時重傳.
那該如何是好?B如果沒有收到A的ack,超時重傳自己的syn同步號,直到收到A的ack爲止。

3.關於三次握手的連環發問

1. 三次握手的第一個包,即A發給B的SYN中途被丟,沒有到達B會怎麼樣?
A會週期性超時重傳,直到收到B的確認

2.三次握手的第二個包,即B發給A的SYN+ACK中途被丟,沒有到達A會怎麼樣? 
B會週期性超時重傳,直到收到A的確認 

3.三次握手的第三個包,即A發給B的ACK中途被丟,沒有到達B會怎麼樣?

A發完ACK,單方面認爲TCP爲Established狀態,而B顯然認爲TCP爲Active狀態:
a.假定此時雙方都沒有數據發送,B會週期性超時重傳,直到收到A的確認,收到之後B的TCP連接也爲Established狀態,雙向可以發包。
b.假定此時A有數據發送,B收到A的Data + ACK,自然會切換爲established 狀態,並接受A的數據。
c.假定B有數據發送,數據發送不了,會一直週期性超時重傳SYN+ACK,直到收到A的確認纔可以發送數據.


4.爲什麼連接建立需要三次握手,而不是兩次握手?
防止失效的連接請求報文段被服務端接收,從而產生錯誤。

PS:失效的連接請求:若客戶端向服務端發送的連接請求丟失,客戶端等待應答超時後就會再次發送連接請求,此時,上一個連接請求就是『失效的』。

若建立連接只需兩次握手,客戶端並沒有太大的變化,仍然需要獲得服務端的應答後才進入ESTABLISHED狀態,而服務端在收到連接請求後就進入ESTABLISHED狀態。此時如果網絡擁塞,客戶端發送的連接請求遲遲到不了服務端,客戶端便超時重發請求,如果服務端正確接收並確認應答,雙方便開始通信,通信結束後釋放連接。此時,如果那個失效的連接請求抵達了服務端,由於只有兩次握手,服務端收到請求就會進入ESTABLISHED狀態,等待發送數據或主動發送數據。但此時的客戶端早已進入CLOSED狀態,服務端將會一直等待下去,這樣浪費服務端連接資源。 

5.如果已經建立了連接,但是客戶端突然出現故障了怎麼辦?(網絡CLOSE)

TCP還設有一個保活計時器,顯然,客戶端如果出現故障,服務器不能一直等下去,白白浪費資源。服務器每收到一次客戶端的請求後都會重新復位這個計時器,時間通常是設置爲2小時,若兩小時還沒有收到客戶端的任何數據,服務器就會發送一個探測報文段,以後每隔75秒鐘發送一次。若一連發送10個探測報文仍然沒反應,服務器就認爲客戶端出了故障,接着就關閉連接。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章