凭这篇三次握手四次挥手总结可以抗住面试的拷打吗?

三次握手

正常通信需要什么条件?

  • 客户端的接收能力、发送能力正常
  • 服务器的接收能力,发送能力正常

所以TCP三次握手建立连接的目的就是为了确定双方的接收和发送能力没有问题,才能保证后面数据传输的正常进行。

TCP报文长什么样子?

凭这篇三次握手四次挥手总结可以抗住面试的拷打吗?
仔细看一下上面的报文,可以看到报文跟数据是拼在一起的,有几个关键的参数要牢记:

  • 序号seq:假设为x,则表示告诉对方自己传的是第x个数据包(即报文的数据部分包含什么数据
  • 确认号ack:假设为y(y=x+1),则表示告诉对方自己已经收到了第x个数据包,希望对方下一次报文包含下一个(即第x+1个)数据包
  • 标志位:
    – ACK用于判断确认号ack是否有效,只有这个标志位为1,ack才有效
    – SYN建立连接,这个标志位为1代表这个报文用于请求建立连接
    – FIN断开连接,这个标志位为1代表这个报文用于请求断开连接

上面几个参数在三次握手和四次挥手中极为重要,务必牢记。

第一次握手

一开始客户端处于closed状态,服务端处于listen状态

假设客户端去请求服务器建立连接,那么首先客户端要发送一个SYN报文给服务器,即SYN请求连接报文,这时候客户端就处于了syn_send状态。

报文内容当然不止SYN=1,客户端还会生成一个初始序号ISN(后面会详细说明)作为seq的值,假设为300,当然第一次握手并不能发送数据,因为双方还未建立连接,所以数据是空的,即这个报文的数据段并不包含所谓的第300个数据包,seq是为了测试服务端的接收能力而存在的,所以这个SYN报文的主要内容就有SYN=1,seq=300;

第二次握手

服务端收到客户端的SYN报文后,它就回复客户端一个报文作为应答。

这个报文得告诉客户端自己允许进行连接,所以SYN=1,同时要应答客户端,告诉它自己收到了第300个(seq)数据包(当然并没有真的收到数据包,只是假装收到了而已,代表自己通过了客户端的测试),希望客户端能发送第301个数据包,所以ack=301,同时为了ack生效,ACK标志位需要为1;同样服务端也要保证对方的接收能力没问题,所以也生成了一个ISN作为seq的值,假设为2000;总结起来报文内容为:SYN=1,ACK=1,ack=301,seq=2000

此时服务器处于syn_rcvd,服务器知道了自己的接收能力没有问题、客户端的发送能力没有问题。

先来说说为什么要第三次握手(面试常考)

看起来两次握手已经够了啊,如果此时建立了连接会发生什么呢?

我们来设想一下。假如客户端第一次发送的SYN请求因为网络拥塞堵在半路到不了服务端,客户端发送服务端回应自己,就以为服务端拒绝了自己的连接请求,伤心地关闭了,处于closed状态。

但是后来SYN报文终于到达了服务端,然后服务端回应了一个SYN+ACK请求报文给客户端,然后就建立了连接。但是客户端因为已经关闭了,不会理会服务端的这个SYN+ACK报文,也不会与服务端进行通信,而服务端傻傻地开着一条跟客户端的连接等待着,十分浪费服务端资源。

所以第三次握手是为了保证服务端不会傻傻地等待。假如没有发生第三次握手,即客户端没有回应自己的SYN+ACK报文,服务端就不会与客户端进行连接。

从另一个角度来说,两次握手结束,此时:

  • 客户端:知道自己和服务端的发送和接收功能都没问题
  • 服务端:知道客户端的发送功能和自己的接收功能没问题,但不知道客户端的接收功能和自己的发送功能有没有问题

所以从这个角度考虑也需要第三次握手。

第三次握手

客户端收到了服务端的SYN+ACK报文,然后它就要最后回应一次,这一次其实携带数据

因为是最后一次握手了,后面就已经建立连接了,所以不需要SYN。而客户端收到的报文里面有seq(seq=2000),所以它必须回应服务端自己收到了它发送的第2000个数据包(again,并没有所谓的数据包),所以需要叫服务器发送第2001个,所以ack=2001,为了让ack生效,所以ACK=1。**并且此时客户端是可以发送数据的,所以seq可以为1,当然如果不发数据就为0。**总结这个报文内容为:ACK=1,ack=2001,seq=0或1。

发送完这个报文,客户端就进入established状态;服务端接收到这个报文也就进入established状态,双方正式建立连接。

配个图可视化感受一下三次握手

凭这篇三次握手四次挥手总结可以抗住面试的拷打吗?

四次挥手

第一次挥手

假设客户端先发起断开连接的请求,那么客户端就会发送一个FIN=1的报文给服务端,这个报文同样会有一个ISN作为seq的值。客户端发送完这个FIN报文就进入了FIN_WAIT1状态;

第二次挥手

服务端接收到客户端的FIN报文,就会发送一个ACK报文作为应答,报文中理所当然有ack=客户端的seq+1。但是服务端不会立即断开连接,因为它可能还需要发送数据,所以它只是回应一下客户端,并且进入了CLOSE_WAIT状态。客户端接收到了这个ACK报文,于是进入FIN_WAIT2状态;

第三次挥手

服务端发送完数据了,也要关闭了,所以它也给客户端发送了一个FIN报文,依旧有ISN作为seq的值,同时服务端进入LAST_ACK状态;

第四次挥手

客户端接收到了这个FIN报文,就返回一个ACK报文,ack=服务端的seq+1,作为应答。然后需要等待2MSL(2倍最长报文段寿命,即一个报文的来回时间),如果没有再次收到FIN报文,就直接关闭连接,进入close状态;如果收到了就再返回一个ACK报文。服务端接收到ACK报文就关闭连接,就进入listen状态。

等待2MSL是为了防止自己发送的ACK丢失,因为服务端发送完FIN报文后,如果没有收到客户端发送的ACK报文,就会重新发送FIN报文。

配个图可视化感受一下四次挥手

凭这篇三次握手四次挥手总结可以抗住面试的拷打吗?