您的位置 首页 传感器

Linux协议栈accept和syn行列问题

环境:Client 通过tcp 连接server,server端只是listen,但是不调用accept。通过netstat –ant查看两端的连接情况。server端listen,不调

环境:

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端。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/yingyong/chuanganqi/298049.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部