TCP的三次握手与四次挥手

TCP报文

报头详解:

  • 源端口号和目的端口号同IP数据报中的源IP与目的IP唯一确定一条TCP连接

  • 序号(seq):4字节,用来标识TCP发送端向TCP接收端发送的数据字节流

  • 确认号(ack):4字节,当ACK标志为1时确认号才有效,并且一旦建立连接,该值将始终发送

  • 数据偏移(头部长度):4位,标识报文首部的长度

  • 保留:6位,作为保留字段,暂时没有什么用处

三次握手

1.(客户端:我要建立连接) Client发出SYN包(SYN = 1,seq = x(随机数))Client进入SYN_SENT(同步已发送)状态,等待Server确认

2.(服务器:你的诉求我知道了,可以连接)Server收到SYN包,同时自己发送一个SYN+ACK包(SYN = 1,ACK = 1,seq = y(随机数),ack = x +1),此时Server进入SYN_RCVD(同步收到)状态

3.(客户端:进行连接) Client收到Server的SYN+ACK包,向Server发送ACK确认包(ACK = 1,seq = x + 1,ack = y + 1),此包发送完毕,Client和Server进入ESTABLISHED(TCP连接成功)状态

四次挥手

  1. 客户端:我数据传完了,我要下线了)Client发出连接释放报文(FIN = 1,seq = u(之前已传数据的最后一个字节的序号加1)),并停止发送数据,Server进入FIN-WAIT-1(终止等待1)状态

  2. 服务器:知道了,我还有点数据,你等下一段时间后)Server收到连接释放报文,发出确定报文(ACK = 1,ack = u + 1,seq = v(Server自己的序列号)),Server进入CLOSE-WAIT(关闭等待)状态,Client收到Server回复后,进入FIN-WAIT-2(终止等待2)状态。此时是半关闭状态,即Client不再发送,但是Server若发送数据,Client依然要接收。

  3. 服务器:我数据发完了,你可以下线了)Server将最后的数据发送完毕,向Client发送连接释放报文(FIN = 1,ACK = 1,seq = w(此时Server自己的序列号),ack = u + 1),Server进入LAST-ACK(最后确认)状态,等待Client的确认。

  4. 客户端:好的)Client收到Server的连接释放报文,必须发出确认报文(ACK = 1,seq = u + 1,ack = w + 1),Client进入TIME-WAIT(时间等待)状态。但是Client连接没有释放,必须经过2MSL的时间之后,才进入CLOSED状态。Server收到Client的确认报文,立即进入CLOSED状态。Server结束TCP连接的时间要比Client早一些。

面试回答

  • TCP/IP 协议是传输层的一个面向连接的安全可靠的一个传输协议。

  • 三次握手的机制是为了保证能建立一个安全可靠的连接,那么第一次握手是由客户端发起,客户端会向服务端发送一个报文,在报文里面:SYN标志位置为1,表示发起新的连接。当服务端收到这个报文之后就知道客户端要和我建立一个新的连接,于是服务端就向客户端发送一个确认消息包,在这个消息包里面:ACK标志位置为1,表示确认客户端发起的第一次连接请求。以上两次握手之后,对于客户端而言:已经明确了我既能给服务端成功发消息,也能成功收到服务端的响应。但是对于服务端而言:两次握手是不够的,因为到目前为止,服务端只知道一件事,客户端发给我的消息我能收到,但是我响应给客户端的消息,客户端能不能收到我是不知道的。所以,还需要进行第三次握手,第三次握手就是当客户端收到服务端发送的确认响应报文之后,还要继续去给服务端进行回应,也是一个ACK标志位置1的确认消息。通过以上三次连接,不管是客户端还是服务端,都知道我既能给对方发送消息,也能收到对方的响应。那么,这个连接就被安全的建立了。

  • 四次挥手机制也是由客户端首先发起的,客户端会发送一个报文,在报文里面:FIN标志位置1。当服务端收到这个报文之后,就知道了客户端想要和我断开连接。但是此时服务端不一定能做好准备,因为客户端发起断开连接的消息的时候,对于服务端而言,它极可能有未发送完的消息,它还要继续发送。所以此时对于服务端只能进行一个消息确认,就是告诉客户端我知道你要跟我断开连接了,但是我还没有做好准备,你需要等我一会。稍过片刻,服务端会继续发送一个断开连接的报文,FIN标志位置1。这个报文表示服务端已经做好了要断开连接的准备。客户端收到后继续发送一个消息确认的报文。通过以上四次连接,不管是客户端还是服务端,都已经做好了要断开连接的准备,连接就可以被断开了。

扩展问法

1、为什么连接的时候是三次握手,关闭的时候却是四次握手?

答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

2、为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。

3、为什么不能用两次握手进行连接?

答:3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
现在把三次握手改成仅需要两次握手,死锁是可能发生的。作为例子,考虑计算机S和C之间的通信,假定C给S发送一个连接请求分组,S收到了这个分组,并发 送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。可是,C在S的应答分组在传输中被丢失的情况下,将不知道S 是否已准备好,不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。在这种情况下,C认为连接还未建立成功,将忽略S发来的任何数据分 组,只等待连接确认应答分组。而S在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。

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

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

【参考资料】

  1. https://www.cnblogs.com/shineyoung/p/10656914.html

  2. https://www.cnblogs.com/bj-mr-li/p/11106390.html

  3. https://www.bilibili.com/video/BV1bi4y1x7m5

posted @ 2021-04-19 07:59  鸢酋  阅读(102)  评论(0编辑  收藏  举报