浅谈tcp的半打开连接

本文深入探讨了半打开连接的概念及形成原因,特别是在listen socket积压队列满时新连接的状态变化,包括不同Linux版本下的行为差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

tcp连接一端在进行完三次握手以后进入ESTABLISHED状态,如果连接的对端在某一时刻在网络中消失,而本端没有感知到,还是处于ESTABLISHED状态,那么本端的连接就被称为半打开连接(Half Open)。

连接的对端在网络中消失的情况有好多:

例如对端主机突然断电,tcp连接来不及发送任何信息就消失啦。

还有,连接路径上的某个nat设备aging-time过期,并且nat port被重用,虽然tcp连接的两端都还处于ESTABLISHED状态,可实际上两端的连接已经无法正常通信,此时这两端的连接都是半打开连接。(这种情况是我的猜测,还没有得到实践的检验。如果结论错误,就会修改掉!)

还有,listen socket的accept调用缓慢导致积压队列满,client端连接会成为半打开连接。这种情况是本次讨论的主题。

首先说下tcp的三次握手

浅谈tcp的半打开连接


server端的tcp连接在三次握手阶段会经历SYN_RECV状态到ESTABLISHED状态的变迁,其中SYN_RECV状态到连接存放于listen socket积压队列的半连接队列中,当连接由SYN_RECV状态变为ESTABLISHED状态,连接会被从半连接队列中移到已连接队列中。系统调用accept的作用就是从listen socket的已连接队列中取走一个连接,然后将该连接与进程绑定。

但是,如果listen socket的积压队列(半连接队列与连接队列)全部满后,对于新来的client连接会如何处理呢。答案是,linux不同版本的实现不同。

当前的实验环境:

zuchunlei@ubuntu14:~$ uname -a
Linux ubuntu14 4.4.0-31-generic #50~14.04.1-Ubuntu SMP Wed Jul 13 01:07:32 UTC 2016 x86_64 x86_64 x86

服务端代码:

In [1]: from socket import *
In [2]: sock = socket(AF_INET,SOCK_STREAM)
In [3]: sock.bind(("",10000))
In [4]: sock.listen(1)

为了简单,我将listen的backlog设置为1,并且不调用sock.accept方法。这样所有的ESTABLISHED状态的连接都存在积压队列中,并且没有和进程绑定起来。

使用netstat查看10000端口的状态:

Every 1.0s: sudo netstat -tnpoa|sed -n -e 2p -e /10000/p                                                                                                                                Sat Dec 16 20:23:03 2017

Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name Timer
tcp        0      0 0.0.0.0:10000           0.0.0.0:*               LISTEN      1578/python      off (0.00/0/0)

使用ss查看10000端口的状态:

Every 1.0s: ss -tnpoa|sed -n -e 1p -e /10000/p                                                                                                                                          Sat Dec 16 20:25:18 2017

State      Recv-Q Send-Q        Local Address:Port          Peer Address:Port
LISTEN     0      1                         *:10000                    *:*      users:(("ipython",1578,6))

解析一下,ss命令输出的State=Listen状态的数据时,其中Send-Q的大小表示该listen socket积压队列的长度,Recv-Q代表已完成三次握手,ESTABLISHED状态的连接个数。这样的连接存在于listen socket的已连接队列中。

用nc localhost 10000进行2次连接后,使用netstat查看10000端口的状态:

Every 1.0s: sudo netstat -tnpoa|
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

完颜振江

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值