TCP之三次握手四次揮手

原文地址緩存

TCP報文格式

TCP提供一種面向鏈接的,可靠的字節流服務。服務器

TCP首部的數據格式以下。(若是不計任選字段,一般是20個字節)網絡

報文頭.png

字段分析

  • 源端口:源端口和IP地址的做用是標識報文的返回地址。
  • 目的端口:端口指明接收方計算機上的應用程序接口。

TCP報頭中的源端口號和目的端口號同IP數據報中的源IP與目的IP惟一肯定一條TCP鏈接。spa

  • 序號:是TCP可靠傳輸的關鍵部分。序號是該報文段發送的數據組的第一個字節的序號。在TCP傳送的流中,每個字節都有一個序號。好比一個報文段的序號爲300,報文段數據部分共有100字節,則下一個報文段的序號爲400。因此序號確保了TCP傳輸的有序性。
  • 確認號:即ACK,指明下一個期待收到的字節序號,代表該序號以前的全部數據已經正確無誤的收到。確認號只有當ACK標誌爲1時纔有效。好比創建鏈接時,SYN報文的ACK標誌位爲0。
  • 首部長度/數據偏移:佔4位,它指出TCP報文的數據距離TCP報文段的起始處有多遠。因爲首部可能含有可選項內容,所以TCP報頭的長度是不肯定的,報頭不包含任何任選字段則長度爲20字節,4位首部長度字段所能表示的最大值爲1111,轉化爲10進製爲15,15*32/8=60,故報頭最大長度爲60字節。首部長度也叫數據偏移,是由於首部長度實際上指示了數據區在報文段中的起始偏移值。
  • 保留:佔6位,保留從此使用,但目前應都位0。

控制位:URG ACK PSH RST SYN FIN,共6個,每個標誌位表示一個控制功能。指針

  • 緊急URG:當URG=1,代表緊急指針字段有效。告訴系統此報文段中有緊急數據
  • 確認ACK:僅當ACK=1時,確認號字段纔有效。TCP規定,在鏈接創建後全部報文的傳輸都必須把ACK置1。
  • 推送PSH:當兩個應用進程進行交互式通訊時,有時在一端的應用進程但願在鍵入一個命令後當即就能收到對方的響應,這時候就將PSH=1。
  • 復位RST:當RST=1,代表TCP鏈接中出現嚴重差錯,必須釋放鏈接,而後再從新創建鏈接。
  • 同步SYN:在鏈接創建時用來同步序號。當SYN=1,ACK=0,代表是鏈接請求報文,若贊成鏈接,則響應報文中應該使SYN=1,ACK=1。
  • 終止FIN:用來釋放鏈接。當FIN=1,代表此報文的發送方的數據已經發送完畢,而且要求釋放。
  • 窗口:滑動窗口大小,用來告知發送端接受端的緩存大小,以此控制發送端發送數據的速率,從而達到流量控制。窗口大小時一個16bit字段,於是窗口大小最大爲65535。
  • 校驗和:奇偶校驗,此校驗和是對整個的 TCP 報文段,包括 TCP 頭部和 TCP 數據,以 16 位字進行計算所得。由發送端計算和存儲,並由接收端進行驗證。
  • 緊急指針:只有當 URG 標誌置 1 時緊急指針纔有效。緊急指針是一個正的偏移量,和順序號字段中的值相加表示緊急數據最後一個字節的序號。 TCP 的緊急方式是發送端向另外一端發送緊急數據的一種方式。
  • 選項和填充:最多見的可選字段是最長報文大小,又稱爲MSS(Maximum Segment Size),每一個鏈接方一般都在通訊的第一個報文段(爲創建鏈接而設置SYN標誌爲1的那個段)中指明這個選項,它表示本端所能接受的最大報文段的長度。選項長度不必定是32位的整數倍,因此要加填充位,即在這個字段中加入額外的零,以保證TCP頭是32的整數倍。
  • 數據部分: TCP 報文段中的數據部分是可選的。在一個鏈接創建和一個鏈接終止時,雙方交換的報文段僅有 TCP 首部。若是一方沒有數據要發送,也使用沒有任何數據的首部來確認收到的數據。在處理超時的許多狀況中,也會發送不帶任何數據的報文段。

三次握手

第一次握手:客戶端發送syn包(syn=x)到服務器,並進入SYN_SEND狀態,等待服務器確認;code

第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=x+1),同時本身也發送一個SYN包(syn=y),即SYN+ACK包,此時服務器進入SYN_RECV狀態;server

第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=y+1),此包發送完畢,客戶端和服務器進入ESTABLISHED狀態,完成三次握手。blog

握手過程當中傳送的包裏不包含數據,三次握手完畢後,客戶端與服務器才正式開始傳送數據。理想狀態下,TCP鏈接一旦創建,在通訊雙方中的任何一方主動關閉鏈接以前,TCP 鏈接都將被一直保持下去。接口

連接.png

爲何會採用三次握手,若採用二次握手能夠嗎? 四次呢?

創建鏈接的過程是利用客戶服務器模式,假設主機A爲客戶端,主機B爲服務器端。進程

採用三次握手是爲了防止失效的鏈接請求報文段忽然又傳送到主機B,於是產生錯誤。失效的鏈接請求報文段是指:主機A發出的鏈接請求沒有收到主機B的確認,因而通過一段時間後,主機A又從新向主機B發送鏈接請求,且創建成功,順序完成數據傳輸。考慮這樣一種特殊狀況,主機A第一次發送的鏈接請求並無丟失,而是由於網絡節點致使延遲達到主機B,主機B覺得是主機A又發起的新鏈接,因而主機B贊成鏈接,並向主機A發回確認,可是此時主機A根本不會理會,主機B就一直在等待主機A發送數據,致使主機B的資源浪費。

採用兩次握手不行,緣由就是上面說的失效的鏈接請求的特殊狀況。而在三次握手中, client和server都有一個發syn和收ack的過程, 雙方都是發後能收, 代表通訊則準備工做OK.

爲何不是四次握手呢? 你們應該知道通訊中著名的藍軍紅軍約定, 這個例子說明, 通訊不可能100%可靠, 而上面的三次握手已經作好了通訊的準備工做, 再增長握手, 並不能顯著提升可靠性, 並且也沒有必要。

四次揮手

數據傳輸完畢後,雙方均可釋放鏈接。最開始的時候,客戶端和服務器都是處於ESTABLISHED狀態,假設客戶端主動關閉,服務器被動關閉。

釋放.png

第一次揮手:客戶端發送一個FIN,用來關閉客戶端到服務器的數據傳送,也就是客戶端告訴服務器:我已經不 會再給你發數據了(固然,在fin包以前發送出去的數據,若是沒有收到對應的ack確認報文,客戶端依然會重發這些數據),可是,此時客戶端還可 以接受數據。
FIN=1,其序列號爲seq=u(等於前面已經傳送過來的數據的最後一個字節的序號加1),此時,客戶端進入FIN-WAIT-1(終止等待1)狀態。 TCP規定,FIN報文段即便不攜帶數據,也要消耗一個序號。

第二次揮手:服務器收到FIN包後,發送一個ACK給對方而且帶上本身的序列號seq,確認序號爲收到序號+1(與SYN相同,一個FIN佔用一個序號)。此時,服務端就進入了CLOSE-WAIT(關閉等待)狀態。TCP服務器通知高層的應用進程,客戶端向服務器的方向就釋放了,這時候處於半關閉狀態,即客戶端已經沒有數據要發送了,可是服務器若發送數據,客戶端依然要接受。這個狀態還要持續一段時間,也就是整個CLOSE-WAIT狀態持續的時間。

此時,客戶端就進入FIN-WAIT-2(終止等待2)狀態,等待服務器發送鏈接釋放報文(在這以前還須要接受服務器發送的最後的數據)。

第三次揮手:服務器發送一個FIN,用來關閉服務器到客戶端的數據傳送,也就是告訴客戶端,個人數據也發送完了,不會再給你發數據了。因爲在半關閉狀態,服務器極可能又發送了一些數據,假定此時的序列號爲seq=w,此時,服務器就進入了LAST-ACK(最後確認)狀態,等待客戶端的確認。

第四次揮手:主動關閉方收到FIN後,發送一個ACK給被動關閉方,確認序號爲收到序號+1,此時,客戶端就進入了TIME-WAIT(時間等待)狀態。注意此時TCP鏈接尚未釋放,必須通過2∗MSL(最長報文段壽命)的時間後,當客戶端撤銷相應的TCB後,才進入CLOSED狀態。

服務器只要收到了客戶端發出的確認,當即進入CLOSED狀態。一樣,撤銷TCB後,就結束了此次的TCP鏈接。能夠看到,服務器結束TCP鏈接的時間要比客戶端早一些。

至此,完成四次揮手。

爲何客戶端最後還要等待2MSL?

MSL(Maximum Segment Lifetime),TCP容許不一樣的實現能夠設置不一樣的MSL值。

第一,保證客戶端發送的最後一個ACK報文可以到達服務器,由於這個ACK報文可能丟失,站在服務器的角度看來,我已經發送了FIN+ACK報文請求斷開了,客戶端尚未給我回應,應該是我發送的請求斷開報文它沒有收到,因而服務器又會從新發送一次,而客戶端就能在這個2MSL時間段內收到這個重傳的報文,接着給出迴應報文,而且會重啓2MSL計時器。

第二,防止相似與「三次握手」中提到了的「已經失效的鏈接請求報文段」出如今本鏈接中。客戶端發送完最後一個確認報文後,在這個2MSL時間中,就可使本鏈接持續的時間內所產生的全部報文段都從網絡中消失。這樣新的鏈接中不會出現舊鏈接的請求報文。

爲何創建鏈接是三次握手,關閉鏈接確是四次揮手呢?

創建鏈接的時候, 服務器在LISTEN狀態下,收到創建鏈接請求的SYN報文後,把ACK和SYN放在一個報文裏發送給客戶端。 而關閉鏈接時,服務器收到對方的FIN報文時,僅僅表示對方再也不發送數據了可是還能接收數據,而本身也未必所有數據都發送給對方了,因此己方能夠當即關閉,也能夠發送一些數據給對方後,再發送FIN報文給對方來表示贊成如今關閉鏈接,所以,己方ACK和FIN通常都會分開發送,從而致使多了一次。

相關文章
相關標籤/搜索