一、Linux服务器上11种网络连接状态:
通常情况下,一个正常的TCP连接,都会有三个阶段:1、TCP三次握手; 2、数据传送; 3、TCP四次挥手 注:以下说明最好能结合”图:TCP的状态机”来理解。 SYN: (同步序列编号,Synchronize Sequence Numbers)该标志仅在三次握手建立TCP连接时有效。表示一个新的TCP连接请求。 ACK: (确认编号,Acknowledgement Number)是对TCP请求的确认标志,同时提示对端系统已经成功接收所有数据。 FIN: (结束标志,FINish)用来结束一个TCP回话.但对应端口仍处于开放状态,准备接收后续数据。
1)、LISTEN:首先服务端需要打开一个socket进行监听,状态为LISTEN. /* The socket is listening for incoming connections. 侦听来自远方TCP端口的连接请求 */ 3)、SYN_RECV:服务端应发出ACK确认客户端的SYN,同时自己向客户端发送一个SYN. 之后状态置为SYN_RECV /* A connection request has been received from the network. 在收到和发送一个连接请求后等待对连接请求的确认 */ 4)、ESTABLISHED: 代表一个打开的连接,双方可以进行或已经在数据交互了。/* The socket has an established connection. 代表一个打开的连接,数据可以传送给用户 */ 5)、FIN_WAIT1:主动关闭(active close)端应用程序调用close,于是其TCP发出FIN请求主动关闭连接,之后进入FIN_WAIT1状态./* The socket is closed, and the connection is shutting down. 等待远程TCP的连接中断请求,或先前的连接中断请求的确认 */ 6)、CLOSE_WAIT:被动关闭(passive close)端TCP接到FIN后,就发出ACK以回应FIN请求(它的接收也作为文件结束符传递给上层应用程序),并进入CLOSE_WAIT. /* The remote end has shut down, waiting for the socket to close. 等待从本地用户发来的连接中断请求 */ 7)、FIN_WAIT2:主动关闭端接到ACK后,就进入了FIN-WAIT-2 ./* Connection is closed, and the socket is waiting for a shutdown from the remote end. 从远程TCP等待连接中断请求 */ 8)、LAST_ACK:被动关闭端一段时间后,接收到文件结束符的应用程序将调用CLOSE关闭连接。这导致它的TCP也发送一个 FIN,等待对方的ACK.就进入了LAST-ACK . /* The remote end has shut down, and the socket is closed. Waiting for acknowledgement. 等待原来发向远程TCP的连接中断请求的确认 */ 9)、TIME_WAIT:在主动关闭端接收到FIN后,TCP就发送ACK包,并进入TIME-WAIT状态。/* The socket is waiting after close to handle packets still in the network.等待足够的时间以确保远程TCP接收到连接中断请求的确认 */ 10)、CLOSING: 比较少见./* Both sockets are shut down but we still don’t have all our data sent. 等待远程TCP对连接中断的确认 */
11)、CLOSED: 被动关闭端在接受到ACK包后,就进入了closed的状态。连接结束./* The socket is not being used. 没有任何连接状态 */
二、关于长连接和短连接: 一个应用至于到底是该使用短连接还是长连接,应该视具体情况而定。一般的应用应该使用长连接。 TCP 四次挥手 TCP协议有一个优雅的关闭(graceful close)机制,以保证应用程序在关闭连接时不必担心正在传输的数据会丢失。如第4.5节的压缩示例程序所示,这个机制还设计为允许两个方向的数据传输相互独立地终止。关闭机制的工作流程是:应用程序通过调用连接套接字的close()方法或shutdownOutput()方法表明数据已经发送完毕。此刻,底层的TCP实现首先将留存在SendQ队列中的数据传输出去(还要依赖于另一端RecvQ队列的剩余空间),然后向另一端发送一个关闭TCP连接的握手消息。该关闭握手消息可以看作是流终止标志:它告诉接收端TCP不会再有新的数据传入RecvQ队列了。(注意,关闭握手消息本身并没有传递给接收端应用程序,而是通过read()方法返回-1来指示其在字节流中的位置。)正在关闭的TCP将等待其关闭握手消息的确认信息,该确认信息表明在连接上传输的所有数据已经安全地传输到了RecvQ中。只要收到了确认消息,该连接就变成"半关闭(Half closed)"状态。直到连接的另一个方向上收到了对称的握手消息后,连接才完全关闭--也就是说,连接的两端都表明它们再没有数据要发送了。 TCP连接的关闭事件序列可能以两种方式发生:一种方式是先由一个应用程序调用close()方法(或shutdownOutput()方法),并在另一端调用close()方法之前完成其关闭握手消息;另一种方式是两端同时调用close()方法,它们的关闭握手消息在网络上交叉传输。图6.10展示了以第一种方式关闭连接时,底层实现中的事件序列。关闭握手消息已经发送,套接字数据结构的状态也已经设置为"Closing"(专业术语称为"FIN_WAIT_1"),然后close()调用返回。完成这些工作后,将禁止在该Socket上的任何读写操作(会抛出异常)。当收到关闭握手确认消息后,套接字数据结构的状态则改变为"半关闭"(专业术语称为"FIN_WAIT_2"),这种状态将一直持续,直到接收到另一端的关闭握手消息 关闭TCP连接的最后微妙之处在于对Time-Wait状态的需要。TCP规范要求在终止连接时,两端的关闭握手都完成后,至少要有一个套接字在Time-Wait状态保持一段时间。这个要求的提出是由于消息在网络中传输时可能延迟。如果在连接两端都完成了关闭握手后,它们都移除了其底层数据结构,而此时在同样一对套接字地址之间又立即建立了新的连接,那么前一个连接在网络上传输时延迟的消息就可能在新连接建立后到达。由于其包含了相同的源地址和目的地址,旧消息就会被错误地认为是属于新连接的,其包含的数据就可能被错误地分配到应用程序中。 虽然这种情形可能很少发生,TCP还是使用了包括Time-Wait状态在内的多种机制对其进行防范。Time-Wait状态用于保证每个TCP连接都在一段平静时间内结束,这期间不会有数据发送。平静时间的长度应该等于分组报文在网络上存留的最长时间的两倍。因此,当一个连接完全结束(即套接字数据结构离开Time-Wait状态并被删除),并为同样一对地址上的新连接清理道路后,就不会再有旧实例发送的消息还存留在网络中。实际上,平静时间的长度要依赖于具体实现,因为没有机制能真正限制分组报文在网络上能够延迟的时间。通常使用的时间范围是4分钟减到30秒,或更短。 Time-Wait状态最重要的作用是,只要底层套接字数据结构还存在,就不允许在相同的本地端口上关联其他套接字。尤其是试图使用该端口创建新的Socket实例时,将抛出IOException异常。 TCP三次握手/四次挥手详解
1
2 CLOSED: 这个没什么好说的了,表示初始状态。 LISTEN: 这个也是非常容易理解的一个状态,表示服务器端的某个SOCKET处于监听状态,可以接受连接了。 SYN_RCVD: 这个状态表示接受到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本上用netstat你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP握手过程中最后一个ACK报文不予发送。因此这种状态时,当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。 SYN_SENT: 这个状态与SYN_RCVD遥想呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,因此也随即它会进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。 ESTABLISHED:这个容易理解了,表示连接已经建立了。 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连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。 TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。 CLOSING: 这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报文的情况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET连接。 CLOSE_WAIT: 这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。 LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。 最后有2个问题的回答,我自己分析后的结论(不一定保证100%正确):
1、 为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?
2、 为什么TIME_WAIT状态还需要等2MSL后才能返回到CLOSED状态? (责任编辑:IT) |