TCP详解
總通信流程圖
?
上圖表明了tcp三次握手,四次揮手通信流程
一般來說,我們希望看到的狀態只有ESTABLISHED,其它狀態都是問題狀態的,但是我們通過命令netstat –alt 能看到其它狀態,常見的有CLOSE_WAIT,TIME_WAIT。下面就來說說為什么會看到這些問題狀態,以及解決方法。
?
TCP揮手詳細流程
揮手比握手復雜,再來一張更加清晰的揮手通信圖
?
?
狀態詳解
LISTEN
狀態為LISTEN,這個沒什么好說的,服務端首先啟動監聽,如果這個狀態有問題,要么就是端口重了,要么就是連網卡有問題。
?
SYN_SENT
主動建立連接的一方發送SYN請求后的狀態
?
SYN_RECV
被動建立連接的一方接受到SYN包后,狀態由LISTEN轉為SYN_RECV,并發出ack和SYN
?
ESTABLISHED
連接建立成功
?
FIN_WAIT1
此狀態表示主動關閉tcp連接的一方,發出了第一次揮手指令后直到接收到另一端響應的ack的狀態。
當FIN_WAIT1過多
分析
·被動關閉的一方出現問題(可能是本身故障或者網絡故障),沒有接收到第一次揮手指令,從而主動關閉的一方沒有接收到響應的ack
·可能是網絡問題
·被動關閉方服務器負載過重,導致沒有資源來發送ack
·可能受到了網絡攻擊,可以在防火墻中過濾該地址
?
解決思路
·查看被動關閉方是否正常,包括所在的網絡環境是否正常
·檢查本地網絡環境
·如果是外來ip,則防火墻拉黑
?
CLOSE_WAIT
當被動關閉方接受到FIN包后,狀態就轉為CLOSE_WAIT,并回復FIN包的ack包。直到被動關閉方向主動關閉方發起FIN包,CLOSE_WAIT狀態才會消失。
CLOSE_WAIT狀態過多
分析
·主動關閉方出現故障,沒有能力回復ack。有可能在回復之前已經關閉連接
?
解決思路
·在主動方關閉連接的時候,被動方接受到FIN,卻沒有關閉自己連接,有可能是代碼問題,檢查代碼有沒有漏關連接。
·減小被動方的連接超時時間,比如connectTimeout,readTimeout設置在1s以內
?
FIN_WAIT2
主動關閉方接受到了自己請求關閉的FIN包的ack后,狀態由FIN_WAIT1轉為FIN_WAIT2。直到接受到被動關閉方發來的關閉請求FIN包。
FIN_WAIT2數量過多
分析
·由于被動關閉方一直沒有發來FIN包,導致主動關閉方一直處于FIN_WAIT2狀態
·網絡狀態,是不是網絡波動導致大量丟包
?
解決思路
·減小FIN_WAIT2的超時時間
在/etc/sysctl.conf中加入配置
#默認超時時間是240s
tcp_fin_timeout=30
·查看被動關閉方代碼。有沒有及時關閉
?
LAST_ACK
被動關閉方在響應主動關閉方的后,發出自己關閉請求的FIN包,此時狀態由CLOSE_WAIT轉為LAST_ACK
?
TIME_WAIT
在接收到被動關閉方的FIN包后,狀態由FIN_WAIT2轉為TIME_WAIT,并向被動關閉方發送ack包。此狀態的意義在于,四次揮手已經接近尾聲,為了防止被動關閉方沒有接收到ack包的問題,主動關閉方只能多存活一段時間(2MSL max segment lifetime),這段時間內如果被動關閉方真的沒有收到ack,則會再次發來FIN包,來要主動關閉方的ack。
TIME_WAIT數量過多
分析
·網絡狀態不穩定,導致連接重復斷連
·連接關閉后釋放不及時,沒有重復利用
?
解決思路
·調整linux上的關于TCP TIME_WAIT的參數
在/etc/sysctl.conf文件中加入或修改
#詳細解釋參考相關配置
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=1
net.ipv4.tcp_max_tw_buckets=5000
?
CLOSED
被動關閉方在接受到ack之后,狀態由LAST_ACK轉為CLOSED,至此連接結束(當然主動關閉方還在苦苦等待,等待結束后也會轉為CLOSED狀態)。
?
意外退出
程序意外退出
當程序意外退出時,比如直接kill -9 $pid
linux內核會釋放關于該進程的所有資源,會自動觸發tcp的4次揮手,并成為主動關閉連接的一方。
?
服務器關閉
服務器關閉就沒這么好運了,通常情況只會留給進程幾秒的時間來做資源釋放,并不能保證tcp能正常釋放
?
相關配置
#設置tcp配置的文件
/etc/sysctl.conf
#配置完記得保存
/sbin/sysctl -p
?
配置
| Key | 默認 | 解釋 |
| net.ipv4.tcp_syncookies | 0 | 表示開啟SYN Cookies。當出現SYN等待隊列溢出時,啟用cookies來處理,可防范少量SYN攻擊,默認為0,表示關閉。 |
| net.ipv4.tcp_tw_reuse | 0 | 表示開啟重用。允許將TIME-WAIT sockets重新用于新的TCP連接,默認為0,表示關閉。 |
| net.ipv4.tcp_tw_recycle | 0 | 表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉。 |
| net.ipv4.tcp_fin_timeout | 240 | 表示如果套接字由本端要求關閉,這個參數決定了它保持在FIN-WAIT-2狀態的時間,可改為30s |
| net.ipv4.tcp_keepalive_time | 60*60*2 | 表示當keepalive起用的時候,TCP發送keepalive消息的頻度。缺省是2小時,一般改為20分鐘。 |
| net.ipv4.ip_local_port_range | 32768 61000 | 表示用于向外連接的端口范圍。缺省情況下過窄:32768到61000,改為1024到65535。 |
| net.ipv4.tcp_max_syn_backlog | 1024 | 表示SYN隊列的長度,默認為1024,加大隊列長度為8192,可以容納更多等待連接的網絡連接數。 |
| net.ipv4.tcp_max_tw_buckets | 180000 | 表示系統同時保持TIME_WAIT套接字的最大數量,如果超過這個數字,TIME_WAIT套接字將立刻被清除并打印警告信息。默認為180000,建議減小,避免TIME_WAIT狀態過多消耗整個服務器的資源,但也不能太小,跟你后端的處理速度有關,如果速度快可以小,速度慢則適當加大,否則高負載會有請求無法響應或非常慢。 可改為5000再視情況而定 |
| net.ipv4.tcp_synack_retries | 5 | 三次握手的第二次交互,tcp_synack_retries 的值必須為正整數,并不能超過 255。因為每一次重新發送封包都會耗費約 30 至 40 秒去等待才決定嘗試下一次重新發送或決定放棄。tcp_synack_retries 的缺省值為 5,即每一個連線要在約 180 秒 (3 分鐘) 后才確定逾時. |
| net.ipv4.tcp_syn_retries | 5 | 三次握手的第一次交互。對于一個新建連接,內核要發送多少個 SYN 連接請求才決定放棄。不應該大于255,默認值是5,對應于180秒左右時間。(對于大負載而物理通信良好的網絡而言,這個值偏高,可修改為2.這個值僅僅是針對對外的連接,對進來的連接,是由tcp_retries1 決定的) |
| net.ipv4.tcp_retries1 | 3 | 放棄回應一個TCP連接請求前﹐需要進行多少次重試。RFC 規定最低的數值是3﹐這也是默認值﹐根據RTO的值大約在3秒 - 8分鐘之間。(注意:這個值同時還決定進入的syn連接) |
| net.ipv4.tcp_retries2 | 15 | 在丟棄激活(已建立通訊狀況)的TCP連接之前﹐需要進行多少次重試。默認值為15,根據RTO的值來決定,相當于13-30分鐘(RFC1122規定,必須大于100秒).(這個值根據目前的網絡設置,可以適當地改小,我的網絡內修改為了5) |
?
參考資料
http://blog.csdn.net/largetalk/article/details/16863689
轉載于:https://www.cnblogs.com/ulysses-you/p/7266594.html
總結
- 上一篇: [Step By Step]SAP Vi
- 下一篇: 应用场景的多样,奠定了区块链的未来