副标题[/!--empirenews.page--]
前文介绍了TCP协议主要的流程,包括建立连接、传输数据和断开连接。如果大家认真阅读了附图,应该可以看到在各个流程中套接字的状态是在不断变化的,不同的状态标识了套集字所处的阶段。
如图1是TCP一个完整的状态转换图,图中包含了套接字的所有状态,以及发生状态转变的触发条件。可能会有人问,了解这些状态有什么用呢?我们平时编程又用不到。
图1 TCP状态转换图
为了说明上述问题,我们从3个角度进行解释,分别是各种状态的含义、在系统层面如何查询状态和在实际生产中的应用。
一、各种状态的含义
在回答问题之前我们先具体了解一下各个状态的含义。
- CLOSED:这个是套接字的初始状态,表示TCP连接是新建“未打开的”状态或者已经“关闭着的”。
- LISTEN :这个是服务端仅有的状态,表示服务器端的某个SOCKET处于监听状态,可以接受客户端的连接。
- SYN_RCVD :表示服务器接收到了来自客户端请求连接的SYN报文。在正常情况下,这个状态我们可能观察不到,因为这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂。
- SYN_SENT :这个状态与SYN_RCVD 状态相呼应,当客户端SOCKET执行connect()进行连接时,它首先发送SYN报文,然后随即进入到SYN_SENT 状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT 状态表示客户端已发送SYN报文。
- ESTABLISHED :表示TCP连接已经成功建立。
- FIN_WAIT_1 :这个状态得好好解释一下,其实FIN_WAIT_1 和FIN_WAIT_2 两种状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET进入到FIN_WAIT_1 状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2 状态。当然在实际的正常情况下,无论对方处于任何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1 状态一般是比较难见到的,而FIN_WAIT_2 状态有时仍可以用netstat看到。
- FIN_WAIT_2 :上面已经解释了这种状态的由来,实际上FIN_WAIT_2状态下的SOCKET表示半连接,即有一方调用close()主动要求关闭连接。注意:FIN_WAIT_2 是没有超时的(不像TIME_WAIT 状态),这种状态下如果对方不关闭(不配合完成4次挥手过程),那这个 FIN_WAIT_2 状态将一直保持到系统重启,越来越多的FIN_WAIT_2 状态会导致内核crash。
- TIME_WAIT :表示收到了对方的FIN报文,并发送出了ACK报文。 TIME_WAIT状态下的TCP连接会等待2*MSL(Max Segment Lifetime,最大分段生存期,指一个TCP报文在Internet上的最长生存时间。)在Linux可以通过cat /proc/sys/net/ipv4/tcp_fin_timeout看到本机的这个值,然后即可回到CLOSED 可用状态了。
- CLOSING :这种状态在实际情况中应该很少见,属于一种比较罕见的例外状态。正常情况下,当一方发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING 状态表示一方发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?那就是当双方几乎在同时close()一个SOCKET的话,就出现了双方同时发送FIN报文的情况,这是就会出现CLOSING 状态,表示双方都正在关闭SOCKET连接。
- CLOSE_WAIT :表示正在等待关闭。怎么理解呢?当对方close()一个SOCKET后发送FIN报文给自己,你的系统毫无疑问地将会回应一个ACK报文给对方,此时TCP连接则进入到CLOSE_WAIT状态。接下来呢,你需要检查自己是否还有数据要发送给对方,如果没有的话,那你也就可以close()这个SOCKET并发送FIN报文给对方,即关闭自己到对方这个方向的连接。有数据的话则看程序的策略,继续发送或丢弃。简单地说,当你处于CLOSE_WAIT 状态下,需要完成的事情是等待你去关闭连接。
- LAST_ACK :当被动关闭的一方在发送FIN报文后,等待对方的ACK报文的时候,就处于LAST_ACK 状态。当收到对方的ACK报文后,也就可以进入到CLOSED 可用状态了。
二、状态的监控方法
前文已经有提及,可以通过netstat命令查看TCP连接的状态。图2是一个简单的例子,执行该命令的时候不带任何参数。
图2 netstat执行结果
由上图可以看出,通过netstat可以看到每个TCP连接和UDP的状态和详细的IP地址等信息。该命令有很多参数,通过不同的参数可以得到我们想要的内容。下面我们举几个具体的例子。
1. 显示所有端口信息
可以通过-a参数列出所有端口信息,而且可以附带-t只列出TCP协议的,或者-u只列出UDP协议的端口信息。
- [root@itworld123~]# netstat -a # 列出所有端口
- [root@itworld123~]# netstat -at # 列出所有TCP端口
- [root@itworld123~]# netstat -au # 列出所有UDP端口
2. 显示所有监听状态的套接字
可以通过-l参数列出所有处于监听状态的套接字。当然也可以结合-t或者-u参数获取想要的信息。如下是获取TCP处于监听状态的套接字列表:
- root@itworld123:~# netstat -lu
图3 监听状态列表
3. 查看服务状态
(编辑:湘西站长网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|