TCP的三次握手四次揮手

1、三次握手

1.wireshark 抓包

 

2.TCP報文手部

 

注意標誌位:git

1).同步 SYN = 1 表示這是一個鏈接請求或鏈接接受報文。 github

2).只有當 ACK = 1 時確認號字段纔有效。當 ACK = 0 時,確認號無效。 服務器

3).FIN = 1 代表此報文段的發送端的數據已發送完畢,並要求釋放運輸鏈接。 cookie

 

3.鏈接示意

 

2、四次揮手

1.知因此然

爲何創建鏈接協議是三次握手,而關閉鏈接倒是四次握手呢?網絡

這是由於服務端的LISTEN狀態下的SOCKET當收到SYN報文的建連請求後,它能夠把ACK和SYN(ACK起應答做用,而SYN起同步做用)併發

放在一個報文裏來發送。但關閉鏈接時,當收到對方的FIN報文通知時,它僅僅表示對方沒有數據發送給你了;但未必你全部的數據都所有socket

發送給對方了,因此你能夠未必會立刻會關閉SOCKET,也即你可能還須要發送一些數據給對方以後,再發送FIN報文給對方來表示你贊成tcp

如今能夠關閉鏈接了,因此它這裏的ACK報文和FIN報文多數狀況下都是分開發送的。優化

  更明瞭的回答:因爲TCP鏈接是全雙工的,所以每一個方向都必須單獨進行關閉。這個原則是當一方完成它的數據發送任務後就能發送一spa

個FIN來終止這個方向的鏈接。收到一個 FIN只意味着這一方向上沒有數據流動,一個TCP鏈接在收到一個FIN後仍能發送數據。首先進行

關閉的一方將執行主動關閉,而另外一方執行被動關閉。

 

2.圖示

 

第一階段

  1. 首先client會發送一個FIN包給server(同時還有ack和seq包),這是要告訴server,我已經沒有數據要發給你了,此時client處於FIN_WAIT_1狀態。接收到FIN包的server處於CLOSE_WAIT的狀態。
  2. server發回一個ACK(值爲client傳過來的seq+1)和seq(值爲client傳過來的ack的值)給client。client收到server發過來的包後確認關閉鏈接,此時client處於FIN_WAIT_2。

第二階段

  1. server在接收到client的FIN後,得知client要斷開tcp鏈接了,因而在發送完ack和seq給client後,本身發送一個FIN包給client(也帶有ack和seq包),告訴client我也要斷開鏈接了,此時server處於LAST_ACK狀態。
  2. client接收到server的FIN信息後,會回覆server一個ack包,而且會進入TIME_WAIT狀態,持續2個MSL(Max Segment Lifetime)。而server接收到client ack後便關閉鏈接。client在指定時間事後仍然沒有接收到server的數據,確認server已經沒有數據過來,也關閉了鏈接。

 

   (1)、CLOSE_WAIT的解釋。
在以上事例,咱們知道server在接收到FIN後,發送ACK以前會進入CLOSE_WAIT,若是長期處於這個狀態,或者說服務器出現大量CLOSE_WAIT,說明ACK包一直沒有發出,這時候就應該檢查代碼了。

 

 

(2)、TIME_WAIT注意事項
從事例咱們知道,主動關閉鏈接的一方會經歷TIME_WAIT狀態,在該狀態下的socket是不會被回收的。而若是是服務器端主動關閉鏈接,則可能會面臨處於大量TIME_WAIT的狀況(由於鏈接不少嘛),會嚴重影響服務器的處理能力。
怎麼解決呢,那就減小服務器端TIME_WAIT的時間咯。

 

 

 

(3)2MSL(Maximum Segment Lifetime)存在的理由

 

TCP的TIME_WAIT狀態也稱爲2MSL等待狀態

 

(4)2MSL狀態爲何設計在主動關閉這一方

(1)發最後ack的是主動關閉一方

(2)只要有一方保持TIME_WAIT狀態,就能起到避免incarnation connection在2MSL內的從新創建,不須要兩方都有

 

 

3、TCP鏈接出現大量TIME_WAIT的解決辦法

 主動關閉TCP/IP鏈接,會經過TIME_WAIT的狀態保留一段時間,時間過了纔會釋放這個端口,當端口接受的頻繁請求數量過多的時候,

就會產生大量的TIME_WAIT狀態的鏈接,這些鏈接佔着端口,會消耗大量的資源。

 

這個TIME_WAIT的做用是什麼?

緣由有二:

1、保證TCP協議的全雙工鏈接可以可靠關閉

 

若是Client直接CLOSED了,那麼因爲IP協議的不可靠性或者是其它網絡緣由,致使Server沒有收到Client最後回覆的ACK。那麼Server就會在超時以後繼續發送FIN。 此時因爲Client已經CLOSED了,就找不到與重發的FIN對應的鏈接,最後Server就會收到RST而不是ACK,Server就會覺得是鏈接錯誤把問題報告給高層。 這樣的狀況雖然不會形成數據丟失,可是卻致使TCP協議不符合可靠鏈接的要求。 因此,Client不是直接進入CLOSED,而是要保持TIME_WAIT,當再次收到FIN的時候,可以保證對方收到ACK,最後正確的關閉鏈接。 

2、保證此次鏈接的重複數據段從網絡中消失

若是Client直接CLOSED,而後又再向Server發起一個新鏈接,咱們不能保證這個新鏈接與剛關閉的鏈接的端口號是不一樣的。也就是說有可能新鏈接和老鏈接的端口號是相同的。 通常來講不會發生什麼問題,可是仍是有特殊狀況出現:假設新鏈接和已經關閉的老鏈接端口號是同樣的,若是前一次鏈接的某些數據仍然滯留在網絡中,這些延遲數據在創建新鏈接以後纔到達Server,因爲新鏈接和老鏈接的端口號是同樣的,又由於TCP協議判斷不一樣鏈接的依據是socket pair。 因而,TCP協議就認爲那個延遲的數據是屬於新鏈接的,這樣就和真正的新鏈接的數據包發生混淆了。

 

vi /etc/sysctl.conf
#當出現SYN等待隊列溢出時,啓用cookies來處理,可防範少許SYN攻擊 net.ipv4.tcp_syncookies
= 1

#容許將TIME-WAIT sockets從新用於新的TCP鏈接,默認爲0 net.ipv4.tcp_tw_reuse = 1

#開啓TCP鏈接中TIME-WAIT sockets的快速回收,默認爲0,表示關閉 net.ipv4.tcp_tw_recycle = 1

# 默認60 net.ipv4.tcp_fin_timeout = 30

/sbin/sysctl -p

  

此外,若是你的鏈接數自己就不少,咱們能夠再優化一下TCP/IP的可以使用端口範圍,進一步提高服務器的併發能力。

 

net.ipv4.tcp_keepalive_time = 1200

表示當keepalive起用的時候,TCP發送keepalive消息的頻度。缺省是2小時,改成20分鐘。


net.ipv4.ip_local_port_range = 10000 65000

表示用於向外鏈接的端口範圍。缺省狀況下很小:32768到61000,改成10000到65000。設的過低,不然可能會佔用掉正常的端口


net.ipv4.tcp_max_syn_backlog = 8192

表示SYN隊列的長度,默認爲1024,加大隊列長度爲8192,能夠容納更多等待鏈接的網絡鏈接數。


net.ipv4.tcp_max_tw_buckets = 5000

表示系統同時保持TIME_WAIT的最大數量,若是超過這個數字,TIME_WAIT將馬上被清除並打印警告信息。默認爲180000,改成5000。對於Apache、Nginx等服務器,上幾行的參數能夠很好地減小TIME_WAIT套接字數量。

 

 

參考:TCP鏈接的創建和釋放

相關文章
相關標籤/搜索