三次握手和四次挥手

三次握手过程理解

第一次握手:建立连接时,客户端发送syn包(syn=x)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

四次挥手过程理解 

1)客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
2)服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
3)客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
4)服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
5)客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
6)服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

 常见面试题

 【问题1】为什么连接的时候是三次握手,关闭的时候却是四次挥手?

因为当服务端收到客户端发送的SYN请求报文后,服务端会直接发送SYN+ACK报文(其中ACK报文是用来应答报文的,SYN报文是用来同步的)。但是关闭连接时,当服务端收到客户端发来的FIN报文时,并不会立即关闭SOCKET,而是会发送一个ACK报文,告诉客户端:你发送的报文我已经收到了,然后等到服务端报文都发送完毕后,才发送FIN报文,因此需要四次挥手。

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

虽然照理来说,四个报文都发送完毕后,客户端可以进入CLOSE状态,可是我们必须假设网络是不可靠的,发送的最后一个ACK报文可能会丢失,所以客户端不能立即关闭,它必须确认服务端收到了该ACK报文。所以当客户端发送最后一个ACK报文后,会设置一个计时器并进入TIME_WAIT状态,等待2MSL,如果在这段时间内再次收到FIN报文,客户端就会重发一次ACK报文并再次等待2MSL。MSL(即一个报文可在网络中存活的最长时间),2MSL即一个报文一次发送和一次恢复的最大时间,如果直到2MSL时间后,客户端并没有收到服务端再次发来FIN报文,就默认服务端已经收到了ACK报文,客户端就关闭连接,进入CLOSE状态。

【问题3】为什么不能用两次握手进行连接?

三次握手的重点在于双方都做好了发送的准备(双方彼此都知道已准备好),也要允许双方协商序列号,这个序列号将在握手过程中被发送和接收。

如果改成两次握手,可能会出现死锁,如果现在计算机A和计算机B准备建立连接,A给B发一个连接请求分组,B收到之后发送一个请求应答分组给A,但是这个应答分组在传输过程中丢失了,A认为连接已经建立了,可以发送数据分组了,可是B并不知道A已经建立了连接,不知道A准备了什么序列号,甚至怀疑A是否收到了应答分组。所以B认为连接还没建立,不会接受数据分组,而一直等待着A发送确认应答分组。而A发送数据分组超时后就重复发送数据分组,此时就出现了死锁。

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

TCP设有一个保活计时器,因为当客户端出现故障时,服务器不能一直等待,那样会浪费大量资源,所以每次客户端发送数据给服务端,服务端就会复位保活计时器,一般为两个小时,如果在这两个小时里没有再次收到客户端发送的任何数据,服务端就会每隔75s发送一次探测报文给客户端,连续发送十次并没有收到任何客户端应答之后就默认客户端已经出现故障,接着关闭连接。

原文地址:https://www.cnblogs.com/keyng/p/12905513.html