Socket `accept queue is full ` 但是一个连接需要从SYN->ACCEPT
由于标题长度有限制,我把想要描述的问题再次描述下:
内核通常会为每一个LISTEN
状态的Socket
维护两个队列:
1 accept
队列: listen()
函数第二个参数BACKLOG
指定,表示已完成连接的队列,等待被accept
函数取走。
2 SYN
队列:由/proc/sys/net/ipv4/tcp_max_syn_backlog
指定,表示处于SYN_RECV
状态的队列。
如果没有概念,参考:
http://blog.csdn.net/yangbodong22011/article/details/60399728
现在的问题是:
如果accept
队列已经满了,并且服务器没有使用accept
函数取走任何连接,那么当一个连接需要从SYN队列
移动到accept
队列时会发生什么?
正确的解释
答案来源:
http://veithen.github.io/2014/01/01/how-tcp-backlog-works-in-linux.html
下面的部分我翻译自作者原文:
This case is handled by the
tcp_check_req
function innet/ipv4/tcp_minisocks.c
, The relevant code reads:
这种情况由net/ipv4/tcp_minisocks.c
中的tcp_check_req
函数处理,相关代码如下:
child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL);
if (child == NULL)
goto listen_overflow;
For IPv4, the first line of code will actually call tcp_v4_syn_recv_sock in net/ipv4/tcp_ipv4.c, which contains the following code:
对于IPv4,第一行代码实际上将调用net/ipv4/tcp_ipv4.c
中的tcp_v4_syn_recv_sock
,其中包含以下代码:
if (sk_acceptq_is_full(sk))
goto exit_overflow;
We see here the check for the accept queue. The code after the
exit_overflow
label will perform some cleanup, update theListenOverflows
andListenDrops
statistics in/proc/net/netstat
and then returnNULL
. This will trigger the execution of thelisten_overflow
code intcp_check_req
:
我们在这里看到了对于accept
队列的检查。 exit_overflow
的代码将执行一些清理,更新/proc/net/netstat
中的ListenOverflows
和ListenDrops
统计信息,然后返回NULL
。 这将触发在tcp_check_req
中执行listen_overflow
代码:
listen_overflow:
if (!sysctl_tcp_abort_on_overflow) {
inet_rsk(req)->acked = 1;
return NULL;
}
This means that unless /proc/sys/net/ipv4/tcp_abort_on_overflow is set to 1 , the implementation basically does… nothing!
这意味着只要/proc/sys/net/ipv4/tcp_abort_on_overflow
被设置为1
,在上面的if (!sysctl_tcp_abort_on_overflow)
判断中为0,就不会执行下面代码,也就是Linux的策略是 : 什么都不干!!!!
备注:
这里的什么都不干对应的是:回应RST包
,客户端出现connection reset by peer
。
To summarize, if the TCP implementation in Linux receives the ACK packet of the 3-way handshake and the accept queue is full, it will basically ignore that packet. At first, this sounds strange, but remember that there is a timer associated with the SYN RECEIVED state: if the ACK packet is not received (or if it is ignored, as in the case considered here), then the TCP implementation will resend the SYN/ACK packet (with a certain number of retries specified by /proc/sys/net/ipv4/tcp_synack_retries and using an exponential backoff algorithm).
总而言之,如果Linux
中的TCP
接收到3次握手的ACK数据包
,并且接受队列已满,它将基本上忽略该数据包。 这听起来很奇怪,但是记住有一个与SYN RECEIVED状态相关联的定时器:如果没有收到ACK
分组(在这里我们考虑的情况是ACK被忽略,就和没有收到是一样的),则TCP
将重新发送 SYN/ACK
数据包(由/proc/sys/net/ipv4/tcp_synack_retries
指定次数)。
备注:我的电脑是5
Since the TCP implementation on the client side gets multiple SYN/ACK packets, it will assume that the ACK packet was lost and resend it (see the lines with TCP Dup ACK in the above trace). If the application on the server side reduces the backlog (i.e. consumes an entry from the accept queue) before the maximum number of SYN/ACK retries has been reached, then the TCP implementation will eventually process one of the duplicate ACKs, transition the state of the connection from SYN RECEIVED to ESTABLISHED and add it to the accept queue. Otherwise, the client will eventually get a RST packet (as in the sample shown above).
由于客户端收到多个SYN/ACK
分组,它将假定ACK
分组丢失并重新发送它。 如果在达到最大SYN/ACK
重试次数之前,服务器侧的应用程序减少了Accept队列大小
(即调用accept
来取接受队列的条目),则TCP
将最终处理重复ACK
中的一个,转变状态从SYN RECEIVED
到ESTABLISHED
的连接,并将其添加到accept
队列。 否则,客户端将最终收到RST
分组。
实验验证
验证环境:
RedHat 7
Linux version 3.10.0-514.el7.x86_64
验证思路:
- 模拟一个”忙”的服务器,保证它的
accept队列被占满
。 - 再用客户端连接。
使用wireshark
抓包情况如下所示(在新的标签页打开图片):
- 前三个包是三次握手,143是客户端,155是服务器。
- 但是155服务器此时
accept队列
是满的,虽然143和它完成了三次握手,但是它仍然不能从SYN RECEIVED
状态转换到ESTABLISHED
状态。 - 此时由于
SYN RECEIVED
状态的定时器机制,服务器155没有收到ACK
分组的时候(实际上是直接扔掉了),会继续给客户端143发送SYN/ACK
数据包,143以为服务器没有收到ACK
,然后回复ACK,这也就是”黑色”的包为什么有10个的原因了,服务器发送的SYN/ACK
有5个,客户端回复的ACK
有5个,就是/proc/sys/net/ipv4/tcp_synack_retries
定义的。
我的疑问:
按道理,客户端最后是会收到服务器端发送的RST
数据包的。但是我不知道多长时间之后会发,于是我等了很久(2小时)。此时服务器端通过netstat
命令查看已经没有任何客户端的连接信息了,但是客户端查看和服务器的连接却是ESTABLISHED
状态。很奇怪,这样的话客户端什么时候退出呢? 难道它一直卡在那里?
ps : 重新测了以下,服务器丢掉SYN RECEIVED
状态的客户端时间大概是1分钟,也就是客户端连接过来,服务器Accept队列满
的话,大概一分钟之后服务器就会丢失这个连接。但是此时客户端维持着一条ESTABLISHED
状态的连接~~,它到底什么时候释放呢?
Socket `accept queue is full ` 但是一个连接需要从SYN->ACCEPT的更多相关文章
- 非阻塞socket调用connect, epoll和select检查连接情况示例
转自http://www.cnblogs.com/yuxingfirst/archive/2013/03/08/2950281.html 我们知道,linux下socket编程有常见的几个系统调用: ...
- python socket编程---从使用Python开发一个Socket示例说到开发者的思维和习惯问题
今天主要说的是一个开发者的思维和习惯问题. 思维包括编程的思维和解决一个具体问题的分析思维,分析思路,分析方法,甚至是分析工具. 无论是好习惯还是不好的习惯,都是在者一天一天的思维中形成的.那些不好的 ...
- 网络编程-socket(三)(TCP长连接和UDP短连接、时间服务器)
详解地址:https://www.cnblogs.com/mys6/p/10587673.html TCP server端 import socketsk = socket.socket() # 创建 ...
- listen - listen for connections on a socket 在一个套接字上倾听连接
SYNOPSIS 概述 #include <sys/socket.h> int listen(int s, int backlog); DESCRIPTION 描述 在接收连接之前,首先要 ...
- 【网络通信】服务器端Socket监听80端口,建立连接传输数据时也是使用的80端口么?
1. 服务器端Socket监听80端口,建立连接传输数据时也是使用的80端口么? 答:对.建立连接时服务器会分配一个新的Socket,但是用的源端口号还是80端口.套接字是由协议类型.源IP.目的IP ...
- Socket 传一幅图片给另一个终端
练习Socket传文件,先添加一个组件,简化socket发送和接收文件, 获取IP和端口的类 public static class AddressHelper { /// <summary&g ...
- android:Faild to install,你的主机中的软件终止了一个连接错误解决
当在用真机调试android程序时出现Faild to install,你的主机中的软件终止了一个连接错误时可以这样解决: 在手机开启usb调试和安装未知来源软件的情况下: 1:先查进入任务管理器查看 ...
- nginx和apache最核心的区别在于apache是同步多进程模型,一个连接对应一个进程;nginx是异步的,多个连接(万级别)可以对应一个进程
nginx和apache的一些优缺点比较,摘自网络,加自己的一些整理. nginx相对于apache的优点: 1.轻量级,同样是web 服务,比apache 占用更少的内存及资源 2.抗并发,ngin ...
- TCP报文格式和三次握手——三次握手三个tcp包(header+data),此外,TCP 报文段中的数据部分是可选的,在一个连接建立和一个连接终止时,双方交换的报文段仅有 TCP 首部。
from:https://blog.csdn.net/mary19920410/article/details/58030147 TCP报文是TCP层传输的数据单元,也叫报文段. 1.端口号:用来标识 ...
随机推荐
- stmt.executeQuery不执行解决办法
感谢博主分享:https://blog.csdn.net/lxmky/article/details/4705698 今天在Eclipse下编写jsp网页时,出现一个问题,主要是stmt.execut ...
- centos查找大文件
首先到相当的目录下面,按下面方式查找 find . -type f -size +800M -print0 | xargs -0 ls -lah或者从根目录(/)开始查找find / -type f ...
- MySQL数据库连接重试功能和连接超时功能的DB连接Python实现
def reConndb(self): # 数据库连接重试功能和连接超时功能的DB连接 _conn_status = True _max_retries_count = 10 # 设置最大重试次数 _ ...
- JS获取contextPath的方法
function getContextPath() { var pathName = document.location.pathname; var index = pathName.subst ...
- 自然语言处理标注工具——Brat(安装、测试、使用)
一.Brat标注工具安装 1.安装条件: (1)运行于Linux系统(window系统下虚拟机内linux系统安装也可以) (2)目前brat最新版本(v1.3p1)仅支持python2版本运行使用( ...
- 多图详解万星 Restful 框架原理与实现
rest框架概览 我们先通过 go-zero 自带的命令行工具 goctl 来生成一个 api service,其 main 函数如下: func main() { flag.Parse() var ...
- VulnHub 实战靶场Breach-1.0
相比于CTF题目,Vulnhub的靶场更贴近于实际一些,而且更加综合考察了知识.在这里记录以下打这个靶场的过程和心得. 测试环境 Kali linux IP:192.168.110.128 Breac ...
- React Native之新架构中的Turbo Module实现原理分析
有段时间没更新博客了,之前计划由浅到深.从应用到原理,更新一些RN的相关博客.之前陆续的更新了6篇RN应用的相关博客(传送门),后边因时间问题没有继续更新.主要是平时空余时间都用来帮着带娃了,不过还是 ...
- vue3 element-plus 配置json快速生成form表单组件,提升生产力近600%(已在公司使用,持续优化中)
️本文为博客园社区首发文章,未获授权禁止转载 大家好,我是aehyok,一个住在深圳城市的佛系码农♀️,如果你喜欢我的文章,可以通过点赞帮我聚集灵力️. 个人github仓库地址: https:gi ...
- 80. 删除有序数组中的重复项 II
题目 给你一个有序数组 nums ,请你原地删除重复出现的元素(不需要考虑数组中超出新长度后面的元素),使每个元素最多出现两次 ,返回删除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入 ...