社区导航

 

搜索
查看: 4731|回复: 1

[分享] 12-TCP 协议(TIME_WAIT 状态)

[复制链接]

628

TA的帖子

18

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2018-6-25 13:16 | 显示全部楼层 |阅读模式

如果你仔细研究了 TCP 四次挥手,你会发现主动关闭一方最后的状态是 TIME_WAIT,这个 TIME_WAIT 状态是什么意思呢?



1.png
图1 仔细观察主动关闭一方最后的状态

1. TIME_WAIT 状态

TIME_WAIT 状态,又称为 2MSL 等待状态。只有主动关闭一方才能进入 TIME_WAIT 状态。

MSL(Maximum Segment Lifetime)表示报文段最大生存时间,它表示任何报文段被丢弃前在网络内的最长时间,实际上这个时间和 TTL 有关(TTL 是 IP 协议中的一个概念,表示能够经历的路由器的跳数,这个跳数是有限制的,最大值为 255)。

然而,MSL 却不用跳数,而是时间。不同系统中,MSL 定义的大小不一样,RFC 规定,MSL = 2 分钟,而实际实现中,通常是 30 秒、1 分钟。尽管 MSL 的单位是时间而不是跳数,我们仍然假设:具有最大跳数(255)的报文在网络中存在的时间不可能超过 MSL 秒。

当 TCP 协议进入 TIME_WAIT 状态时,必须要在这个状态停留 2 倍 MSL 的时间。

  • 等待 2MSL 的第一个原因

可以防止连接终止的最后一个 ACK 丢失。假设最后一个 ACK 在到达对端时恰好消失,此时对端已经等待了一个 RTT(报文段往返时间),于是进行重传最后一个 FIN,经过 0.5RTT 后到达对端。



2.png
图2 为什么要 2MSL 时间

  • 等待 2MSL 的第二个原因

假设在 ip1:port1 和 ip2:port2 建立了一个连接 A,发送完数据后关闭连接 A。如果没有 TIME_WAIT 状态,我们又立即在 ip1:port1 和 ip2:port2 建立了一个连接 B(虽然这种事情概率很小,但是仍然存在)。

很不幸的是,连接 A 它有一个重复的 TCP 段被连接 B 收到了,然而连接 B 并不知道这个 TCP 段是连接 A 中的旧报文,这会造成错误!

如果有了 TIME_WAIT 状态,等待 2MSL,就足以让连接 A 中重复的报文在网络中消逝;另一方面,TCP 协议规定,处于 TIME_WAIT 状态的端口,是无法建立新的连接的。这样就保证了每成功建立一个新连接时,旧连接中的重复 TCP 段都已消逝。

2. TIME_WAIT 状态的影响

如果 TCP 处于 TIME_WAIT 状态,会进行 2MSL 时间的等待,在这个时间内,定义此连接的本地端口不能再次使用。比如有一个连接:

(local 192.168.80.130:5050, foreign 192.168.166.107:40891) state: TIME_WAIT
  • 1

那么对于 192.168.80.130 这个主机来说,在 2MSL 时间内,5050 端口都不能再次被使用。

一般来说,主动关闭一方都是客户端,客户端建立连接时的端口号都是由系统自动分配的,这并没什么影响,这个端口被占用了,那就再分配一个其它端口就是了。

但是对于服务器来说,它使用的端口是熟知端口(公开出去的端口),如果它是主动关闭一方,进入了 TIME_WAIT 状态,那么 2MSL 时间内,这个服务器都无法启动。如果再次启动,会提示 Address already in use 的错误。

我们用实验来模拟服务器发起主动关闭。

3. 实验3.1 实验步骤
  • 在 linux 上启动 serv 程序

该程序路径是 unp/protocol/tools/tcpserver/serv.c,需要你自己编译一下。

$ ./serv 192.168.80.130 6666
  • 1
  • 在 win7 上启动 tcp_client.exe

该程序路径是 unp/protocol/tools/winclient/tcp_client.cpp,需要你自己用 VS 编译。

tcp_client.exe 192.168.80.130 6666
  • 1
  • 使用 ctrl c 快捷键把 linux 上的 serv 程序终止

此时在 linux 上执行 netstat -ant 命令,可以看到我们的连接处于 FIN_WAIT2 状态。


3.png


  • 在 win7 上的 tcp_client 中输入 q 退出,关闭连接。

4.png


  • 在 linux 上再次执行 netstat -ant

5.png


如果此时,我们再次启动服务器,就会出错:


6.png


3.2 结果分析

反过来,如果客户端也想申请一个处于 2MSL 的本地端口,一样会出问题。但是一般来说客户端使用的本地端口并不是自己指定的,而是系统自动分派的,所以没什么问题。

但是对于服务器来说,如果它的熟知口处于 TIME_WAIT 状态,它将无法再次启动。实际上,现在的 Linux 提供了一种方法,它可能通过给 socket 指定选项 SO_REUSEADDR 允许端口重用。

需要注意的是,即使服务器或客户端绑定了处于 2MSL 的端口,RFC 规定它们也不能建立连接。可惜的是,大多系统实现并未遵守这个规定:

  • 如果服务器重用了处于 2MSL 端口,它仍然可以接收连接请求并连接成功(这违反了协议)
  • 如果客户端重用了处于 2MSL 端口,它建立连接时仍然会失败。(没有违反协议)
4. 总结
  • 理解 TIME_WAIT 状态
  • 掌握 2MSL 的含义
  • 理解为什么在 TIME_WAIT 状态要等待 2MSL(两个原因)


回复

使用道具 举报

1991

TA的帖子

0

TA的资源

版主

Rank: 6Rank: 6

发表于 2018-6-25 13:45 | 显示全部楼层
好复杂的的,学习一下

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

关闭

站长推荐上一条 1/4 下一条

  • 论坛活动 E手掌握

    扫码关注
    EEWORLD 官方微信

  • EE福利  唾手可得

    扫码关注
    EE福利 唾手可得

Archiver|手机版|小黑屋|电子工程世界 ( 京ICP证 060456 )

GMT+8, 2020-6-4 08:42 , Processed in 0.117308 second(s), 23 queries , Gzip On, MemCache On.

快速回复 返回顶部 返回列表