TCP相关内容 4 | 青训营

99 阅读2分钟

TCP相关内容 4 | 青训营

最后一篇文章了,青训营也结束了,我接着尝试总结一下TCP半连接的一些内容。

在TCP三次握手时,Linux的内核围护了半连接队列(SYN队列)和全连接队列(accept队列)。他们有不同的作用,大致放入工作流程是这样的。当服务端收到SYN请求时,内核会自动将这个链接储存在半连接队列,随后给客户端发送响应 SYN + ACK ,接着客户端会回复 ACK报文,当服务端收到第三次握手的ACK报文后,内核就会把储存在半连接队列的连接移除出去,然后创建新的完全的连接,并将其添加到 accept 队列,等待进程调用 accept 函数时把连接取出来。

半连接既然是在内核维护的,那么他就一定有大小的限制,但是Linux并没有直接的命令可以查看TCP 半连接队列长度的长度,我们可以认为服务端处于 SYN_RECV 状态的 TCP 连接,就是 TCP 半连接队列的长度。如果超过这个长度,就是对服务端一直发送 TCP SYN 包,但是不回第三次握手 ACK,这样就会使得服务端有大量的处于 SYN_RECV 状态的 TCP 连接(所谓的 SYN 洪泛、SYN 攻击、DDos 攻击),有点像只敲门不进门的感觉,对于个人网站可能对白白耗费流量。服务端受到 SYN 攻击后,半连接队列移除,会丢弃很多 TCP 连接。半连接队列最大值不是单单由 max_syn_backlog 决定,还跟 somaxconn(128默认值) 和 backlog (Nginx 默认值511)有关系:如果 max_syn_backlog > min(somaxconn, backlog),半连接最大长度为min(somaxconn, backlog) * 2。如果 max_syn_backlog <= min(somaxconn, backlog),半连接最大长度(max_qlen_log)为max_syn_backlog 2 。当然这只是理论值,服务端处于 SYN_RECV 状态的最大个数并不是 max_qlen_log 变量的值。原因是因为:若没有开启 tcp_syncookies,并且 max_syn_backlog 减去 当前半连接队列长度小于 (max_syn_backlog >> 2) ,就依然会丢弃SYN包,这样开来开启tcp_syncookies 有助于防御SYN攻击。

半连接队列如果满了,但要是开启了syncookies 功能就可以在不使用 SYN 半连接队列的情况下成功建立连接。

待续...