TCP/IP相關

2020-08-11 15:30:49

TCP/IP相關

1. 定義

  • IP協定

    • IP 協定實際上是用來查詢地址的,而它對應的層級也是網路層,也可以稱之爲網際互聯層,區別不大。

  • TCP協定

    • TCP 協定是用來規範傳輸規則的,和IP 協定是不同的,而它對應的層級是傳輸層,也就是IP去尋找地址,把所有的傳輸任務都交給TCP,而TCP相當於一個快遞員的角色。

2. 三次握手

  • 序號

    • seq:sequence number 的縮寫,即序號。seq表示的則是自己傳遞的序號,TCP在傳輸的時候,其中每一個位元組,都會有一個序號,發送數據的時候,會把第一個數據的第一個序號發送給對方,就是看到的第一步,而接收的這一方面,會按照這個序號來檢查是否是一個連線完整的數據,是完整的話就繼續,不完整的話就重新發送。保證數據完整性不被破壞。

    • ack: 注意是小寫的 acknoledgement number的縮寫 表示確認號 ,要和ACK(確認位)區分 ,接收端用它來給發送端返回接受訊息的數據資訊,而這時候,它的值就是表明我想接收下一個數據包了。而這個值就是下一個數據包的開始的序號,而這個ack所代表的值的序號前面的數據都已經接受成功了。

    • ACK確認位: 只有當ACK=1的時候ack纔會起到作用,而在我們第一次請求的時候,是沒有需要確認的接受的數據的,這個時候ACK=0,正常通訊下ACK=1.

    • SYN: 同步位 ,作用是用於建立連線時同步序號,剛建立連線的時候,ACK=0這時ack就不起作用,當接收端收到SYN=1的報文的時候,會將ack設定爲接收到的seq+1的值,這時候的ack的值就是根據SYN來設定的。

    • FIN:終止位,在本圖沒有體現,在四次揮手的時候能完全體現出來。而它是用來在數據傳輸都完成之後來釋放連線的。

  • 上圖解析:

    • 第一次握手(SYN=1,seq=x)

      • 用戶端發送一個TCP的SYN標誌位置1的包,指明用戶端打算連線的伺服器的埠,以及初始序號X,儲存在包頭的序列號(seq)中。發送完畢後,用戶端進入SYN_SEND狀態

    • 第二次握手(ack=y+1,ACK=1,seq=y,SYN=1)

      • 伺服器發回確認包(ACK)應答。即SYN和ACK標誌位都爲1。伺服器端選擇自己ISN序列號,放到seq域中,同時將確認序號ack設定爲客戶的ISN加1,即y+1。發送完畢後,伺服器端進入SYN_RCVD狀態

    • 第三次握手(ack=y+1,ACK=1)

      • 用戶端再次發送確認包(ACK),SYN標誌位爲0,ACK標誌位爲1,並且把伺服器發來的ACK序號欄位+1,放在ack中返回。發送完畢後,用戶端進入ESTABLISHED狀態,當伺服器端接收到這個包時也會進入ESTABLISHED狀態,TCP握手結束。

3. 四次揮手

 

  • 流程解讀:

    • 第一次揮手(FIN=1,seq=x)

      • 假如用戶端想要關閉連線,用戶端發送一個FIN標誌位置爲1的包,表示自己已經沒有數據可以發送了,但是任然可以接受數據,發送完畢後,用戶端進入FIN_WAIT_1狀態

    • 第二次揮手(ACK=1,ack=x+1)

      • 伺服器端接收到用戶端發送的FIN包,發送一個確認包,表明自己接受到了用戶端關閉連線的請求但是伺服器端還沒有準備好關閉連線。發送完畢後,伺服器端進入CLOSE_WAIT狀態,用戶端收到這個確認包後,進入FIN_WAIT_2狀態等待伺服器關閉連線。

    • 第三次揮手(FIN=1,seq=y)

      • 伺服器端準備好關閉連線時,向用戶端發送結束連線請求,FIN值爲1。發送完畢後,伺服器端進入LAST_ACK狀態 ,等待來自用戶端的最後一個ACK。

    • 第四次揮手(ACK=1,ack=y+1)

      • 用戶端收到伺服器端的關閉請求時,發送一個確認包,並且進入TIME_WAIT狀態,等待可能出現的要求重傳的ACK包。

      • 伺服器端接收到這個包後,關閉連線,進入CLOSED狀態

      • 用戶端等待了某個固定時間(兩個最大段生命週期,2MSL,2Maximum Segment Lifetime)之後,沒有收到伺服器端的ACK,認爲伺服器端已經正常關閉連線,於是自己也關閉連線,進入CLOSED狀態。兩次後會重傳直到超時。如果多了會有大量半鏈接阻塞佇列

4. 爲什麼連線三次握手,而斷開是四次揮手呢

  • 這是因爲伺服器端在LISTEN狀態下,收到建立連線請求的SYN報文後,把ACK和SYN放在一個報文發送給用戶端。而關閉連線時,當收到對方的FIN報文時,僅僅表示用戶端不再發送數據,但是還能接受數據,伺服器端是否現在關閉數據發送通道需要上層應用決定,因此ACK和FIN一般分開發送。

5. 伺服器保持了大量TIME_WAIT狀態

  • 原因

    • TIME_WAIT是主動關閉連線的一方保持的狀態,對於爬蟲伺服器來說他本身就是「用戶端」,在完成一個爬取任務之後,他就 會發起主動關閉連線,從而進入TIME_WAIT的狀態,然後在保持這個狀態2MSL(max segment lifetime)時間之後,徹底關閉回收資源。

    • 檢視伺服器所有連線狀態的命令

      netstat -n|awk '/^tcp/{++S[$NF]}END{for (key in S) print key,S[key]}'
  • 爲什麼?

    • 防止上一次連線中的包,迷路後重新出現,影響新連線(經過2MSL,上一次連線中所有的重複包都會消失)

    • 可靠的關閉TCP連線。在主動關閉方發送的最後一個 ack(fin) ,有可能丟失,這時被動方會重新發fin, 如果這時主動方處於 CLOSED 狀態 ,就會響應 rst 而不是 ack。所以主動方要處於 TIME_WAIT 狀態,而不能是 CLOSED 。另外這麼設計TIME_WAIT 會定時的回收資源,並不會佔用很大資源的,除非短時間內接受大量請求或者受到攻擊。

  • 解決方案

    • 編輯檔案/etc/sysctl.conf,加入以下內容:

      net.ipv4.tcp_syncookies = 1
      net.ipv4.tcp_tw_reuse = 1
      net.ipv4.tcp_tw_recycle = 1
      net.ipv4.tcp_fin_timeout = 30

6. 伺服器保持了大量CLOSE_WAIT狀態

  • 原因

    • 就是在對方關閉連線之後伺服器程式自己沒有進一步發出ack信號。換句話說,就是在對方連線關閉之後,程式裡沒有檢測到,或者程式壓根就忘記了這個時候需要關閉連線,於是這個資源就一直 被程式佔着。

    • 比如說

      伺服器A是一臺爬蟲伺服器,它使用簡單的HttpClient去請求資源伺服器B上面的apache獲取檔案資源,正常情況下,如果請求成功,那麼在抓取完 資源後,伺服器A會主動發出關閉連線的請求,這個時候就是主動關閉連線,伺服器A的連線狀態我們可以看到是TIME_WAIT。如果一旦發生異常呢?假設 請求的資源伺服器B上並不存在,那麼這個時候就會由伺服器B發出關閉連線的請求,伺服器A就是被動的關閉了連線,如果伺服器A被動關閉連線之後程式設計師忘了 讓HttpClient釋放連線,那就會造成CLOSE_WAIT的狀態了。

  • 解決方案

    • 此問題一般是由於程式程式碼編寫問題導致的,查程式碼吧