TCP三次握手四次挥手
Chao 工程师

TCP的三次握手四次挥手实质就是TCP通信的连接断开

image

1.三次握手

​ TCP协议位于传输层,作用是提供可靠的字节流服务,为了准确无误地将数据送达目的地,TCP协议采纳三次握手策略。

==三次握手原理:==

  • 第1次握手:客户端发送一个带有SYN(synchronize)标志的数据包给服务端;

  • 第2次握手:服务端接收成功后,回传一个带有SYN/ACK标志的数据包传递确认信息,表示收到了;

  • 第3次握手:客户端再回传一个带有ACK标志的数据包,握手结束。

其中:SYN标志位数置1,表示建立TCP连接;ACK标志表示验证字段。

ACK:此标志表示应答域有效。TCP应答号将会包含在TCP数据包中。

​ 有两个取值:0和1,1表示应答域有效,反之为0。

SYN(SYNchronization) :

在连接建立时用来同步序号。SYN置1就表示这是一个连接请求或连接接受报文

​ 当SYN=1而ACK=0时,表明这是一个连接请求报文;

​ SYN=1和ACK=1,对方同意建立连接。

可通过以下趣味图解理解三次握手:

image

三次握手详细说明:

  • 第一次握手:建立连接。客户端发送连接请求报文段,将SYN位置为1,Sequence Numberx;然后,客户端进入SYN_SEND状态,等待服务器的确认;
  • 第二次握手:服务器收到SYN报文段。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置Acknowledgment Numberx+1(Sequence Number+1);同时,自己自己还要发送SYN请求信息,将SYN位置为1Sequence Numbery;服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;
  • 第三次握手:客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,,完成TCP三次握手。 完成了三次握手,客户端和服务器端就可以开始传送数据。

2.四次挥手

​ 由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个 FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

==四次挥手原理:==

  • 第1次挥手:客户端发送一个FIN,用来关闭客户端到服务端的数据传送,客户端进入FIN_WAIT_1状态;

  • 第2次挥手:服务端收到FIN后,发送一个ACK给客户端,确认序号为收到序号+1

    ​ (与SYN相同,一个FIN占用一个序号),服务端进入CLOSE_WAIT状态;

    ​ 客户端进入FIN_WAIT_2状态

  • 第3次挥手:服务端发送一个FIN,用来关闭服务端到客户端的数据传送,服务端进入LAST_ACK状态;

  • 第4次挥手:客户端收到FIN后,客户端t进入TIME_WAIT状态,接着发送一个ACK给Server,

    ​ 确认序号为收到序号+1,服务端进入CLOSED状态,完成四次挥手。

其中:FIN(finis)标志位数置1,表示断开TCP连接。

可通过以下趣味图解理解四次挥手:

image

LISTEN:等待从任何远端TCP 和端口的连接请求。

SYN_SENT:发送完一个连接请求后等待一个匹配的连接请求。

SYN_RECEIVED:发送连接请求并且接收到匹配的连接请求以后等待连接请求确认。

ESTABLISHED:表示一个打开的连接,接收到的数据可以被投递给用户。连接的数据传输阶段的正常状态。

FIN_WAIT_1:等待远端TCP 的连接终止请求,或者等待之前发送的连接终止请求的确认。

FIN_WAIT_2:等待远端TCP 的连接终止请求。

CLOSE_WAIT:等待本地用户的连接终止请求。

CLOSING:等待远端TCP 的连接终止请求确认。

LAST_ACK:等待先前发送给远端TCP 的连接终止请求的确认(包括它字节的连接终止请求的确认)

TIME_WAIT:等待足够的时间过去以确保远端TCP 接收到它的连接终止请求的确认。
TIME_WAIT 两个存在的理由:
1.可靠的实现tcp全双工连接的终止;
2.允许老的重复分节在网络中消逝。

CLOSED:不在连接状态(这是为方便描述假想的状态,实际不存在)

3.为什么需要三次握手,两次不行吗?

弄清这个问题,我们需要先弄明白三次握手的目的是什么,能不能只用两次握手来达到同样的目的。

  • 第一次握手:客户端发送网络包,服务端收到了。 这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
  • 第二次握手:服务端发包,客户端收到了。 这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时==服务器并不能确认客户端的接收能力是否正常==。
  • 第三次握手:客户端发包,服务端收到了。 这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。

另一个种解释:

  • 因为某些原因,S没有收到C的包,过了一段时间后才收到,S认为这是两个请求,而C认为是一个请求,从而在2次握手后进入等待状态,造成状态不一致。

  • 如果在3次握手的状态下,S收不到最后的ACK包,自然不会认为连接建立成功。

  • 所以3次握手,就是为了解决网络信道不可靠的问题。

因此,需要三次握手才能确认双方的接收与发送能力是否正常。

image

4.三次握手过程中可以携带数据吗?

其实第三次握手的时候,是可以携带数据的。但是,第一次、第二次握手不可以携带数据

为什么这样呢?大家可以想一个问题,假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据。因为攻击者根本就不理服务器的接收、发送能力是否正常,然后疯狂着重复发 SYN 报文的话,这会让服务器花费很多时间、内存空间来接收这些报文。

也就是说,第一次握手不可以放数据,其中一个简单的原因就是会让服务器更加容易受到攻击了。而对于第三次的话,此时客户端已经处于 ESTABLISHED 状态。对于客户端来说,他已经建立起连接了,并且也已经知道服务器的接收、发送能力是正常的了,所以能携带数据也没啥毛病。

5.挥手为什么需要四次?

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

6.为什么客户端需要等待超时时间

这是为了保证对方已经收到ACK。

  • 因为假设客户端发送完最后一份ACK后,就释放了链接,一旦ack包在网络中丢失,服务端将一直停留在最后的确认状态。
  • 如果客户端发行完最后一份ACK后,等待一段时间,这时服务端又没有收到ACK,会重发FIN包,客户端会响应这个FIN包,重发ACK包,并刷新超时时间,也是为了保证在不可靠的网络链路中进行可靠的链接断开确认

浏览器相关原理(面试题)详细总结一

 Comments