服务器需要等待的时间大概在六到八小时左右。作为自由的非官方一名工作则需要等待这个时间。玩家dayz按照规定等待。这款游戏是自由的,非官方则被称之为僵尸末日,游戏早在2013年12月开始上线运营。作为一部大型的丧尸,玩家在游戏当中击杀敌人,并能够存活。上面就是打一针、服务器重启需要的时间,而具体的重启需要的时间在就到七八年。玩家可以尝试下用这总放哪该发尝试下重启哦。首先,我们需要明确, 只有主动断开的那一方才会进入 TIME_WAIT 状态 ,且会在那个状态持续 2 个 MSL(Max Segment Lifetime)。
为了讲清楚 TIME_WAIT,需要先介绍一下 MSL 的概念。
MSL(报文最大生存时间)是 TCP 报文在网络中的最大生存时间。这个值与 IP 报文头的 TTL 字段有密切的关系。
IP 报文头中有一个 8 位的存活时间字段(Time to live, TTL)如下图。 这个存活时间存储的不是具体的时间,而是一个 IP 报文最大可经过的路由数,每经过一个路由器,TTL 减 1,当 TTL 减到 0 时这个 IP 报文会被丢弃。
TTL 经过路由器不断减小的过程如下图所示,假设初始的 TTL 为 12,经过下一个路由器 R1 以后 TTL 变为 11,后面每经过一个路由器以后 TTL 减 1
从上面可以看到 TTL 说的是「跳数」限制而不是「时间」限制,尽管如此我们依然假设 最大跳数的报文在网络中存活的时间不可能超过 MSL 秒 。
Linux 的套接字实现假设 MSL 为 30 秒,因此在 Linux 机器上 TIME_WAIT 状态将持续 60秒。
要构造一个 TIME_WAIT 非常简单,只需要建立一个 TCP 连接,然后断开某一方连接,主动断开的那一方就会进入 TIME_WAIT 状态,我们用 Linux 上开箱即用的 nc 命令来构造一个。
过程如下图:
在机器 c2 上用nc -l 8888启动一个 TCP 服务器
在机器 c1 上用 nc c2 8888 创建一条 TCP 连接
在机器 c1 上用 Ctrl+C 停止 nc 命令,随后在用netstat -atnp | grep 8888查看连接状态。
第一个原因是:数据报文可能在发送途中延迟但最终会到达,因此要等老的“迷路”的重复报文段在网络中过期失效,这样可以避免用相同源端口和目标端口创建新连接时收到旧连接姗姗来迟的数据包,造成数据错乱。
比如下面的例子
假设客户端 10211552 的 61594 端口与服务端 102115510 的 8080 端口一开始建立了一个 TCP 连接。
假如客户端发送完 FIN 包以后不等待直接进入 CLOSED 状态,老连接 SEQ=3 的包因为网络的延迟。过了一段时间 相同 的 IP 和端口号又新建了另一条连接,这样 TCP 连接的四元组就完全一样了。
恰好 SEQ 因为回绕等原因 也正好相同,那么 SEQ=3 的包就无法知道到底是旧连接的包还是新连接的包了,造成新连接数据的混乱。
TIME_WAIT 等待时间是 2 个 MSL,已经足够让一个方向上的包最多存活 MSL 秒就被丢弃,保证了在创建新的 TCP 连接以后,老连接姗姗来迟的包已经在网络中被丢弃消逝,不会干扰新的连接。
第二个原因是确保可靠实现 TCP 全双工终止连接。
关闭连接的四次挥手中,最终的 ACK 由主动关闭方发出,如果这个 ACK 丢失,对端(被动关闭方)将重发 FIN,如果主动关闭方不维持 TIME_WAIT 直接进入 CLOSED 状态,则无法重传 ACK,被动关闭方因此不能及时可靠释放。
如果四次挥手的第 4 步中客户端发送了给服务端的确认 ACK 报文以后不进入 TIME_WAIT 状态,直接进入 CLOSED状态,然后重用端口建立新连接会发生什么呢?
如下图所示
主动关闭方如果马上进入 CLOSED 状态,被动关闭方这个时候还处于LAST-ACK状态,主动关闭方认为连接已经释放,端口可以重用了, 如果使用相同的端口三次握手发送 SYN 包,会被处于 LAST-ACK状态状态的被动关闭方返回一个 RST,三次握手失败。
为什么时间是两个 MSL?
1 个 MSL 确保四次挥手中主动关闭方最后的 ACK 报文最终能达到对端
1 个 MSL 确保对端没有收到 ACK 重传的 FIN 报文可以到达
2MS = 去向 ACK 消息最大存活时间(MSL) + 来向 FIN 消息的最大存活时间(MSL)
在一个非常繁忙的服务器上,如果有大量 TIME_WAIT 状态的连接会怎么样呢?
连接表无法复用
socket 结构体内存占用
连接表无法复用 因为处于 TIME_WAIT 的连接会存活 2MSL(60s),意味着相同的TCP 连接四元组(源端口、源 ip、目标端口、目标 ip)在一分钟之内都没有办法复用,通俗一点来讲就是“占着茅坑不拉屎”。
假设主动断开的一方是客户端,对于 web 服务器而言,目标地址、目标端口都是固定值(比如本机 ip + 80 端口),客户端的 IP 也是固定的,那么能变化的就只有端口了,在一台 Linux 机器上,端口最多是 65535 个( 2 个字节)。
如果客户端与服务器通信全部使用短连接,不停的创建连接,接着关闭连接,客户端机器会造成大量的 TCP 连接进入 TIME_WAIT 状态。
可以来写一个简单的 shell 脚本来测试一下,使用 nc 命令连接 redis 发送 ping 命令以后断开连接。
如果在 60s 内有超过 65535 次 redis 短连接 *** 作,就会出现端口不够用的情况,这也是使用 连接池 的一个重要原因。
针对 TIME_WAIT 持续时间过长的问题,Linux 新增了几个相关的选项,netipv4tcp_tw_reuse 和 netipv4tcp_tw_recycle。
下面我们来说明一下这两个参数的用意。 这两个参数都依赖于 TCP 头部的扩展选项:timestamp
TCP 头部时间戳选项(TCP Timestamps Option,TSopt)
除了我们之前介绍的 MSS、Window Scale 还有以一个非常重要的选项:时间戳(TCP Timestamps Option,TSopt)
它由四部分构成:类别(kind)、长度(Length)、发送方时间戳(TS value)、回显时间戳(TS Echo Reply)。
时间戳选项类别(kind)的值等于 8,用来与其它类型的选项区分。长度(length)等于 10。两个时间戳相关的选项都是 4 字节。
如下图所示:
是否使用时间戳选项是在三次握手里面的 SYN 报文里面确定的。
下面的包是 curl githubcom 抓包得到的结果:
发送方发送数据时,将一个发送时间戳 1734581141 放在发送方时间戳 TSval 中
接收方收到数据包以后,将收到的时间戳 1734581141 原封不动的返回给发送方,放在 TSecr 字段中,同时把自己的时间戳 3303928779 放在 TSval 中
后面的包以此类推
有几个需要说明的点:
1 时间戳是一个单调递增的值,与我们所知的 epoch 时间戳不是一回事。 这个选项不要求两台主机进行时钟同步
2 timestamps 是一个双向的选项,如果只要有一方不开启,双方都将停用 timestamps。
比如下面是curl >>
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)