久久ER99热精品一区二区-久久精品99国产精品日本-久久精品免费一区二区三区-久久综合九色综合欧美狠狠

新聞中心

EEPW首頁 > 嵌入式系統 > 設計應用 > Linux協議棧accept和syn隊列問題

Linux協議棧accept和syn隊列問題

作者: 時間:2016-10-08 來源:網絡 收藏

環境:

本文引用地址:http://cqxgywz.com/article/201610/305659.htm

Client 通過tcp 連接server,server端只是listen,但是不調用accept。通過netstat –ant查看兩端的連接情況。

server端listen,不調用accept。

client一直去connect server。

問題:

運行一段時間后,為什么server端的ESTABLISHED連接的個數基本是固定的129個,但是client端的ESTABLISHED連接的個數卻在不斷增加?

分析

Linux內核協議棧為一個tcp連接管理使用兩個隊列,一個是半鏈接隊列(用來保存處于SYN_SENT和SYN_RECV狀態的請求),一個是accpetd隊列(用來保存處于established狀態,但是應用層沒有調用accept取走的請求)。

第一個隊列的長度是/proc/sys/net/ipv4/tcp_max_syn_backlog,默認是1024。如果開啟了syncookies,那么基本上沒有限制。

第二個隊列的長度是/proc/sys/net/core/somaxconn,默認是128,表示最多有129個established鏈接等待accept。(為什么是129?詳見下面的附錄1)。

現在假設acceptd隊列已經達到129的情況:

client發送syn到server。client(SYN_SENT),server(SYN_RECV)

server端處理流程:tcp_v4_do_rcv--->tcp_rcv_state_process--->tcp_v4_conn_request

if(sk_acceptq_is_full(sk) inet_csk_reqsk_queue_yong(sk)>1)

goto drop;

inet_csk_reqsk_queue_yong(sk)的含義是請求隊列中有多少個握手過程中沒有重傳過的段。

在第一次的時候,之前的握手過程都沒有重傳過,所以這個syn包server端會直接drop掉,之后client會重傳syn,當inet_csk_reqsk_queue_yong(sk) 1,那么這個syn被server端接受。server會回復synack給client。這樣一來兩邊的狀態就變為client(ESTABLISHED), server(SYN_SENT)

Client收到synack后回復ack給server。

server端處理流程: tcp_check_req--->syn_recv_sock-->tcp_v4_syn_recv_sock

if(sk_acceptq_is_full(sk)

goto exit_overflow;

如果server端設置了sysctl_tcp_abort_on_overflow,那么server會發送rst給client,并刪除掉這個鏈接;否則server端只是記錄一下LINUX_MIB_LISTENOVERFLOWS(詳見附錄2),然后返回。默認情況下是不會設置的,server端只是標記連接請求塊的acked標志,之后連接建立定時器,會遍歷半連接表,重新發送synack,重復上面的過程(具體的函數是inet_csk_reqsk_queue_prune),如果重傳次數超過synack重傳的閥值(/proc/sys/net/ipv4/tcp_synack_retries),會把該連接從半連接鏈表中刪除。

一次異常問題分析

Nginx通過FASTCGI協議連接cgi程序,出現cgi程序read讀取socket內容的時候永遠block。通過netstat查看,cgi程序所在的服務器上顯示連接存在,但是nginx所在的服務器上顯示不存在該連接。

下面是原始數據圖:

我們從上面的數據流來分析一下:

出現問題的時候,cgi程序(tcp server端)處理非常慢,導致大量的連接請求放到accept隊列,把accept隊列阻塞。

148021 nginx(tcp client端) 連接cgi程序,發送syn

此時server端accpet隊列已滿,并且inet_csk_reqsk_queue_yong(sk) > 1,server端直接丟棄該數據包

148840 client端等待3秒后,重傳SYN

此時server端狀態與之前送變化,仍然丟棄該數據包

150163 client端又等待6秒后,重傳SYN

此時server端accept隊列仍然是滿的,但是存在了重傳握手的連接請求,server端接受連接請求,并發送synack給client端(150164)

150166 client端收到synack,標記本地連接為ESTABLISHED狀態,給server端應答ack,connect系統調用完成。

Server收到ack后,嘗試將連接放到accept隊列,但是因為accept隊列已滿,所以只是標記連接為acked,并不會將連接移動到accept隊列中,也不會為連接分配sendbuf和recvbuf等資源。

150167 client端的應用程序,檢測到connect系統調用完成,開始向該連接發送數據。

Server端收到數據包,由于acept隊列仍然是滿的,所以server端處理也只是標記acked,然后返回。

150225 client端由于沒有收到剛才發送數據的ack,所以會重傳剛才的數據包

150296 同上

150496 同上

150920 同上

151112 server端連接建立定時器生效,遍歷半連接鏈表,發現剛才acked的連接,重新發送synack給client端。

151113 client端收到synack后,根據ack值,使用SACK算法,只重傳最后一個ack內容。

Server端收到數據包,由于accept隊列仍然是滿的,所以server端處理也只是標記acked,然后返回。

151896 client端等待3秒后,沒有收到對應的ack,認為之前的數據包也丟失,所以重傳之前的內容數據包。

152579 server端連接建立定時器生效,遍歷半連接鏈表,發現剛才acked的連接,synack重傳次數在閥值以內,重新發送synack給client端。

152581 cient端收到synack后,根據ack值,使用SACK算法,只重傳最后一個ack內容。

Server端收到數據包,由于accept隊列仍然是滿的,所以server端處理也只是標記acked,然后返回

153455 client端等待3秒后,沒有收到對應的ack,認為之前的數據包也丟失,所以重傳之前的內容數據包。

155399 server端連接建立定時器生效,遍歷半連接鏈表,發現剛才acked的連接,synack重傳次數在閥值以內,重新發送synack給client端。

155400 cient端收到synack后,根據ack值,使用SACK算法,只重傳最后一個ack內容。

Server端收到數據包,由于accept隊列仍然是滿的,所以server端處理也只是標記acked,然后返回。

156468 client端等待幾秒后,沒有收到對應的ack,認為之前的數據包也丟失,所以重傳之前的內容數據包。

161309 server端連接建立定時器生效,遍歷半連接鏈表,發現剛才acked的連接,synack重傳次數在閥值以內,重新發送synack給client端。


上一頁 1 2 下一頁

關鍵詞:

評論


相關推薦

技術專區

關閉