TCP的三次握手与四次挥手

前面的话

TCP连接的三次握手与四次挥手面试也是常考的,小柒查阅了许多资料全面的总结一下。

TCP报文段的首部格式

在介绍三次握手和四次挥手前,先介绍一下TCP报文的相关知识。

TCP虽然是面向字节流的,但是TCP传送的数据单元却是报文段。一个报文段分为首部和数据两部分,而TCP的全部功能都体现在它的首部中各字段的作用。其首部的前20个字节是固定的。
在这里插入图片描述

  • 源端口与目的端口:各占2个字节,分别写入源端口号和目的端口号。
  • 序号seq: 占4个字节,范围:【0,2^32 -1】,用来标记报文段的顺序。每个字节都是按顺序编号。一个报文段的首部中的序号seq的值表示该报文段所携带数据的第一个字节的编号。
  • 确认号ack: 占4个字节,表示期望收到对方下一个报文段的第一个数据字节的序号。
  • 确认标志位ACK:仅当ACK=1时,确认号ack才有效。ACK = 0,确认号无效。
  • 同步标志位SYN:建立TCP连接时用的同步序号。当SYN = 1时,ACK = 0时表示:这是一个连接请求报文段。若同意连接,则相应报文中使得SYN = 1,ACK = 1。SYN这个表示位只有在TCP连接时才会被置为1,握手完成后SYN标志位置为0。
  • 终止标志位FIN:表示要释放一个连接。FIN = 1表示报文的发送方的数据已经发送完毕,要求释放连接。与SYN的作用刚好相反。

在这里插入图片描述

注意:ACK、SYN、FIN这些大写的单词都表示标志位,要么置为1,要么置为0;而ack、seq小写单词表示序号。

三次握手

三次握手其实就是连接一个TCP连接时,需要客户端和服务器总共发送3个TCP报文段。进行三次握手的主要作用:为了确认双方的接受能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠传输做准备。
在这里插入图片描述

  • 第一次握手:客户端向服务端发送一个请求报文段,首部的SYN 置为1,同时选择一个初始化seq序列号,seq = x。TCP规定,SYN = 1的请求报文段不能携带数据,但是要消耗一个序号。这是客户端进入SYN-SENT(同步已发送)状态。
  • 第二次握手:服务端接收客户端的请求报文段之后,如果同意连接,就会传回一个确认报文段,这个报文段中的SYN = 1、ACK = 1,确认号ack = x+1 。同时自己也会选择一个初始化序号seq = y。同样,这个报文段也不能携带数据,但要消耗一个序号。此时,服务器进入SYN_RCVD(同步收到)状态。
  • 第三次握手:客户端收到服务器的确认报文段之后,还要给服务器发送一个确认报文。即ACK = 1,ack = y+1, seq = x +1。这时,TCP建立连接,客户端处于ESTABLISHED(已连接状态)。当服务器收到这个确认报文之后,也处于ESTABLISHED状态。此时,双方已建立起连接。
为什么是三次握手,两次不行吗?

先说一下三次握手的目的:

  • 第一次握手:客户端发送报文段,服务器接收了。这样表示:服务器知道客服端的发送能力正常。
  • 第二次握手:服务器发送报文段,客户端接收了。这样表示: 客户端知道服务器的发送与接收能力是正常的。此时服务器不知道客户端的接受能力是否正常
  • 第三次握手:客户端发送报文段,服务器接收了。这样服务器就知道客户端的接受能力正常。

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

如果是两次握手,则会出现下面这种情况:

客户端发送了第一个请求连接并且没有丢失,只是因为在网络节点中滞留时间太长了,由于TCP的客户端迟迟没有收到确认报文,以为服务器没有收到,此时会重传请求报文,此后客户端和服务器经过两次握手完成了连接,传输数据,然后关闭连接。此时此前滞留的那次请求连接,网络通畅了到达了服务器,这个报文本该是失效的,但是,两次握手的机制将会让客户端和服务器再次建立连接,这将导致不必要的错误和资源浪费。

如果是三次握手,就算那个失效报文传给了服务器,服务器也发送了一个确认报文,但是客户端不会再发出一个确认报文给服务器。由于服务器接收不到确认,就不会建立TCP连接。

什么是半连接队列?

服务器第一次收到客户端的SYN之后,就会处在SYN_RCVD状态(同步收到),此时双方还没有完全建立其连接,服务器会把此种状态下的请求连接放在一个队列里,我们把这种队列称为半连接队列

既然有半连接队列就会有全连接队列,就是已经完成三次握手,建立起连接的请求就会放在全连接队列中。如果队列满了,就可能出现丢包现象。

SYN Flood 攻击原理

SYN Flood 属于典型的 DoS/DDoS 攻击。其攻击的原理很简单,就是用客户端在短时间内伪造大量不存在的 IP 地址,并向服务端疯狂发送SYN。对于服务端而言,会产生两个危险的后果:

  • 处理大量的SYN包并返回对应ACK, 势必有大量连接处于SYN_RCVD状态,从而占满整个半连接队列,无法处理正常的请求
  • 由于是不存在的 IP,服务端长时间收不到客户端的ACK,会导致服务端不断重发数据,直到耗尽服务端的资源。
如何应对 SYN Flood 攻击?
  • 增加 SYN 连接,也就是增加半连接队列的容量。
  • 减少 SYN + ACK 重试次数,避免大量的超时重发。
  • 利用 SYN Cookie 技术,在服务端接收到SYN后不立即分配连接资源,而是根据这个SYN计算出一个Cookie,连同第二次握手回复给客户端,在客户端回复ACK的时候带上这个Cookie值,服务端验证 Cookie 合法之后才分配连接资源。
关于SYN—ACK重传次数的问题

第二次握手服务器传回给客户端一个确认报文段(SYN—ACK),如果未收到客户端的确认报文段,服务器进行首次重传,等待一段时间仍未收到客户确认报文段,将进行第二次重传,每一次重传的时间是上一次的2倍。如:1s、2s、4s、8s…
如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。

ISN(Initial Sequece Number)是固定的吗?

当一端建立连接时,首部SYN = 1,同时要选择一个初始化序号seq。初始化序号随时间而变化,因此每一个连接都具有不同的seq。这样选择序号的目的:防止在网络中延迟的分组在以后又被传回,而导致某个连接的一方对它做错误的解释。

三次握手的一个重要功能是客户端与服务端交换ISN(初始化seq),以便让对方知道接下来接受数据的时候如何按序号组装数据。如果初始化seq是固定的,攻击者很容易猜出后续的确认号,因此ISN是动态生成的。

三次握手过程中可以携带数据吗?
  • 第一次、第二次不可以携带数据。因为TCP规定,SYN=1的报文段是不能携带数据的,但是要消耗一个序号。
  • 对于第三次握手是可以携带数据的,此时的客户端已经处于ESTABLISHED(已连接状态),对于客户端来说,它已经建立起了连接,并且也已经知道服务器的接受能力、发送能力是正常的,所有可以携带数据。
四次挥手

为什么会是四次挥手,那是因为TCP连接具有半关闭状态。所谓的半关闭状态就是:比如说客户端向服务端发出连接释放报文段,服务器给出了确认,这只能说明客户端到服务器端关闭了连接,但是服务器到客户端这个方向并没有关闭连接 。
客户端还是可以接受服务器的数据。

即半关闭状态就是说:建立tcp连接的某一端结束了发送之后还具有接受另一方的数据的能力。
在这里插入图片描述

  • 第一次挥手:客户端发送一个释放连接的报文段,其首部终止控制位FIN = 1,序号为u(u等于前面已经传送过的数据的最后一个字节的序号加一)。这时客户端进入FIN-WAIT1(终止等待1)状态,等待服务器的确认。与SYN=1的报文段一样,FIN =1的报文段同样不能携带数据
  • 第二次挥手:服务器收到连接释放报文段之后发送一个确认报文段,ACK = 1,ack = u+1,seq = v。此时服务器进入CLOSE-WAIT(关闭等待)状态。这时的TCP连接就处于半关闭状态。即客户端到服务器这个方向的连接已经关闭,客户端已经没有数据要发送了,但服务器若还有数据发送,客户端仍要接受。
    客户端接受到了服务器的确认之后,进入FIN-WAIT-2(终止等待2),等待服务器发出连接释放报文段。
  • 如果服务器也没有数据要发送给客户端了,就发出连接释放报文段,其 FIN = 1,ACK = 1,ack = u+1,seq = w。此时服务器进入LAST-ACK(最后确认)状态,等待客户端的确认。
  • 第四次挥手:客户端收到连接释放报文段之后,必须发送确认。在确认报文段中, 其ACK= 1,ack = w+1,seq = u+1,客户端进入TIWE-WAIT(时间等待)状态。此时TCP连接未释放掉,需要经过时间等待计时器设置的事件2MSL之后,客户端才进入CLIOSED状态。
挥手为什么要4次?

关闭连接时,服务器收到FIN报文段时,很可能还有数据没发送完,就不会立即关闭连接,只能先回复一个ACK报文段,告诉客户端,“你发送的FIN报文段我收到了”。只有等服务器的数据都发送完了,才能发送FIN报文段释放连接。所以要四次挥手。

为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
  • 首先说一下MSL:MSL(Maximum Segment Lifetime)最长报文段寿命,它是任何报文段在网络上存在的最长事件,超过这个时间报文将被丢弃。

  • 第一个原因: 为了保证客户端发送的最后一个ACK报文段能够到达服务器。因为这个ACK报文段有可能丢失,从而导致处在LAST-ACK(最后确认)状态的服务器收不到对FIN-ACK的确认报文段,服务器会超时重传这个FIN-ACK报文段,而客户端就能在2MSL时间内收到这个重传的FIN-ACK报文段,接着客户端再重传一次确认,重新启动时间等待计时器。最后双方都进入CLOSED状态。

    假如客户端不等待2MSL,而是在发送完ACK之后直接进入CLOSED状态,一旦这个ACK报文段丢失,服务器就无法正常的进入CLOSED状态。

  • 第二个原因:防止已失效的连接请求报文段出现在本连接中

    客户端在发送完最后一个ACK报文段后,再经过2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失,使下一个新的连接中不会出现这种旧的连接请求报文段。

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

除了时间等待计时器外,TCP还设有一个保活计时器。服务器每收到一次客户端的请求后会重新设置保活计时器,时间通常是2小时,若两小时还没有收到客户端的数据,服务器就发送一个探测报文段,以后则每隔75秒钟发送一次。若一连10个探测报文段后仍无客户端响应,服务器就认为客户端出了故障,接着就关闭这个连接。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值