Time-wait状态(2MSL)一些理解
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Time-wait状态(2MSL)⼀些理解
1. 编写TCP/SOCK 服务时,SO_REUSEADDR到底是什么意思?
这个套接字选项通知内核,如果端⼝忙,但TCP状态处于TIME_WAIT,可以重⽤端⼝。
如果端⼝忙,TCP状态处于其他状态,重⽤端⼝时依旧指明“地址已经在使⽤中”。
如果你的服务程序停⽌后向⽴刻重启,⽽新套接字依旧使⽤同⼀个端⼝,此时SO_REUSEADDR选项⾮常有⽤。
但是必须意识到,此时任何⾮期望数据到达,都可能导致服务程序反应混乱。
⼀个套接字由五个部分组成:协议,本地地址,本地端⼝,远程地址和远程端⼝。
SO_REUSEADDR仅仅表⽰可以重⽤本地地址,本地端⼝。
2. 为什么需要TIME_WAIT状态?
假设最后的ACK丢失,server将重发FIN,client必须维护TCP状态信息以便可以重发最后的ACK,否则将会发送RST,结果server认为发⽣错误。
TCP实现必须可靠地终⽌连接的两个⽅向,所以client必须进⼊TIME_WAIT状态。
此外,考虑⼀种情况,TCP实现可能⾯临着先后两个相同的五元组。
如果前⼀个连接处于TIME_WAIT状态,⽽允许另⼀个拥有相同五元组连接出现,可能处理TCP报⽂时,两个连接互相⼲扰。
所以使⽤SO_REUSEADDR选项就需要考虑这种情况。
3. 什么是2MSL
MSL是Maximum Segment Lifetime,译为“报⽂最⼤⽣存时间”,他是任何报⽂在⽹络上存在的最长时间,超过这个时间报⽂将被丢弃。
因为TCP报⽂(segment)是IP数据报(datagram)的数据部分,⽽IP头中有⼀个TTL域,TTL是time to live的缩写,中⽂可以译为“⽣存时间”,这个⽣存时间是由源主机设置初始值但不是存的具体时间,⽽是存储了⼀个IP数据报可以经过的最⼤路由数,每经过⼀个处理他的路由器此值就减1,当此值为0则数据报将被丢弃,同时发送ICMP报⽂通知源主机。
RFC 793中规定MSL为2分钟,实际应⽤中常⽤的是30秒,1分钟和2分钟等
2MSL即两倍的MSL,TCP的TIME_WAIT状态也称为2MSL等待状态,当TCP的⼀端发起主动关闭,在发出最后⼀个ACK包后,即第3次握⼿完成后发送了第四次握⼿的ACK包后就进⼊了TIME_WAIT状态,必须在此状态上停留两倍的MSL时间。
等待2MSL时间主要⽬的是怕最后⼀个ACK包对⽅没收到,那么对⽅在超时后将重发第三次握⼿的FIN包,主动关闭端接到重发的FIN包后可以再发⼀个ACK应答包。
在TIME_WAIT状态时两端的端⼝不能使⽤,要等到2MSL时间结束才可继续使⽤。
当连接处于2MSL等待阶段时任何迟到的报⽂段都将被丢弃。
不过在实际应⽤中可以通过设置SO_REUSEADDR选项达到不必等待2MSL时间结束再使⽤此端⼝。
TTL与MSL是有关系的但不是简单的相等的关系,MSL要⼤于等于TTL。
4. 为什么TIME_WAIT状态需要保持2MSL这么长的时间?
如果TIME_WAIT状态保持时间不⾜够长,第⼀个连接就正常终⽌了。
第⼆个拥有相同五元组的连接出现,⽽第⼀个连接的重复报⽂到达,⼲扰了第⼆个连接。
TCP事先必须防⽌某个连接的重复报⽂在连接终⽌后出现,所以让TIME_WAIT状态保持时间⾜够长(2MSL),连接相应⽅向的上的TCP报⽂要么完全响应完毕,要么被丢弃。
建⽴第⼆个连接的时候,不会混淆。
2MSL等待状态
TIME_WAIT状态也称为2MSL等待状态。
每个具体TCP实现必须选择⼀个报⽂段最⼤⽣存时间MSL(Maximum Segment Lifetime)。
它是任何报⽂段被丢弃前在⽹络内的最长时间。
我们知道这个时间是有限的,因为TCP报⽂段以IP数据报在⽹络内传输,⽽IP数据报则有限制其⽣存时间的TTL字段。
对⼀个具体实现所给定的MSL值,处理的原则是:当TCP执⾏⼀个主动关闭,并发回最后⼀个ACK,该连接必须在TIME_WAIT状态停留的时间为2倍的MSL。
这样可让TCP再次发送最后的ACK以防这个ACK丢失(另⼀端超时并重发最后的FIN)。
这种2MSL等待的另⼀个结果是这个TCP连接在2MSL等待期间,定义这个连接的套接⼝(客户的IP地址和端⼝号,服务器的IP地址和端⼝号)不能再被使⽤。
这个连接只能在2MSL结束后才能再被使⽤。
遗憾的是,⼤多数TCP实现(如伯克利版)强加了更为严格的限制。
在
2MSL等待期间,套接⼝中使⽤的本地端⼝在默认情况下不能再被使⽤。
在连接处于2MSL等待时,任何迟到的报⽂段将被丢弃。
因为处于2MSL等待的、由该套接⼝对(socket pair)定义的连接在这段时间内不能被再⽤,因此当要建⽴⼀个有效的连接时,来⾃该连接的⼀个较早替⾝( incarnation)的迟到报⽂段作为新连接的⼀部分不可能不被曲解(⼀个连接由⼀个插⼝对来定义。
⼀个连接的新的实例( instance)称为该连接的替⾝)。
客户执⾏主动关闭并进⼊TIME_WAIT是正常的。
服务器通常执⾏被动关闭,不会进⼊TIME_WAIT状态。
这暗⽰如果我们终⽌⼀个客户程序,并⽴即重新启动这个客户程序,则这个新客户程序将不能重⽤相同的本地端⼝。
这不会带来什么问题,因为客户使⽤本地端⼝,⽽并不关⼼这个端⼝号是什么。
然⽽,对于服务器,情况就有所不同,因为服务器使⽤熟知端⼝。
如果我们终⽌⼀个已经建⽴连接的服务器程序,并试图⽴即重新启动这个服务器程序,服务器程序将不能把它的这个熟知端⼝赋值给它的端点,因为那个端⼝是处于2MSL连接的⼀部分。
在重新启动服务器程序前,它需要在1~4分钟。
尽管许多具体的实现中允许⼀个进程重新使⽤仍处于2MSL等待的端⼝(通常是设置选项SO _REUSEADDR),但TCP不能允许⼀个新的连接建⽴在相同的插⼝对上。
平静时间的概念
对于来⾃某个连接的较早替⾝的迟到报⽂段, 2MSL等待可防⽌将它解释成使⽤相同插⼝对的新连接的⼀部分。
但这只有在处于2MSL等待连接中的主机处于正常⼯作状态时才有效。
如果使⽤处于2MSL等待端⼝的主机出现故障,它会在MSL秒内重新启动,并⽴即使⽤故障前仍处于2MSL的插⼝对来建⽴⼀个新的连接吗?如果是这样,在故障前从这个连接发出⽽迟到的报⽂段会被错误地当作属于重启后新连接的报⽂段。
⽆论如何选择重启后新连接的初始序号,都会发⽣这种情况。
为了防⽌这种情况,RFC 793指出TCP在重启动后的MSL秒内不能建⽴任何连接。
这就称为平静时间(quiet time)。
只有极少的实现版遵守这⼀原则,因为⼤多数主机重启动的时间都⽐MSL秒要长。