连接建立--三次握手
三次握手流程
- A初始化连接准备,包括初始化序列号SEQ,然后发送SYN报文
- B收到后,回复一个报文,包括自己的SEQ,并且SYN和ACK都置一
- A收到后也回复一个ACK,对于A而言连接建立;B收到ACK后对于B而言连接建立。
我们要知道:
- 连接是双向的,tcp是全双工通信协议,连接建立表示的是通信双方都认为自己连接上了。
- 网络是分布式的,A和B没有统一的时钟,要确认一个连接是否过时只能由同一方进行确认。
为什么要进行三次握手
-
连接是双方的
-
通信是不稳定的
-
通过三次握手才能阻止重复历史连接的初始化
-
通过三次握手才能对通信双方的初始序列号进行初始化
我们假设三次握手的报文分别为1、2、3。报文可能会延迟到达或者丢失,所以发送方会在发送后启动一个定时器,超时后需要重新发送。
假设只进行两次握手,即B收到报文1后发送报文即建立了连接。因为网络是分布式的,而且是不稳定的,B无法知道报文1是否是经过延迟才到达,如果是延迟到达的,那么该报文 其实已经过期,还为它分配资源是完全浪费的。
网络是分布式的,A和B没有统一的时钟,要确认一个连接是否过时只能由同一方进行确认。所以A发送完1后要等到一个报文2回来才知道此次没有出现延迟,是否可以正常建立连接。
连接拆除--四次挥手
流程:
- 想要拆除连接的一方A发送FIN报文,自身进入到FIN_WAIT_1状态;
- 被拆除连接的一方B接收到FIN报文,发ACK,自身进入到CLOSE_WAIT状态;
- A收到ACK,进入FIN_WAIT_2状态;
- B发送FIN,自身进入LAST_ACK状态;
- A收到FIN,发送ACK,自身进入TIME_WAIT状态;
- B收到ACK报文,B上的这个socket关闭,端口释放;
- A等待2MSL后socket关闭,释放端口。
从以上连接拆除过程我们可以看到:主动发送第一个FIN报文的一方会进入TIME_WAIT状态;进入TIME_WAIT状态的一方需要等待2MSL时间才会释放端口,在2MSL时间内,这个socket对应的四元组(源目IP、源目端口)处于冻结状态。
TIME_WAIT状态的作用主要有两个:
- 避免拆链报文在链路中丢失造成连接关闭异常:在第6步,B没有收到ACK报文的时候会认为A没有收到FIN包,进而会重传第4步的FIN,如果这个时候没有TIME_WAIT状态,A侧socket已经关闭,A会针对B发送的FIN包响应RST,有可能导致B连接异常。
- *避免乱序到来的业务报文在新生成的socket连接中引发混乱:假设在拆链前有TCP报文由于中间网络传输原因导致在第7步完成之后才到达,如果没有TIME_WAIT状态而A和B又使用同样的4元组新建了一个新的socket,那么迷路的数据包就会进入到新的socket中进行处理,可能导致业务异常。
通过TIME_WAIT状态可以很好的规避上面提到的两个问题,TIME_WAIT状态的老化时间是2MSL,MSL是最大分段生存时间,表示的是一个TCP分段可能在网络上存在的最大时间。2倍MSL的设计可以很好的满足报文在A、B之间一来一回的最大需要消耗的时间,最大程度上避免上述两个问题。在CentOS系统中,MSL的时间一般是30s。