TCP(二)

TCP半鏈接和全鏈接問題html

 

TCP握手過程詳解算法

 

 

如上圖所示,關鍵部分:syns queue(半鏈接隊列)和accept queue(全鏈接隊列)數據庫

正常狀況下的處理過程以下:apache

1)當server端收到client發送的SYN後,將鏈接相關信息放在syns queue中,並回復SYN+ACK;centos

2)當server端收到client發送的ACK後,將鏈接相關信息從syns queue中取出並放在accept queue中。服務器

 異常狀況:併發

步驟2)中若是accept queue滿了,則根據tcp_abort_on_overflow指定的策略執行socket

  若是tcp_abort_on_overflow爲0,server丟棄client發送的ack,而且在一段時間後再次發送syn+ack給client(即從新走握手的第二步),若是cilent的超時時間比較短,就會出現異常;重試次數由net.ipv4.tcp_synack_retries指定(centos默認5次);tcp

  若是tcp_abort_on_overflow爲1,server將發送一個reset給client,表示要廢掉此次握手過程和鏈接。此時client應該會出現connection reset by peer異常。性能

 

怎麼查看隊列是否滿?

netstat -s

  該命令查看每一個協議的統計數據

netstat -s | egrep "listen" 

  若是看到:XXXX times the listen queue of a socket overflowed 而且XXXX 值在不斷增長,就說明有全鏈接隊列偶爾滿了。

ss -lnt | grep port

State         Recv-Q      Send-Q        Local Address:Port        Peer Address:Port
LISTEN     0                50                :::9188                            :::*

其中Send-Q爲監聽9188端口的全鏈接隊列最大爲50,Recv-Q表示全鏈接隊列中和等待進入全鏈接的數量。

全鏈接隊列的大小取決於:min(backlog, somaxconn) . backlog是在socket建立的時候傳入的(Java Socket默認爲50),somaxconn是一個os級別的系統參數

半鏈接隊列的大小取決於:max(64, /proc/sys/net/ipv4/tcp_max_syn_backlog)。 不一樣版本的os會有些差別.

 

 

 

 

CLOSE-WAIT問題

 

什麼狀況下會出現CLOSE-WAIT狀態

  在被動關閉鏈接時,已經收到對方發來的FIN(併發送了ACK),但尚未發送本身的FIN時,處於CLOSE_WAIT狀態。

 

正常狀況下該狀態持續的時間應該很短,出現大量close_wait的現象,主要緣由是某種狀況下對方關閉了socket連接,可是我方忙與讀或者寫,沒有關閉鏈接。

 

產生該問題的例子:https://blog.csdn.net/yu616568/article/details/44677985

  首先,我這邊的大部分請求都須要查詢數據庫,個人數據庫鏈接池設置的最大鏈接數是100,因此每個請求建立了一個鏈接,等到100個請求就把鏈接池佔滿了,可是處理servlet的那個線程並無釋放這個鏈接,因而接下來的請求再去建立數據庫鏈接的時候就會一直阻塞在那裏,這裏我所用的是DBCP做爲鏈接池的,它的實現好像是使用apache的objectPool來實現的,若是沒有可用的鏈接對象會致使線程等待,好了,servlet因爲得不到數據庫鏈接而阻塞了,這個客戶端的請求就一直等待,客戶端使用httpclient設置了5s的請求超時時間,那麼超時以後就會拋出異常,關閉鏈接,關閉鏈接致使客戶端發送了FIN報文,我這邊的TCP/IP返回了ACK報文,可是因爲處理請求的線程還處於阻塞的狀態,因此當前的鏈接狀態時CLOSE_WAIT。

 

解決方法
基本的思想就是要檢測出對方已經關閉的socket,而後關閉它

1.代碼須要判斷socket,一旦read返回0,斷開鏈接,read返回負,檢查一下errno,若是不是AGAIN,也斷開鏈接。(注:在UNP 7.5節的圖7.6中,能夠看到使用select可以檢測出對方發送了FIN,再根據這條規則就能夠處理CLOSE_WAIT的鏈接)
2.給每個socket設置一個時間戳last_update,每接收或者是發送成功數據,就用當前時間更新這個時間戳。按期檢查全部的時間戳,若是時間戳與當前時間差值超過必定的閾值,就關閉這個socket。
3.使用一個Heart-Beat線程,按期向socket發送指定格式的心跳數據包,若是接收到對方的RST報文,說明對方已經關閉了socket,那麼咱們也關閉這個socket。
4.設置SO_KEEPALIVE選項,並修改內核參數

 

 

 

 

TCP協議在帶寬利用率、性能方面的優化 

 

delay ack

  

Nagle算法

 

 

 

參考資料

服務器TIME_WAIT和CLOSE_WAIT詳解和解決辦法

CLOSE_WAIT狀態的緣由與解決方法

關於TCP 半鏈接隊列和全鏈接隊列

就是要你懂 TCP | 最經典的TCP性能問題

相關文章
相關標籤/搜索