1. 程式人生 > >TCP建立連線三次握手和釋放連線四次握手

TCP建立連線三次握手和釋放連線四次握手

TCP的報文結構如下下所示:

序列號seq:佔4個位元組,用來標記資料段的順序,TCP把連線中傳送的所有資料位元組都編上一個序號,第一個位元組的編號由本地隨機產生;給位元組編上序號後,就給每一個報文段指派一個序號;序列號seq就是這個報文段中的第一個位元組的資料編號。
    確認號ack:佔4個位元組,期待收到對方下一個報文段的第一個資料位元組的序號;序列號表示報文段攜帶資料的第一個位元組的編號;而確認號指的是期望接收到下一個位元組的編號;因此當前報文段最後一個位元組的編號+1即為確認號。
確認ACK:佔1位,僅當ACK=1時,確認號欄位才有效。ACK=0時,確認號無效
同步SYN:連線建立時用於同步序號。當SYN=1,ACK=0時表示:這是一個連線請求報文段。若同意連線,則在響應報文段中使得SYN=1,ACK=1。因此,SYN=1表示這是一個連線請求,或連線接受報文。
SYN這個標誌位只有在TCP建產連線時才會被置1,握手完成後SYN標誌位被置0。
終止FIN:用來釋放一個連線。FIN=1表示:此報文段的傳送方的資料已經發送完畢,並要求釋放運輸連線
 PS:ACK、SYN和FIN這些大寫的單詞表示標誌位,其值要麼是1,要麼是0;ack、seq小寫的單詞表示序號。一、TCP建立連線三次握手(1)、三次握手的過程   1)主機A向主機B傳送TCP連線請求資料包,其中包含主機A的初始序列號seq(A)=x。(其中報文中同步標誌位SYN=1,ACK=0,表示這是一個TCP連線請求資料報文;序號seq=x,表明傳輸資料時的第一個資料位元組的序號是x),此時A主機進入SYN_SENT狀態,等待伺服器確認

2)主機B收到請求後,會發回連線確認資料包。(其中確認報文段中,標識位SYN=1,ACK=1,表示這是一個TCP連線響應資料報文,並含主機B的初始序列號seq(B)=y,以及主機B對主機A初始序列號的確認號ack(B)=seq(A)+1=x+1) 此時伺服器進入SYN_RECV狀態[在收到客戶端SYN報文之前均為LISTEN狀態]
3)第三次,主機A收到主機B的確認報文後,便進入
ESTABLISHED狀態,此時需要對B狀態作出確認,即傳送一個序列號seq(A)=x+1;確認號為ack(A)=y+1的報文;此時B伺服器也進入ESTABLISHED狀態,雙方便可以傳送訊息2)為什麼需要第三次握手?

 為什麼不能一次握手很容易理解,TCP是面向連線的,一次握手肯定建立不了連線,一條資訊發出去連個回信都沒有怎麼連線?所以問題在為什麼不能兩次握手。假設只有兩次握手,當A想要建立連線時傳送一個SYN,然後等待ACK,結果這個SYN因為網路問題沒有及時到達B,所以A在一段時間內沒收到ACK後,在傳送一個SYN,B也成功收到,然後A也收到ACK,這時A傳送的第一個SYN終於到了B,對於B來說這是一個新連線請求,然後B又為這個連線申請資源,返回ACK,然而這個SYN是個無效的請求,A收到這個SYN的ACK後也並不會理會它,而B卻不知道,B會一直為這個連線維持著資源,造成資源的浪費

    那三次握手為什麼可以?兩次握手的問題在於伺服器端不知道一個SYN是否是無效的,而三次握手機制因為客戶端會給伺服器回覆第二次握手,也意味著伺服器會等待客戶端的第三次握手,如果第三次握手遲遲不來,伺服器便會認為這個SYN是無效的,釋放相關資源。但這時有個問題就是客戶端完成第二次握手便認為連線已建立,而第三次握手可能在傳輸中丟失,服務端會認為連線是無效的,這時如果Client端向Server寫資料,Server端將以RST包響應,方能感知到Server的錯誤。

   總的來說,三次握手可以保證任何一次握手出現問題,都是可以被發現或補救的

     第一次握手A傳送SYN傳輸失敗,A,B都不會申請資源,連線失敗。如果一段時間內發出多個SYN連線請求,那麼A只會接受它最後傳送的那個SYN的SYN+ACK迴應,忽略其他迴應全部迴應,B中多申請的資源也會釋放

     第二次握手B傳送SYN+ACK傳輸失敗,A不會申請資源,B申請了資源,但收不到A的ACK,過一段時間釋放資源。如果是收到了多個A的SYN請求,B都會回覆SYN+ACK,但A只會承認其中它最早傳送的那個SYN的迴應,並回復最後一次握手的ACK

     第三次握手ACK傳輸失敗,B沒有收到ACK,釋放資源,對於後序的A的傳輸資料返回RST。實際上B會因為沒有收到A的ACK會多次傳送SYN+ACK,次數是可以設定的,如果最後還是沒有收到A的ACK,則釋放資源,對A的資料傳輸返回RST

二、TCP釋放連線四次握手(1)四次握手過程  假設主機A為客戶端,主機B為伺服器,其釋放TCP連線的過程如下:    1) 關閉客戶端到伺服器的連線:首先客戶端A傳送一個FIN,用來關閉客戶到伺服器的資料傳送,然後等待伺服器的確認。其中終止標誌位FIN=1,序列號seq=u   2) 伺服器收到這個FIN,它發回一個ACK,確認號ack為收到的序號加1。
   3) 關閉伺服器到客戶端的連線:也是傳送一個FIN給客戶端。
   4) 客戶段收到FIN後,併發回一個ACK報文確認,並將確認序號seq設定為收到序號加1。
     首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。
主機A傳送FIN後,進入終止等待狀態, 伺服器B收到主機A連線釋放報文段後,就立即給主機A傳送確認,然後伺服器B就進入close-wait狀態,此時TCP伺服器程序就通知高層應用程序,因而從A到B的連線就釋放了。此時是“半關閉”狀態。即A不可以傳送給B,但是B可以傳送給A。
  此時,若B沒有資料報要傳送給A了,其應用程序就通知TCP釋放連線,然後傳送給A連線釋放報文段,並等待確認。A傳送確認後,進入time-wait,注意,此時TCP連線還沒有釋放掉,然後經過時間等待計時器設定的2MSL後,A才進入到close狀態。
(2)為什麼要等待2MSL呢?
    MSL即Maximum Segment Lifetime,也就是最大
報文生存時間,他是任何報文在網路上存在的最長時間,超過這個時間報文將被丟棄。引用《TCP/IP詳解》中的話:“它(MSL)是任何報文段被丟棄前在網路內的最長時間”。RFC 793中規定MSL為2分鐘,實際應用中常用的是30秒,1分鐘和2分鐘等。
    TCP的TIME_WAIT狀態需要等待2MSL,當TCP的一端發起主動關閉,在發出最後一個ACK包後,即第3次握手完成後傳送了第四次握手的ACK包後就進入了TIME_WAIT狀態,必須在此狀態上停留兩倍的MSL時間,等待2MSL時間主要目的是怕最後一個ACK包對方沒收到,那麼對方在超時後將重發第三次握手的FIN包,主動關閉端接到重發的FIN包後可以再發一個ACK應答包。在TIME_WAIT狀態時兩端的埠不能使用,要等到2MSL時間結束才可繼續使用。當連線處於2MSL等待階段時任何遲到的報文段都將被丟棄。不過在實際應用中可以通過設定SO_REUSEADDR選項達到不必等待2MSL時間結束再使用此埠。    概括原因如下:    ①、為了保證A傳送的最後一個ACK報文段能夠到達B。即最後這個確認報文段很有可能丟失,那麼B會超時重傳,然後A再一次確認,同時啟動2MSL計時器,如此下去。如果沒有等待時間,傳送完確認報文段就立即釋放連線的話,B就無法重傳了(連線已被釋放,任何資料都不能出傳了),因而也就收不到確認,就無法按照步驟進入CLOSE狀態,即必須收到確認才能close。
    ②、防止“已失效的連線請求報文段”出現在連線中。經過2MSL,那些在這個連線持續的時間內,產生的所有報文段就可以都從網路中消失。即在這個連線釋放的過程中會有一些無效的報文段滯留在樓閣結點,但是呢,經過2MSL這些無效報文段就肯定可以傳送到目的地,不會滯留在網路中。這樣的話,在下一個連線中就不會出現上一個連線遺留下來的請求報文段了。
可以看出:B結束TCP連線的時間比A早一點,因為B收到確認就斷開連線了,而A還得等待2MSL.
(3)為什麼TCP釋放連線需要四次?      TCP建立連線要進行三次握手,而斷開連線要進行四次。這是由於TCP的半關閉造成的。因為TCP連線是全雙工的(即資料可在兩個方向上同時傳遞)所以進行關閉時每個方向上都要單獨進行關閉。這個單方向的關閉就叫半關閉。當一方完成它的資料傳送任務,就傳送一個FIN來向另一方通告將要終止這個方向的連線。     注意:     1)傳送了FIN只是表示這端不能繼續傳送資料(應用層不能再呼叫send傳送),但是還可以接收資料。收到一個 FIN只意味著這一方向上沒有資料流動,一個TCP連線在收到一個FIN後仍能傳送資料,比如:如主機A收到主機B的FIN斷開TCP連線請求,只是表示主機B已經發送完資料,主機A收到FIN後作出應答,並終止這個方向的資料傳輸,此時處於半關閉狀態。但是主機A仍然可以傳送資料的,只有當主機A傳送完資料併發送FIN給主機B時,主機B才停止這個方向的資料傳輸,並關閉TCP連線。     2)在很多時候,TCP連線的斷開都會由TCP層自動進行,例如你CTRL+C終止你的程式,TCP連線依然會正常關閉,你可以寫程式碼試試。