tcp连接一端在进行完三次握手以后进入ESTABLISHED状态,如果连接的对端在某一时刻在网络中消失,而本端没有感知到,还是处于ESTABLISHED状态,那么本端的连接就被称为半打开连接(Half Open) 。
连接的对端在网络中消失的情况有好多:
【浅谈tcp的半打开连接】例如对端主机突然断电,tcp连接来不及发送任何信息就消失啦 。
还有,连接路径上的某个nat设备aging-time过期,并且nat port被重用,虽然tcp连接的两端都还处于ESTABLISHED状态,可实际上两端的连接已经无法正常通信,此时这两端的连接都是半打开连接 。(这种情况是我的猜测,还没有得到实践的检验 。如果结论错误,就会修改掉!)
还有,listen socket的accept调用缓慢导致积压队列满,client端连接会成为半打开连接 。这种情况是本次讨论的主题 。
首先说下tcp的三次握手
文章插图
server端的tcp连接在三次握手阶段会经历SYN_RECV状态到ESTABLISHED状态的变迁,其中SYN_RECV状态到连接存放于listen socket积压队列的半连接队列中,当连接由SYN_RECV状态变为ESTABLISHED状态,连接会被从半连接队列中移到已连接队列中 。系统调用accept的作用就是从listen socket的已连接队列中取走一个连接,然后将该连接与进程绑定 。
但是,如果listen socket的积压队列(半连接队列与连接队列)全部满后,对于新来的client连接会如何处理呢 。答案是,linux不同版本的实现不同 。
当前的实验环境:
zuchunlei@ubuntu14:~$ uname -aLinux 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/pSat Dec 16 20:23:03 2017Proto Recv-Q Send-Q Local AddressForeign AddressStatePID/Program name Timertcp00 0.0.0.0:100000.0.0.0:*LISTEN1578/Pythonoff (0.00/0/0)
使用ss查看10000端口的状态:Every 1.0s: ss -tnpoa|sed -n -e 1p -e /10000/pSat Dec 16 20:25:18 2017StateRecv-Q Send-QLocal Address:PortPeer Address:PortLISTEN01*: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|sed -n -e 2p -e /10000/pSat Dec 16 20:32:45 2017Proto Recv-Q Send-Q Local AddressForeign AddressStatePID/Program name Timertcp00 0.0.0.0:100000.0.0.0:*LISTEN1578/pythonoff (0.00/0/0)tcp00 127.0.0.1:59890127.0.0.1:10000ESTABLISHED 6301/ncoff (0.00/0/0)tcp00 127.0.0.1:10000127.0.0.1:59890ESTABLISHED -off (0.00/0/0)tcp00 127.0.0.1:10000127.0.0.1:59892ESTABLISHED -off (0.00/0/0)tcp00 127.0.0.1:59892127.0.0.1:10000ESTABLISHED 6379/ncoff (0.00/0/0)
netstat显示当前客户端程序nc连接已经建立完成,服务端的2个连接也处于ESTABLISHED状态,但因为当前没有accept调用,所以服务端的两个连接的进程PID显示为-,表示当前连接没有和进程绑定起来 。使用ss查看10000端口的状态:
Every 1.0s: ss -tnpoa|sed -n -e 1p -e /10000/pSat Dec 16 20:36:10 2017StateRecv-Q Send-QLocal Address:PortPeer Address:PortLISTEN21*:10000*:*users:(("ipython",1578,6))ESTAB00127.0.0.1:59890127.0.0.1:10000users:(("nc",6301,3))ESTAB00127.0.0.1:10000127.0.0.1:59890ESTAB00127.0.0.1:10000127.0.0.1:59892ESTAB00127.0.0.1:59892127.0.0.1:10000users:(("nc",6379,3))
通过ss可以看到,当前LISTEN状态的RECV-Q值为2,表示有2个ESTABLISHED状态的连接在已连接队列中等待应用层调用accept取走 。用nc localhost 10000进行第三次连接后,netstat查看10000端口的状态:
Every 1.0s: sudo netstat -tnpoa|sed -n -e 2p -e /10000/pSat Dec 16 20:41:18 2017Proto Recv-Q Send-Q Local AddressForeign AddressStatePID/Program name Timertcp00 0.0.0.0:100000.0.0.0:*LISTEN1578/pythonoff (0.00/0/0)tcp00 127.0.0.1:59890127.0.0.1:10000ESTABLISHED 6301/ncoff (0.00/0/0)tcp00 127.0.0.1:10000127.0.0.1:59896SYN_RECV-on (1.06/3/0)tcp00 127.0.0.1:59896127.0.0.1:10000ESTABLISHED 10989/ncoff (0.00/0/0)tcp00 127.0.0.1:10000127.0.0.1:59890ESTABLISHED -off (0.00/0/0)tcp00 127.0.0.1:10000127.0.0.1:59892ESTABLISHED -off (0.00/0/0)tcp00 127.0.0.1:59892127.0.0.1:10000ESTABLISHED 6379/ncoff (0.00/0/0)
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 苍蝇和蚊子的外形特征 蚊子和苍蝇的相同点
- 芈月传姝公主第几集死的 芈月传太子荡哪集死
- 火星内部是热的吗 火星的热度
- 这颗奇特恒星的发现了人类对天体 恒星最终将演化成哪些天体
- 七牛云的免费SSL证书申请和用法
- 每个程序员都应该知晓的核心搜索算法
- 科研团队在银河系中发现两个孕育恒星的巨大分子云 发射星云是星云气体反射及散射附近恒星可见光而亮的
- 虚拟主机和云主机的区别是什么?
- 来自远古的巨人 超远古巨人
- 张开嘴的蛇 蛇张开嘴巴