linux網路程式設計系列(四)--tcp包頭、三次握手、四次揮手、狀態

piny發表於2021-09-09

1. TCP協議

1.1 TCP資料包頭

要了解三次握手和四次揮手,首先需要了解下TCP資料包頭的結構,如下:
圖片描述

  • 源埠、目的埠:16位長,標識出遠端和本地的埠號;
  • 序號:SEQ,32位長,標識傳送的資料包的順序,防止資料包亂序;
  • 確認號:32位長,接收方對傳送方傳送來的TCP報文段的響應,其值是對收到的報文序號加1,用於解決不丟包的問題;
  • TCP頭長:4位頭長,標識tcp頭部可以有多少個32bit,即多少個4位元組,因為頭長是4位,最大能表示15,所以TCP頭部最大就是15*4等於60個位元組,也就是說TCP包頭最長可以有60個位元組;
  • URG:表示緊急指標是否有效;
  • ACK:ACK位置1表明確認號是合法的,如果ACK為0,那麼資料包不包含確認資訊,確認欄位被省略;
  • PSH:提示接收端應用程式應該立即從TCP接收緩衝區中讀走資料,為接收後續資料騰出空間;
  • RST:表示要求對方重新建立連線,用於復位由於主機崩潰或其他原因而出現的錯誤的連線,還可以用於拒絕非法的資料包或拒絕連線請求;
  • SYN:表示請求建立連線;
  • FIN:表示通知對方要關閉連線了;
  • 視窗大小:16位長,是一種流量控制的手段,這個視窗,指的是接收通告視窗,它告訴對端本端的TCP緩衝區還能容納多少位元組的資料,這樣對方就可以控制傳送資料的速度;
  • 校驗和:16位長,由傳送端填充,接收端根據該值,校驗接收到的TCP報文段在傳輸過程中是否損壞,校驗包括頭部和資料部分,它是TCP可靠傳輸的一個重要保障;
  • 緊急指標:16位長,是一個正的偏移量,它和序號相加表示最後一個緊急資料的下一個位元組的序號,確切的說,它是緊急指標相對當前序號的偏移,是傳送端向接收端傳送緊急資料的辦法;
  • 可選項:TCP頭部最長可以有60個位元組,而前部分已知的欄位佔用了20個位元組,所以選項最多可以有40個位元組,包括最大TCP載荷,視窗比例、選擇重複資料包等選項;

注意:TCP資料包是沒有IP地址的,只有埠

1.2 三次握手協議

在利用TCP實現源主機和目的主機通訊時,目的主機必須同意,否則TCP連線無法建立。為了確保TCP連線的成功建立,TCP採用了一種稱為三次握手的方式,三次握手方式使得“序號/確認號”系統能夠正常工作,從而使它們的序號達成同步。如果三次握手成功,則連線建立成功,可以開始傳送資料資訊。
三次握手:為應用程式提供可靠的通訊連線,適合於一次傳輸大批資料的情況,並適用於要求得到響應的應用程式。
其三次握手分別為:

  • 源主機A的TCP向主機B傳送連線請求報文段,其首部中的SYN(同步)標誌位應置為1,表示想跟目標主機B建立連線,進行通訊,併傳送一個同步序列號X(例:SEQ=100)進行同步,表明在後面傳送資料時的第一個資料位元組的序號為X+1(即101), 此時client端狀態為SYN_SENT。
  • 目標主機B的TCP收到連線請求報文段後,如同意,則發回確認。再確認報中應將ACK位置為1.確認號為X+1,同時又向A也傳送一個SYN=1,併傳送一個序號Y, 此時server端狀態為SYN_RCVD。
  • 源主機A的TCP收到目標主機B的確認後要想目標主機B給出確認。其ACK置為1,確認號為Y+1,而自己的序號為X+1。TCP的標準規定,SYN置1的報文段要消耗掉一個序號, 當兩邊都確認完成後,狀態改為ESTABLISHED。

執行客戶程式的源主機A的TCP通知上層應用程式,連線已經建立。
當源主機A向目標主機B傳送第一個資料包文段時,其序號仍為X+1,因為前一個確認報文段並不消耗序號。
當執行服務程式的目標主機B的TCP收到源主機A的確認後,也通知其上層應用程式,連線已經建立。至此建立了一個全雙工的連線。

1.3 tcp斷開連線四次揮手

tcp建立連線是三次,但斷開連線卻要四次,是因為tcp是全雙工的,兩個方向上都需要進行關閉。

  • 當主機A完成資料傳輸後,將控制位FIN置1,向主機B提出停止TCP連線的請求,狀態改為FIN_WAIT_1,此時,該資料包中,序列號為主機B傳送的上一個資料包中的確認號值,而確認號為主機A傳送的上一個資料包中的序列號+該資料包所帶的資料的大小;
  • 主機B收到FIN後對其作出響應,確認這一方向上的TCP連線將關閉,將ACK置1,此時伺服器狀態改為CLOSE_WAIT, 客戶端狀態改為FIN_WAIT_1,此時序列號為上一步中的確認號,確認號為上一步中的序列號加1;
  • 由B 端再提出反方向的關閉請求,將FIN置1,服務端狀態為LAST_ACK,客戶端狀態為TIME_WAIT,此時序列號為上一步的確認號,確認號為上一步的序列號加上資料包所帶資料的大小;
  • 主機A對主機B的請求進行確認,將ACK置1,雙方向的關閉結束狀態為CLOSED,此時序列號為上一步中的確認號,確認號為上一步中的序列號加1;

注意 : FIN和SYN一樣,也要消耗一個序號。理論上伺服器在TCP連線關閉時傳送的終止資料包中,只有終止位置是1,然後客戶端進行確認。但是在實際的 TCP實現中,在終止資料包中,確認位和終止位是同時置為1的,確認位置為1表示對最後一次傳輸的資料進行確認,終止位置為1表示關閉該方向的TCP連 接。

1.4 TCP有哪些狀態

一般我們可以使用netstat檢視當前socket狀態。

  • CLOSED:表示初始狀態;
  • LISTEN:表示伺服器端的某個socket處於監聽狀態,可以接受連線;
  • SYN_SENT:三次握手時,客戶端傳送第一次SYN連線請求後,狀態SYN_SENT;
  • SYN_RCVD:也是三次握手時服務端的一箇中間狀態;
  • ESTABLISHED:表示連線已經建立,這裡要說明一下,其實TCP連線並不是真的有什麼東西連著在,只是說雙方都是ESTABLLISHED狀態,就說明雙方連線正常;
  • FIN_WAIT_1:已經建立連線後,其中一方請求終止連線,四次揮手中間狀態;
  • TIME_WAIT:表示收到了對方的FIN報文,併傳送出了ACK報文,就等2MSL(預設是2min)後回到CLOSED可用狀態;
  • CLOSING:表示傳送FIN報文後,沒有收到對方的ACK報文,反而收到了對方的FIN報文,這種情況其實就是雙方同時關閉socket;
  • CLOSE_WAIT:四次揮手中間狀態,表示在等待關閉連線;
  • LAST_ACK:四次揮手時被動關閉一方在傳送FIN報文後,等待對方的ACK確認報文;
  • RST:同時開啟和同時關閉;

1.5 TIME_WAIT為什麼要等2MSL才會變為CLOSED

有兩個原因:

  • 可靠地終止TCP連線,在四次揮手的最後一步中,可能客戶端傳送到服務端的確認包丟失,服務端就會重發結束報文段,客戶端重新發起確認報文段,而這就需要停留一段時間;
  • 保證讓遲來的TCP報文段有足夠的時間被識別並丟棄,如果沒有停留一段時間,原來客戶端的埠號就可以立即被另外一個應用程式重用,此時如果服務端有遲來的報文段,就會發到該新的應用程式上去,而這顯然是不被允許的;

注意:報文段的生存週期是一個MSL,所以在2MSL後,不會還存在遲到的報文段。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/3034/viewspace-2823411/,如需轉載,請註明出處,否則將追究法律責任。

相關文章