TCP 建立连接的过程,为什么要三次握手、四次挥手?

分析&回答

TCP(Transmission Control Protocol)

TCP是主机对主机层的传输控制协议,提供可靠的连接服务。

tcp标志位(位码)有6种标示:

  1. SYN(synchronous建立联机)
  2. ACK(acknowledgement 确认)
  3. PSH(push传送)
  4. FIN(finish结束)
  5. RST(reset重置)
  6. URG(urgent紧急)

HTTP的三次握手:

第一次:客户端向服务器发送SYN报文(SYN一般是用来进行同步的)此时客户端进入了 SYN_SEND状态,服务器进入SYN_RECE等待确认状态。
主机A发送位码为syn=1,随机产生seq number=x的数据包到服务器,主机B由SYN=1知道,A要求建立联机;

第二次:服务器接收到SYN报文后同时向客户端发送接收确认报文,并带上ACK报文,(用于应答的)。
主机B收到请求后要确认联机信息,向A发送ack number=(主机A的x+1),syn=1,ack=1,随机产生seq=y的包

第三次:客户端接收到ACK报文并检查ACK报文是否正确,如果正确的话客户端再次发送ACK,服务器收到后确认验证通过,表示连接已经成功建立,可以发送数据包了。
主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的y+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功。

断开的四次挥手:

由于TCP是全双工的,因此每个方向都必须单独进行关闭才可,这个原则是当一方完成数据发送任务后就能发送一个FIN的标志来结束这个发送通道,收到FIN后只意味着这一个方向上没有数据流动(没有需要的数据要发送了),一个TCP可以在收到一个FIN后仍然能发送数据。

第一次挥手:客户端向服务器发送FIN,用来告诉服务器你发的东西我收到了,我要关闭通道了。因此当主动方发送断开连接的请求(即FIN报文)给被动方时,仅仅代表主动方不会再发送数据报文了,但主动方仍可以接收数据报文。

第二次挥手:服务器从客户度收到FIN,并发回一个ACK报文(应答用的),确认收到客户端的消息。被动方此时有可能还有相应的数据报文需要发送,因此需要先发送ACK报文,告知主动方“我知道你想断开连接的请求了”。这样主动方便不会因为没有收到应答而继续发送断开连接的请求(即FIN报文)。

第三次挥手:服务器关闭与客户端的连接,发送一个FIN给客户端。被动方在处理完数据报文后,便发送给主动方FIN报文;这样可以保证数据通信正常可靠地完成。发送完FIN报文后,被动方进入LAST_ACK阶段(超时等待)。

第四次关闭连接:客户端收到后发回ACK报文确认。如果主动方及时发送ACK报文进行连接中断的确认,这时被动方就直接释放连接,进入可用状态。

为什么TCP客户端最后还要发送一次确认呢?

换句话说,为什么tcp连接要进行,三次握手,两次不行吗?
建立三次握手主要是因为A发送了再一次的确认,那么A为什么会再确认一次呢,主要是为了防止已失效的连接请求报文段又突然传送给B,从而产生了错误。
所谓“已失效的连接请求报文”是这样产生的,正常情况下,A发出连接请求,但是因为连接报文请求丢失而未收到确认,于是A再重传一次连接请求,后来收到了请求,并收到了确认,建立了连接,数据传输完毕后,就释放链接,A共发送了两次连接请求报文段,其中第一个丢失,第二个到达了B,没有“已失效的连接请求报文段”,但是还有异常情况下,A发送的请求报文连接段并没有丢失,而是在某个网络节点滞留较长时间,以致延误到请求释放后的某个时间到达B,本来是一个早已失效的报文段,但是B收到了此失效连接请求报文段后,就误以为A又重新发送的连接请求报文段,并发送确认报文段给A,同意建立连接,如果没有三次握手,那么B发送确认后,连接就建立了,而此时A没有发送建立连接的请求报文段,于是不理会B的确认,也不会给B发送数据,而B却一直等待A发送数据,因此B的许多资源就浪费了,采用三次握手的方式就可以防止这种事情发生,例如刚刚,A不理会B,就不会给B发送确认,B收不到A的确认,就知道A不要求建立连接,就不会白白浪费资源。

反思&扩展

1.为什么客户端最后还要等待2MSL?

MSL(Maximum Segment Lifetime),最大报文段寿命,TCP允许不同的实现可以设置不同的MSL值。

第一,保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。

第二,防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。深刻理解一下,这里所谓的新旧连接的问题:假如没有这个2msl的等待时间,那么,此时主动关闭方进入close状态后,立马在与另一方(同ip,同端口)进行tcp连接,这时候,新的连接就可能会把之前旧连接所无效的报文段当成自己的报文段,从而产生混乱。

2.为什么建立连接是三次握手,关闭连接确是四次挥手呢?

建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。

而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。

3.如果已经建立了连接,但是客户端突然出现故障了怎么办?

TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75s发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

喵呜面试助手:一站式解决面试问题,你可以搜索微信小程序 [喵呜面试助手] 或关注 [喵呜刷题] -> 面试助手 免费刷题。如有好的面试知识或技巧期待您的共享!

猜你喜欢

转载自blog.csdn.net/jjclove/article/details/127392398