22. TCP协议之四次挥手

百般思念 提交于 2019-12-01 19:12:56



TCP创建的过程和释放的过程都是通过TCP/IP协议栈自动完成的. 本篇就主要是分析TCP释放过程.


TCP报文段首部格式

注意 : TCP虽然是面向字节流的, 但是TCP传送的数据单元却是报文段.

在这里插入图片描述
本篇我们主要会涉及到TCP首部的 : FIN.


四次挥手的过程

在这里插入图片描述

连接释放需要发送4次报文才能完成. 这是因为TCP连接是全双工的, 每一端都需要对读写部分分别进行关闭才行. 当一端关闭读/写或者都关闭时, 该端就会向对象发送FIN来告知对端我将要关闭了, 对端知道后挥发送确认, 关闭端确认后再发送一个确认给对端. 整体就是首先进行关闭的一方将执行主动关闭, 而另一方执行被动关闭.

上图是客户发送FIN, 当然也可以是服务端发送FIN, 一般是客户端主动断开.

  1. 客服端调用close等函数主动关闭, 并向服务端发送一个含FIN的报文, 然后就进入FIN-WAIT1阶段, 该阶段是等待对端的ACK到来.
  2. 服务端接收到对端的FIN后, 立马向对端回一个ACK确认, 然后进入CLOSE-WAIT阶段, 该阶段服务端还能够将没有发送完的数据发送给对端. 当服务端将数据发送完后再发送一个FIN段, 之后进入LAST-ACK阶段, 等待客服端的ACK到来
  3. 当客户端接收到对端的ACK时, 进入FIN-WAIT2阶段, 该阶段客服端还能够继续接收数据, 但是不能在发送数据了; 当接收到对端的FIN后立马向对端发送ACK确认, 之后进入TIME_WAIT阶段. 等待2MSL后客户端彻底关闭.
  4. 服务端收到ACK后就完全将关闭该连接.

半关闭

因为TCP是全双工通信, 主动关闭的发送FIN后关闭了写端, 但是读端并没有关闭, 所以还可以继续接收数据. 这种状态就被称为半关闭. 可以通过shutdown函数来指定关闭读/写端 [1].

问题

  1. 为什么是四次挥手?

    在分析过程的时候已经分析到, TCP连接是全双工的, 有半关闭特性, 每一端都需要对读写部分分别进行关闭. 主动关闭端是因为已经没有数据再发送了, 工作已经做完了; 但是对端不一定做完啊, 可能还有数据要发给你, 所以被动方还能够发送数据, 直到数据发完了才FIN结束. 这个过程主动发只能接收(或丢弃), 不能做其他事了. 如图 :

在这里插入图片描述

当然也有可能被动方也没有数据发送了ACKFIN一并发过来, 这就是“三次挥手”了, 其实还是四次挥手. 如图 :

在这里插入图片描述
2. 为什么主动方最后要等待2MSL?

  1. 可靠的实现TCP全双工链接的终止.

    这是因为虽然双方都同意关闭连接了, 而且握手的4个报文也都协调和发送完毕, 按理可以直接回到CLOSED状态; 但是因为我们必须要假想网络是不可靠的, 你无法保证你最后发送的ACK报文会一定被对方收到, 因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文, 而重发FIN报文, 所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文.

  2. 为什么主动方最后要等待2MSL?

    1. 可靠的终止TCP连接.

      这是因为虽然双方都同意关闭连接了, 而且握手的4个报文也都协调和发送完毕, 按理可以直接回到CLOSED状态; 但是因为我们必须要假想网络是不可靠的, 你无法保证你最后发送的ACK报文会一定被对方收到, 因此对方处于LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文, 而重发FIN报文, 所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文.

    2. 保证让迟来的TCP报文有足够的时间被识别并丢弃.

      如果不存在TIME-WAIT状态, 则应用程序能够立马建立一个和刚关闭的连接相似的连接, 因为它们的IP地址和端口号都相同(这个新连接就被称为上一个连接的化身). 新的化身可能接收到属于原来连接的应用程序数据的TCP报文, 这显然是不应该发生的. 为了避免这样的发生, TCP将TIME_WAIT状态的持续时间是MSL的2倍, 就可以使本连接持续的时间内所产生的所有报文段都从网络中消失. 这样就可以使下一个新的连接中不会出现这种就得连接请求报文段.

    正因为需要等待2MSL时间, 所以主动关闭的一方所使用的端口需要等待2MSL后才能被重新使用, 因为主被关闭方还处于TIME-WAIT阶段. 比如 : TCP套接字之通信 实验中先关闭服务端, 那么一段时间服务端无法被重启.


网络编程

通常可以直接ctrl+c或者程序正常结束使得一端进行关闭, 从而四次挥手释放. 也可以调用close函数, 还可以调用shutdown函数对读/写分别进行关闭.


总结

  • 四次挥手的过程
  • 为什么需要四次挥手
  • 为什么主动关闭方要等待2MSL时间.
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!