前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >全连接队列和半连接队列

全连接队列和半连接队列

作者头像
opencode
发布2022-12-26 16:14:56
7030
发布2022-12-26 16:14:56
举报
文章被收录于专栏:知识同步

内核网络基础

大家对于 TCP 的三次握手应该都比较熟悉了,对于服务端,收到 SYN 包后该怎么处理,收到 Establish 之后又该怎么处理,或者说这些连接放在哪里,其实这也是之前面试问过的问题

我们在回顾下三次握手的流程图

*基本流程

上图是常见的三次握手流程,客户端调用 connect 函数后发送 SYN 报文,服务端收到后将连接信息加入半连接队列,也就是图中的 syns queue ,然后在收到最后来自客户端的的 ACK 报文后将其从半连接队列移除,加入全连接队列,也就是 accept queue ,然后服务端调用 accept 的时候会从全连接队列拿出一个来进行连接

*半连接队列(syn队列)长度

max(64, /proc/sys/net/ipv4/tcp_max_syn_backlog)

机器的 tcp_max_syn_backlog 值在 /proc/sys/net/ipv4/tcp_max_syn_backlog 下配置,在内核2.2之后默认值位2048

*全连接队列(accept队列)长度

min(backlog, somaxconn)

默认情况下, somaxconn 的值为 128,表示最多有 129 的 ESTAB 的连接等待 accept(),而 backlog 的值则应该是由 int listen(int sockfd, int backlog) 中的第二个参数指定,listen 里面的 backlog 可以由我们的应用程序去定义的

在Linux内核2.4.25之前,是写死在代码常量 SOMAXCONN ,在Linux内核2.4.25之后,在配置文件 /proc/sys/net/core/somaxconn 中直接修改,或者在 /etc/sysctl.conf 中配置 net.core.somaxconn = 128

*当 accept q 满了,syn q 中有连接完成时,需要转移进 accept q,该做什么样的处理?

在源码 net/ipv4/tcp_minisocks.c 中,这个行为是由 tcp_check_req 函数控制的:

代码语言:javascript
复制
child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL);
if (child == NULL)
goto listen_overflow;

再来看一眼 listen_overflow:

代码语言:javascript
复制
listen_overflow:
if (!sysctl_tcp_abort_on_overflow) {
inet_rsk(req)->acked = 1;
return NULL;
}

/proc/sys/net/ipv4/tcp_abort_on_overflow的值决定了后面的操作,0表示直接丢弃该ACK,1表示发送RST通知client;相应的,client则会分别返回read timeout 或者 connection reset by peer。

这说明除非设置了 /proc/sys/net/ipv4/tcp_abort_on_overflow 为 1 ,不然的话系统什么都不做。但是这个什么都不做,并不代表系统真的什么都不做了。当系统忽略了最后的 ACK,而系统中还有一个 net.ipv4.tcp_synack_retries 设置时,Linux 会重新发送 SYN ACK 包。而客户端收到多个 SYN ACK 包,则会认为之前的 ACK 丢包了。于是促使客户端再次发送 ACK ,在 accept q 有空闲的时候最终完成连接。若 accept q 始终满员,则最终客户端收到 RST 包。

同时 accept q 满了,对 syn q 也有影响,在代码 net/ipv4/tcp_ipv4.c :

代码语言:javascript
复制
/* Accept backlog is full. If we have already queued enough
* of warm entries in syn queue, drop request. It is better than
* clogging syn queue with openreqs with exponentially increasing
* timeout.
*/
if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) {
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS);
goto drop;
}

这说明如果 accept q 满了,系统会开始检查 SYN 包收到的频率,并且做出限制。如果达到了其定义的限制(我还不知道是如何定义的),变开始丢弃 syn q 中的包。我个人根据观察到的现象认为,其必须要满足 syn q 也已经被塞满这个条件,才会丢包。

*当 syn q 满了,系统还在不断的收到 SYN 包时,怎么处理?

在系统 syncookies=1 时,syn q 满了以后,系统会对 SYN 返回 syncookie 包。所返回的 SYN ACK 包会产生一个新的标志位 want_cookie。这个标志位默认为 0 ,但当要验证 cookies 时,want_cookie 会设置为 1. 发送的 cookie 数值是通过 cookie_v4_init_sequence() 函数计算出来的,在包发送出去后不维护该连接在服务器上的状态。这么做应该是为了节约服务器资源,毕竟其目的是为了判断对方是否是恶意攻击。 客户端拿到 cookie 数值后,通过计算,返回 cookies 数值,服务端获取到返回计算该数值是否合法。从而决定是否建立连接。

不开启syncookies的时候,Server会丢弃新来的SYN包,而Client端在多次重发SYN包得不到响应而返回(connection time out)错误

*参考链接:

tcp的半连接与完全连接队列

TCP全连接队列和半连接队列已满之后的连接建立过程抓包分析[转]

Linux SYN Backlog and somaxconn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-06-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • *基本流程
  • *半连接队列(syn队列)长度
  • *全连接队列(accept队列)长度
  • *当 accept q 满了,syn q 中有连接完成时,需要转移进 accept q,该做什么样的处理?
  • *当 syn q 满了,系统还在不断的收到 SYN 包时,怎么处理?
  • *参考链接:
相关产品与服务
云服务器
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档