TCP四次挥手三种情况

一、客户端主动关闭,服务器还有数据没有发送完

客户端向服务器发送连接释放报文,设置FIN标志位,序号为seq=u,即前面已传送过的数据的最后一个字节的序号加1。客户端从ESTABLISHED(已建立连接)状态进入FIN-WAIT-1(终止等待1)状态。

服务器收到客户端发来的连接释放报文后发出确认,确认号ack=u+1,选择自己的序号v,v等于服务器前面已传送过的数据的最后一个字节的序号加1。服务器进入CLOSE-WAIT(关闭等待)状态。此时客户端到服务器的连接释放,TCP连接处于半关闭状态,即客户端已经没有数据要发送,但是服务器此时若发送数据,客户端仍要接收。因为服务器到客户端的连接此时并未关闭。

客户端收到服务器的确认后,进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文。

若服务器此时已没有数据发送,向客户端发送连接释放报文,设置FIN标志位,选择序号w,即前面已传送过的数据的最后一个字节的序号加1。重复上次发送的确认号ack=u+1.服务器进入LAST-ACK(最后确认)状态。

客户端收到服务器的连接释放报文,发出确认,设置ACK标志位,确认号为ack = w + 1。自己的序号为u+1。进入TIME-WAIT(时间等待)状态。等待2MSL时间后关闭,进入CLOSED状态。

服务器收到ACK,进入CLOSED状态。

二、客户端主动关闭,服务器此时没有数据要发送(比较极端的情况,三次挥手)

客户端主动关闭,发送FIN。客户端进入FIN-WAIT-1(终止等待1)状态。

服务器收到FIN,进入CLOSE-WAIT(关闭等待)状态,此时服务器没有数据要发送,给客户端发送ACK + FIN,进入LAST-ACK(最后确认)状态。

客户端收到服务器发送的FIN+ACK,给服务器发送ACK,进入TIME-WAIT(时间等待)状态。等待2MSL时间后关闭,进入CLOSED状态。

服务器收到ACK,进入CLOSED状态。

三、客户端服务器几乎同时发送释放连接请求

两端几乎同时发送FIN,两端进入FIN-WAIT-1(终止等待1)状态。

两端同时收到FIN,同时回一个ACK。进入CLOSEING状态。

两端收到ACK,进入TIME-WAIT(时间等待)状态。等待2MSL时间后关闭,进入CLOSED状态。

MSL(Maximum Segment Lifetime),最长报文段寿命。
为什么客户端再TIME-WAIT状态必须等待2MSL的时间?

第一:为了保证客户端最后发送的ACK报文能够到达服务器。这个ACK报文有可能丢失,此时服务器没有收到客户端的确认,会超时重传ACK+FIN报文,客户端就能在2MSL中收到服务器重传的ACK+FIN报文。接着客户端重传确认报文,重新等待2MSL。最后两端都正常进入CLOSED状态。客户端进入TIME-WAIT如果不等待2MSL,那么就有可能无法收到服务器重传的FIN+ACK,就不确认。这样的话服务器就无法收到确认,无法正常进入CLOSED状态。

第二:防止已失效的连接请求报文出现在本连接中。客户端在发送完最后一个ACK报文后,等待2MSL,就可以使本连接持续的时间内所产生的所有报文段消失,这样下一个连接中就不会出现旧的连接请求报文。

为什么挥手需要四次?

这是由于TCP的半关闭(half-close)造成的。半关闭是指:TCP提供了连接的一方在结束它的发送后还能接受来自另一端数据的能力。通俗来说,就是不能发送数据,但是还可以接受数据。

TCP不允许连接处于半打开状态时,就单向传输数据,因此完成三次握手后才可以传输数据(第三握手可以携带数据)。

当连接处于半关闭状态时,TCP是允许单向传输数据的,也就是说服务器此时仍然可以向客户端发送数据,等服务器不再发送数据时,才会发送FIN报文段,同意现在关闭连接。

这一特性是由于TCP双向通道互相独立所导致的,也使得关闭连接必须经过四次握手。

为什么中间的ACK和FIN不可以像三次握手那样合为一个报文段呢?

在socket网络编程中,执行close()方法会触发内核发送FIN报文。什么时候调用close()方法,这是由用户态决定的,假如服务器仍有大量数据等待处理,那么服务器会等数据处理完后,才调用close()方法,这个时间可能会很久,而ACK报文则是由系统内核来完成的,这个过程会很快。所以中间的ACK和FIN不能合为一个包。

TIME_WAIT状态过多有什么危害?

只有主动发起断开请求的一方才会进入TIME_WAIT状态!

1.占用系统资源

2.socket的TIME_WAIT状态结束之前,该socket占用的端口号将一直无法释放。如果服务器TIME_WAIT状态过多,占满了所有端口资源,则会导致无法创建新的连接。

如何解决TIME_WAIT状态过多?

最好的办法是尽量让客户端主动断开连接,除非遇到一些异常情况,如客户端协议错误、客户端超时等。

打开系统的TIME_WAIT重用和快速回收。

在Linux系统可以修改以下参数:

1.打开TCP对时间戳的支持,保持服务器与客户端时间同步

net.ipv4.tcp_timestamps=1(默认即为 1)

2.修改net.ipv4.tcp_tw_reuse = 1,允许对处于TIME_WAIT的socket用于建立新的连接

net.ipv4.tcp_tw_reuse = 1 (默认为0)

修改TIME_WAIT连接状态的上限值,超过上限值,处于TIME_WAIT状态的socket将立刻被清除并打印警告信息。

net.ipv4.tcp_max_tw_buckets = 18000,表示系统同时保持处于TIME_WAIT状态的socket的最大数量,默认为18000。

可修改为更小值。

net.ipv4.tcp_max_tw_buckets = 6666

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值