TCP三次握手,UDP,四次揮手,TIME_WAIT

三次握手過程

  1 客戶端的協議棧向服務器端發送了SYN包,並告訴服務器端當前發送序列號j,客戶端進入SYNC_SENT狀態;服務器

  2 服務器端的協議棧收到這個包以後,和客戶端進行ACK應答,應答的值爲j+1,表示對SYN包j的確認,同時服務器也發送一個SYN包,告訴客戶端當前個人發送序列號併發

爲k,服務器端進入SYNC_RCVD狀態;編碼

  3 客戶端協議棧收到ACK以後,使得應用程序從connect調用返回,表示客戶端到服務器端的單向鏈接創建成功,客戶端的狀態爲ESTABLISHED,同時客戶端協議棧也設計

會對服務器端的SYN包進行應答,應答數據爲k+1;blog

  應答包到達服務器端後,服務器端協議棧使得accept阻塞調用返回,這個時候服務器端到客戶端的單向鏈接也創建成功,服務器端也進入ESTABLISHED狀態。ip

形象一點的比喻是這樣的,有A和B想進行通話:內存

  A先對B說:「喂,你在麼?我在的,個人口令是j。」資源

  B收到以後大聲回答:「我收到你的口令j並準備好了,你準備好了嗎?個人口令是k。」it

  A收到以後也大聲回答:「我收到你的口令k並準備好了,咱們開始吧。」基礎

  能夠看到,這樣的應答過程總共進行了三次,這就是TCP鏈接創建之因此被叫爲「三次握手」的緣由了。

UDP

  咱們能夠給 UDP 找一個相似的例子,這個例子就是郵寄明信片。在這個例子中,發信方在明信片中填上了接收方的地址和郵編,投遞到郵局的郵筒以後,就能夠無論

了。發信方也能夠給這個接收方再郵寄第二張、第三張,甚至是第四張明信片,可是這幾張明信片之間是沒有任何關係的,他們的到達順序也是不保證的,有可能最後寄出的

第四張明信片最早到達接收者的手中,由於沒有序號,接收者也不知道這是第四張寄出的明信片;並且,即便接收方沒有收到明信片,也沒有辦法從新郵寄一遍該明信片。

  TCP 是一個面向鏈接的協議,TCP 在 IP 報文的基礎上,增長了諸如重傳、確認、有序傳輸、擁塞控制等能力,通訊的雙方是在一個肯定的上下文中工做的。

  而 UDP 則不一樣,UDP 沒有這樣一個肯定的上下文,它是一個不可靠的通訊協議,沒有重傳和確認,沒有有序控制,也沒有擁塞控制。咱們能夠簡單地理解爲,在 IP 報

文的基礎上,UDP 增長的能力有限。

  UDP 不保證報文的有效傳遞,不保證報文的有序,也就是說使用 UDP 的時候,咱們須要作好丟包、重傳、報文組裝等工做。

 四次揮手

 

  首先,一方應用程序調用 close,咱們稱該方爲主動關閉方,該端的 TCP 發送一個 FIN 包,表示須要關閉鏈接。以後主動關閉方進入 FIN_WAIT_1 狀態。

  接着,接收到這個 FIN 包的對端執行被動關閉。這個 FIN 由 TCP 協議棧處理,咱們知道,TCP 協議棧爲 FIN 包插入一個文件結束符 EOF 到接收緩衝區中,應用程序可

以經過 read 調用來感知這個 FIN 包。必定要注意,這個 EOF 會被放在已排隊等候的其餘已接收的數據以後,這就意味着接收端應用程序須要處理這種異常狀況,由於 EOF

表示在該鏈接上再無額外數據到達。此時,被動關閉方進入 CLOSE_WAIT 狀態。

  接下來,被動關閉方將讀到這個 EOF,因而,應用程序也調用 close 關閉它的套接字,這致使它的 TCP 也發送一個 FIN 包。這樣,被動關閉方將進入 LAST_ACK 狀態。

  最終,主動關閉方接收到對方的 FIN 包,並確認這個 FIN 包。主動關閉方進入 TIME_WAIT 狀態,而接收到 ACK 的被動關閉方則進入 CLOSED 狀態。進過 2MSL 時間

以後,主動關閉方也進入 CLOSED 狀態。

  你能夠看到,每一個方向都須要一個 FIN 和一個 ACK,所以一般被稱爲四次揮手。

  固然,這中間使用 shutdown,執行一端到另外一端的半關閉也是能夠的。

TIME_WAIT

  TCP 鏈接終止時,主機 1 先發送 FIN 報文,主機 2 進入 CLOSE_WAIT 狀態,併發送一個 ACK 應答,同時,主機 2 經過 read 調用得到 EOF,並將此結果通知應用程

序進行主動關閉操做,發送 FIN 報文。主機 1 在接收到 FIN 報文後發送 ACK 應答,此時主機 1 進入 TIME_WAIT 狀態。

  主機 1 在 TIME_WAIT 停留持續時間是固定的,是最長分節生命期 MSL(maximum segment lifetime)的兩倍,通常稱之爲 2MSL。和大多數 BSD 派生的系統同樣,

Linux 系統裏有一個硬編碼的字段,名稱爲TCP_TIMEWAIT_LEN,其值爲 60 秒。也就是說,Linux 系統停留在 TIME_WAIT 的時間爲固定的 60 秒。

  過了這個時間以後,主機 1 就進入 CLOSED 狀態。只有發起鏈接終止的一方會進入 TIME_WAIT 狀態

time_wait 的做用

  爲何不直接進入 CLOSED 狀態,而要停留在 TIME_WAIT 這個狀態

  首先,這樣作是爲了確保最後的 ACK 能讓被動關閉方接收,從而幫助其正常關閉。

  TCP 在設計的時候,作了充分的容錯性設計,好比,TCP 假設報文會出錯,須要重傳。在這裏,若是圖中主機 1 的 ACK 報文沒有傳輸成功,那麼主機 2 就會從新發送 FIN 報文。

  若是主機 1 沒有維護 TIME_WAIT 狀態,而直接進入 CLOSED 狀態,它就失去了當前狀態的上下文,只能回覆一個 RST 操做,從而致使被動關閉方出現錯誤。

  如今主機 1 知道本身處於 TIME_WAIT 的狀態,就能夠在接收到 FIN 報文以後,從新發出一個 ACK 報文,使得主機 2 能夠進入正常的 CLOSED 狀態。

time_wait 的危害

  過多的 TIME_WAIT 的主要危害有兩種。

  第一是內存資源佔用,這個目前看來不是太嚴重,基本能夠忽略。

  第二是對端口資源的佔用,一個 TCP 鏈接至少消耗一個本地端口。要知道,端口資源也是有限的,通常能夠開啓的端口爲 32768~61000 ,也能夠經過

net.ipv4.ip_local_port_range指定,若是 TIME_WAIT 狀態過多,會致使沒法建立新鏈接。這個也是咱們在一開始講到的那個例子。

相關文章
相關標籤/搜索