天天看點

C++/java網絡常見題目1_TCP三向交握及四次揮手TCPTCP報頭參考:

TCP

定義:TCP(Transmission Control Protocol 傳輸控制協定)是一種面向連接配接的、可靠的、基于位元組流的傳輸層通信協定。

TCP報頭

C++/java網絡常見題目1_TCP三向交握及四次揮手TCPTCP報頭參考:
  1. 源端口和目的端口,各占2個位元組,分别寫入源端口和目的端口;
  2. 序号是發送資料包中的第一個位元組的序列号,TCP連接配接中傳送的位元組流中的每個位元組都按順序編号。
  3. 确認号,占4個位元組,表示下一次應該收到的資料的序列号。發送端收到這個确認應答以後可以認為在這個序号以前的資料都已經被正常接收。
  4. 資料偏移,占4位,它指出TCP封包的資料距離TCP封包段的起始處有多遠;
  5. 保留,占6位,保留今後使用,但目前應都位0;
  6. 字段 含義
    URG 緊急指針是否有效。為1,表示某一位需要被優先處理。
    ACK 僅當ACK=1時,确認号字段才有效。
    PSH 提示接收端應用程式立即從TCP緩沖區把資料讀走。
    RST 對方要求重建立立連接配接,複位。
    SYN 請求建立連接配接,并在其序列号的字段進行序列号的初始值設定。建立連接配接,設定為1.
    FIN 希望斷開連接配接。當FIN=1,表明此封包的發送方的資料已經發送完畢,并且要求釋放;
  7. 視窗,占2位元組,指的是通知接收方,發送本封包你需要有多大的空間來接受;
  8. 檢驗和,占2位元組,校驗首部和資料這兩部分;
  9. 緊急指針,占2位元組,隻有URG标志位被設定時該字段才有意義,表示緊急資料相對序列号(Sequence Number字段的值)的偏移
  10. 選項,長度可變,定義一些其他的可選的參數。

三次握手:建立連接配接

C++/java網絡常見題目1_TCP三向交握及四次揮手TCPTCP報頭參考:

第一次握手:建立連接配接時,用戶端發送請求封包(SYN=1,同時選擇一個初始序列号 seq=x)到伺服器,并進入SYN_SEND狀态,等待伺服器确認;

第二次握手:伺服器收到請求封包,同意連接配接,則發出确認封包(ACK=1,SYN=1,确認号是ack=x+1,同時也要為自己初始化一個序列号 seq=y),此時伺服器進入SYN_RECV狀态;

第三次握手:用戶端收到伺服器的确認後,還要向伺服器給出确認封包(ACK=1,确認号是ack=y+1,自己的序列号為 seq=x+1),此包發送完畢,用戶端和伺服器進入ESTABLISHED狀态,完成三次握手。

完成三次握手,用戶端與伺服器開始傳送資料

四次揮手:釋放連接配接

C++/java網絡常見題目1_TCP三向交握及四次揮手TCPTCP報頭參考:
  1. 用戶端程序發出連接配接釋放封包(FIN=1,其序列号為seq=u,其中u為前面已經傳送過來的資料的最後一個位元組的序号加1),并且停止發送資料。
  2. 伺服器收到連接配接釋放封包,發出确認封包(ACK=1,ack=u+1,并且帶上自己的序列号seq=t),進入CLOSE_WAIT狀态,用戶端收到這個ACK,進入FIN_WAIT2狀态。此階段若伺服器發送資料,用戶端仍要接受。
  3. 伺服器将最後的資料發送完畢後,就向用戶端發送連接配接釋放封包(FIN=1,ACK = 1,ack=u+1,seq=w,其中seq不是t的原因是可能在此過程中發送了資料,故序号增加改變),伺服器進入LAST_ACK狀态
  4. 用戶端收到伺服器的連接配接釋放封包後,必須發出确認封包(ACK=1,ack=w+1,自己的序列号是seq=u+1),進入TIME_WAIT狀态,服務端收到ACK,進入CLOSE狀态。

TIME_WAIT

  • TIME_WAIT 是主動關閉連結時形成的,等待2MSL時間,約4分鐘。主要是防止最後一個ACK丢失。 由于TIME_WAIT 的時間會非常長,是以server端應盡量減少主動關閉連接配接

CLOSE_WAIT

  • CLOSE_WAIT是被動關閉連接配接是形成的。根據TCP狀态機,伺服器收到用戶端發送的FIN,則按照TCP實作發送ACK,是以進入CLOSE_WAIT狀态。但如果伺服器端不執行close(),就不能由CLOSE_WAIT遷移到LAST_ACK,則系統中會存在很多CLOSE_WAIT狀态的連接配接。此時,可能是系統忙于處理讀、寫操作,而未将已收到FIN的連接配接,進行close。此時,recv/read已收到FIN的連接配接socket,會傳回0。

為什麼需要 TIME_WAIT 狀态?

  • 假設最終的ACK丢失,伺服器将重發FIN,用戶端必須維護TCP狀态資訊以便可以重發最終的ACK,否則會發送RST,結果伺服器認為發生錯誤。TCP實作必須可靠地終止連接配接的兩個方向(全雙工關閉),用戶端必須進入 TIME_WAIT 狀态,因為用戶端可能面 臨重發最終ACK的情形。

為什麼 TIME_WAIT 狀态需要保持 2MSL 這麼長的時間?

  1. 為了保證A發送的最後一個ACK封包能夠到達B。這個ACK封包段有可能丢失,因而使處在LAST-ACK狀态的B收不到對已發送的FIN+ACK封包段的确認。B會逾時重傳這個FIN+ACK封包段,而A就能在2MSL時間内收到這個重傳的FIN+ACK封包段。如果A在TIME-WAIT狀态不等待一段時間,而是在發送完ACK封包段後就立即釋放連接配接,就無法收到B重傳的FIN+ACK封包段,因而也不會再發送一次确認封包段。這樣,B就無法按照正常的步驟進入CLOSED狀态。
  2. A在發送完ACK封包段後,再經過2MSL時間,就可以使本連接配接持續的時間所産生的所有封包段都從網絡中消失。這樣就可以使下一個新的連接配接中不會出現這種舊的連接配接請求的封包段。

 建立連接配接為什麼需要三次握手,兩次不可以嗎?

  • 第三次握手是為了防止:如果用戶端遲遲沒有收到伺服器傳回确認封包,這時會放棄連接配接,重新啟動一條連接配接請求,但問題是:伺服器不知道用戶端沒有收到,是以他會收到兩個連接配接,浪費連接配接開銷。如果每次都是這樣,就會浪費多個連接配接開銷。
  • 假設用戶端請求建立連接配接,發給伺服器SYN包等待伺服器确認,伺服器收到确認後,如果是兩次握手,假設伺服器給用戶端在第二次握手時發送資料,資料從伺服器發出,伺服器認為連接配接已經建立,但在發送資料的過程中資料丢失,用戶端認為連接配接沒有建立,會進行重傳。假設每次發送的資料一直在丢失,用戶端一直SYN,伺服器就會産生多個無效連接配接,占用資源,這個時候伺服器可能會挂掉。這個現象就是我們聽過的“SYN的洪水攻擊”。

本系列文章目的為個人準備面試的簡單總結,文中多有不足,敬請批評指正!

參考:

https://blog.csdn.net/qzcsu/article/details/72861891

https://blog.csdn.net/ZWE7616175/article/details/80432486