TCP状态转换图解析
本文参考Unix网络编程卷1,对TCP状态转换进行总结,方便掌握TCP链接中各个状态及故障分析。
1.Linux下TCP相关工具
基于Linux系统查看网络状态,首先了解几个基本查看指令。
Linux查看网络状态的命令:
- netstat -nat 查看TCP各个状态的数量
- lsof -i:port , 可以检测到打开套接字的状况。lsof(list open files)列出当前系统打开的文本的工具。
- tcpdump -iany tcp port 9000 ,对tcp端口为9000的进行抓包。 tcpdump为Linux下的抓包工具。
- sar -n SOCK 查看tcp创建的连接数
网络测试使用的Linux命令:、
1.ping:检测网络连接的正常与否,主要是测试延时、抖动、丢包率。
ping命令使用ICMP协议,用于测试网络的连通性,可以通过接受到的返回值简单查看测试网络经过的路由数(由TTL值判断)及网络延迟时间。
2.traceroute: 跟踪数据包到达网络主机所经过的路由工具
使用方法:traceroute hostname
3.pathping:是一个路由跟踪工具,它将 ping 和 tracert 命令的功能与这两个工具所不提供的其他信息结合起来,综合了二者的功能。
使用方法:pathping www.baidu.com
4.mtr:以结合ping nslookup tracert 来判断网络的相关特性。
5.nslookup:用于解析域名,一般用来检测本机的DNS设置是否配置正确。
2.TCP状态
使用netstat命令查看TCP连接,在每个连接后会显示连接状态,各个状态说明如下:
2.SYN-SENT:再发送连接请求后等待匹配的连接请求(客户端发送连接请求后)
3.SYN-RECEIVED:再收到和发送一个连接请求后等待对方对连接请求的确认(服务端接收到SYN后发送确认,等待客户端对此确认的确认)
如果发现有很多SYN_RCVD状态,那你的机器有可能被SYN Flood的DoS(拒绝服务攻击)攻击了。
状态为ESTABLISHED表示此端口处于连接状态,正在进行数据传输。
客户端正常断开时会发送FIN报给服务端,此后服务端处于CLOSE_WAIT状态。
主动关闭(active close)端应用程序调用close,于是其TCP发出FIN请求主动关闭连接,之后进入FIN_WAIT1状态。
6.FIN-WAIT-2:从远程TCP等待连接中断请求(接收到FIN的ACK后)
主动关闭端接到ACK后,就进入了FIN-WAIT-2 状态。
7.CLOSE-WAIT:等待从本地用户发来的连接中断请求(服务端接收到FIN并发送ACK后)
服务端接收到远程客户端发送的FIN报并发送ACK进行确认后等待本地用户发送的中断请求期间处于CLOSE-WAIT状态。
8.CLOSING:等待远程TCP对连接中断的确认(尚不清楚状态)
不常见
9.LAST-ACK:等待原来的发向远程TCP的连接中断请求的确认(服务端发送FIN后等待客户端的ACK)
被动关闭端(服务端)一段时间后,接收到文件结束符的应用程序将调用CLOSE关闭连接。这导致它的TCP也发送一个 FIN,等待对方的ACK.就进入了LAST-ACK
10.TIME-WAIT:等待足够的时间以确保远程TCP接收到连接中断请求的确认(客户端接收到FIN后发送ACK,等待确保服务端接收到此ACK)
在客户端接收到FIN后,TCP就发送ACK包,并进入TIME-WAIT状态。
11.CLOSED:没有任何连接状态(服务端接收到ACK后进入)
3.TCP状态转换图
如下转换图展示了服务端和客户端的状态转换关系。
TCP连接中的3次握手及4次挥手示意图:
4.TCP状态转换中部分难点
1.什么是半打开连接?什么是半关闭连接?
TCP的半开连接(half-open)是指TCP连接的一端崩溃,或者在未通知对端的情况下移除socket,不可以正常收发数据,否则会产生RST。
TCP的半关闭是指TCP连接的一端调用shutdown操作使数据只能往一个方向流动,只有一方发送了FIN,仍然可以正常收(或发)数据。
2..为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?
这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发 送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下 都是分开发送的。
3.为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态?
这是因为虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样):
一方面是可靠的实现TCP全双工连接的终止,也就是当最后的ACK丢失后,被动关闭端会重发FIN,因此主动关闭端需要维持状态信息,以允许它重新发送最终的ACK。
另一方面,但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文,所以这个TIME_WAIT状态的作用 就是用来重发可能丢失的ACK报文。
TCP在2MSL等待期间,定义这个连接(4元组)不能再使用,任何迟到的报文都会丢弃。设想如果没有2MSL的限制,恰好新到的连接正好满足原先的4元组,这时候连接就可能接收到网络上的延迟报文就可能 干扰最新建立的连接。
4.发现系统存在大量TIME_WAIT状态的连接,可以通过调整内核参数解决:vi /etc/sysctl.conf 加入以下内容:
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 30
然后执行 /sbin/sysctl -p 让参数生效。
net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_fin_timeout 修改系統默认的 TIMEOUT 时间