注意標誌位:git
1).同步 SYN = 1 表示這是一個鏈接請求或鏈接接受報文。 github
2).只有當 ACK = 1 時確認號字段纔有效。當 ACK = 0 時,確認號無效。 服務器
3).FIN = 1 代表此報文段的發送端的數據已發送完畢,並要求釋放運輸鏈接。 cookie
爲何創建鏈接協議是三次握手,而關閉鏈接倒是四次握手呢?網絡
這是由於服務端的LISTEN狀態下的SOCKET當收到SYN報文的建連請求後,它能夠把ACK和SYN(ACK起應答做用,而SYN起同步做用)併發
放在一個報文裏來發送。但關閉鏈接時,當收到對方的FIN報文通知時,它僅僅表示對方沒有數據發送給你了;但未必你全部的數據都所有socket
發送給對方了,因此你能夠未必會立刻會關閉SOCKET,也即你可能還須要發送一些數據給對方以後,再發送FIN報文給對方來表示你贊成tcp
如今能夠關閉鏈接了,因此它這裏的ACK報文和FIN報文多數狀況下都是分開發送的。優化
更明瞭的回答:因爲TCP鏈接是全雙工的,所以每一個方向都必須單獨進行關閉。這個原則是當一方完成它的數據發送任務後就能發送一spa
個FIN來終止這個方向的鏈接。收到一個 FIN只意味着這一方向上沒有數據流動,一個TCP鏈接在收到一個FIN後仍能發送數據。首先進行
關閉的一方將執行主動關閉,而另外一方執行被動關閉。
第一階段
第二階段
(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內的從新創建,不須要兩方都有
主動關閉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鏈接的創建和釋放