TCP的半连接队列与全连接队列

作者 : 开心源码 本文共2346个字,预计阅读时间需要6分钟 发布时间: 2022-05-12 共153人阅读

首先我们根据下图,理解TCP三次握手与TCP队列之间的联络

第一次握手

client发送SYN给server,server收到来自client的SYN后,就把相关信息放入到syns queue

第二次握手

server发送SYN、ACK给client

第三次握手

client收到来自server的SYN、ACK后,发送确认包ACK给server,server收到client的ack,假如这时全连接队列没满,那么从半连接队列拿出相关信息放入到全连接队列中,否则按tcp_abort_on_overflow指示的执行

# 查看tcp_abort_on_overflow的状态# cat /proc/sys/net/ipv4/tcp_abort_on_overflow—— tcp_abort_on_overflow 为0表示过一段时间后重新向client发送ACK+SYN(重复第二次握手)——tcp_abort_on_overflow 为1表示第三握手时假如全连接队列满了,server发送一个reset包给client,表示废掉这个握手过程和这个连接,用户端异常中可以看到connection reset by peer的错误

也就是说,client进行connect之后先进入server的半连接队列,client就直接进入established状态,假如server的全连接队列(accept队列)未满,则将其放入全连接队列(未被应使用层进行accpet函数调使用取走),而后server也进入established状态。假如全连接队列满了,则server停留在syn_recv状态。

队列的类型

socket接收的所有连接都存放在队列类型中,队列有以下两种:

  • syns queue(半连接队列,使用来保存处于SYN_SENT和SYN_RECV状态的请求)
  • accept queue(全连接队列,使用来保存处于established状态,但是应使用层没有调使用accept取走的请求)
队列的长度是由以下参数决定的:
  • 全连接队列的最大值取决于:min(backlog, /proc/sys/net/core/somaxconn),在linux内核2.2版本以后,backlog参数控制的accept queue的大小,backlog是在socket创立的时候传入的,属于listen函数里的参数;somaxconn是内核的参数,默认是128
  • 半连接队列的最大值取决于:max(/proc/sys/net/ipv4/tcp_max_syn_backlog),CentOS7默认为512,当启使用syncookies时,没有逻辑最大长度,忽略tcp_max_syn_backlog设置,syncookies的设置可以防范SYN flood攻击,查看syncookies能否启动:
# cat  /proc/sys/net/ipv4/tcp_syncookies# 假如是“1”说明已启使用,为“0”说明未启使用
为什么全连接队列由backlog与somaxconn的最小值决定呢?

其实,backlog可以比喻为酒店的大厅,somaxconn可以比喻为大厅里的座位,能服务的人数由大厅里的座位数决定,但大厅里的座位的多少又由大厅的大小而决定,所以服务端能接收的完整连接数上限是由backlog和somaxconn的最小值而决定。listen方法指定的backlog是在使用户态指定的,内核态的参数优先级高于使用户态参数,所以即便在listen方法里面指定backlog是一个大于somaxconn的值,socket在内核态运行时还会检查一次somaxconn,假如连接数超过somaxconn就会等待。

当全连接队列已满且半连接队列未满的情况下:

当用户端发起一个syn分节时,服务端不会丢弃该syn分节,而是直接响应ack和syn,这时用户端响应ack,并成为established状态,而服务端收到ack响应后,试图将该syn分节从半连接队列中移除,并加入全链接队列,而后因为全连接队列已经满了,这时,在默认情况下,服务端啥也不做,而且不会将该连接由SYN_RECV变成ESTABLISHED,服务端仅仅只是创立一个定时器,以固定间隔重传syn和ack到用户端,直到到达系统默认的synack重传阖值,而后服务端将处于半连接队列里面的syn分节丢弃。

当全连接已满且半连接队列也满的情况下:

当用户端发起一个syn分节时,服务端发现半连接队列已经满了,同时该syn分节尚未重传过,服务端直接丢弃该syn分节,而后用户端过了4秒重传syn分节,这个时候服务端发现半连接队列已满同时,该syn分节已经重传过了,服务端收下了该syn分节,并响应用户端syn+ack,用户端收到syn+ack后,响应ack。用户端三次握手已经完成,而服务端收到ack之后,发现全连接队列是满的,这个时候不会将该连接从SYN_RECV转换成ESTABLISHED,服务端创立定时器,定时重传syn+ack, 直到到达系统默认的synack重传阖值,而后服务端将处于半连接队列里面的syn分节丢弃

TCP连接队列溢出指标
# cat /proc/net/netstat | awk '/TcpExt/ { print $21,$22 }'ListenOverflows ListenDrops165 165

Tcp ListenOverflows tcp_v4_syn_recv_sock():三路握手最后一步完全之后,Accept queue队列超过上限时加1
Tcp ListenDrops tcp_v4_syn_recv_sock():任何起因,包括Accept queue超限,创立新连接,继承端口失败等,加1

参考文章1
参考文章2

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » TCP的半连接队列与全连接队列

发表回复