TCP三次握手和四次挥手

参考面试官,不要再问我三次握手和四次挥手

TCP三次握手

在socket编程中,客户端执行connect()时,将触发三次握手。

三次握手状态图

在这里插入图片描述

需要注意的是:

  • 客户端和服务端的状态变化。
  • 发送报文的SYN、ACK标志。
  • 报文的seq和ack序列号。

首先服务端创建socket,然后用bind函数绑定端口号,再调用listen函数去监听这个端口。客户端这边创建socket,然后调用connect函数去与服务端对应的端口建立连接(期间有三次握手,半连接队列的内容)。连接成功后服务端调用accept函数从连接队列中取出socket,接收客户端请求。客户端使用send函数向socket写入信息,服务端使用recv函数从socket读取信息。

半连接队列

内核为服务器的每一个LISTEN状态的socket维护两个队列:

  1. SYN队列(半连接队列):表示处于 SYN_RECV 状态的队列;
  2. ACCEPT队列(全连接队列):表示已完成连接的队列,等待被 accept系统调用取走。

客户端使用connect函数向服务器发起TCP连接,

  • 第一次握手客户端的SYN包到达了服务器后,内核会把这个socket放到半连接队列中。
  • 服务器回一个SYN+ACK包给客户端。
  • 客户端发来了ACK包,内核把对应的socket从半连接队列中取出,再把这个连接放到全连接队列中

随后服务器调用accept函数时,其实就是直接从全连接队列中取出已经成功建立连接的socket而已。

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

不行。

原因一:如果没有第三次握手,服务器第二次握手后直接分配缓存资源、建立连接,然后等待数据,会导致服务器受到syn洪泛攻击时损失更大。

原因二:其次还要考虑这种情况:客户端共发出了两个连接请求报文段,其中第一个丢失,第二个到达了服务端建立连接,后来释放。但是第一个丢失的报文段在网络中长时间滞留后到达服务端,此时服务端误认为客户端又发出一次新的连接请求。

  • 使用三次握手:服务端分配资源,向客户端发出确认报文段,而客户端不返回ack包,则服务端超时后不建立连接,释放资源。
  • 使用两次握手:服务端分配资源,向客户端发出确认报文段,并马上建立连接,但客户端忽略服务端发来的确认,也不发送数据,则服务端一直等待客户端发送数据,浪费资源。

原因三:此外还有一个说法就是,需要三次握手才能让双方确认双方的接收与发送能力是否正常。

  1. 一次握手:客户端发包,服务端接收。
    • 服务端:确定了客户端的发送能力正常、服务端的接收能力正常。
  2. 二次握手:服务端发包,客户端接收。
    • 客户端:确定了客户端的发送、接收能力正常,服务端的发送、接收能力正常。
  3. 三次握手:客户端发包,服务端接收。
    • 服务端:确定了客户端的发送、接收能力正常,服务端的发送、接收能力正常。

如果没有第三次握手,服务端就不清楚客户端能否接收报文,不清楚服务端自己能否发送报文。

SYN洪泛攻击

SYN洪泛攻击就是伪造大量IP地址,然后向服务器不断地发送SYN包,服务器则回复syn+ack包,并等待客户端确认。

  • 这些伪造的SYN包将长时间占用半连接队列,导致正常的SYN请求因为队列满而被丢弃。
  • 由于源地址不存在,因此服务器需要不断重发,开销很大。

SYN cookie防御机制

SYN Cookie的原理和实现

背景:服务端在接收到第一次握手后把socket放进半连接队列中,等到收到第三次握手时,从半连接队列里找出对应的socket,然后放进全连接队列,并且分配缓存等资源。因此服务端在受到syn洪泛攻击时,最主要的影响就是半连接队列会被占满,导致无法处理真正的用户的请求。

SYN cookie防御机制:

  • 服务器接收到第一次握手后,不分配数据区,而是根据这个SYN报文的首部信息计算出一个cookie值。这个cookie作为第二次握手报文的初始序列号。
  • 服务器接收到第三次握手后,根据ACK报文首部信息计算cookie值,如果确认序列号等于cookie值+1,则为它分配资源,建立连接。

SYN cookie防御机制主要思想就是避免为半连接的socket分配专门数据区,从而降低SYN洪泛攻击所带来的资源开销,同时借助序列号来保存半连接socket的信息,不影响后面第三次握手建立连接。

ISN(Initial Sequence Number,初始化序列号)是固定的吗?

三次握手的其中一个重要功能是客户端和服务端交换初始序列号,以便让对方知道接下来接收数据的时候如何按序列号组装数据。

ISN是动态生成的。不用固定的初始化序号的原因是:

  1. 容易被攻击者伪造序列号进行攻击。
  2. 容易混淆,网络中滞留的报文和客户端新发的报文序列号相同,二者到达服务器时无法区分。

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

第一握手不可以携带数据,第三次握手可以。

  • 第一次握手不可以带数据,否则会让服务器在受到SYN洪泛攻击时,不得不接收大量无用的数据。
  • 第三次握手的时候,客户端已经处于 ESTABLISHED 状态。客户端已经知道双方的接收、发送能力正常,所以能携带数据。

TCP四次挥手

在socket编程中,任何一方执行close()操作即可产生挥手操作。

四次挥手状态图:

在这里插入图片描述

需要注意的是:

  • 客户端和服务端的状态变化。
  • 发送报文的SYN、ACK标志。
  • 报文的seq和ack序列号。

第二次挥手完成后,TCP处于半关闭状态,即客户端到服务端的连接关闭了,但服务端到客户端的连接还没有关闭 ,服务端继续发送剩下的数据。

挥手为什么需要四次?

关闭连接需要4次挥手,是因为TCP的半关闭机制。第二次握手服务器只是发送了一个ACK包告诉客户端自己收到了FIN报文,随后还要继续发送剩下的数据,然后才发送FIN+ACK报文。如果只有三次挥手的话,服务器就不允许发送剩下的数据,应该立刻发送FIN+ACK报文回应。

TIME_WAIT的作用

2MSL = 去向ACK包最大存活时间(MSL) + 来向重发的FIN+ACK包的最大存活时间(MSL)。

主动关闭方发出最后一次握手后要等待2MSL的原因:

  1. 保证客户端发送的第四次挥手能够到达服务端(ACK报文超时后,服务端重发第三次挥手),如果不等待2MSL,直接释放连接,可能ACK报文丢失导致对方不能正常进入CLOSED状态。。
  2. 可以使本连接所产生的所有报文段都从网络中消失,不会影响到下一条连接。

报文段最大生存时间MSL(Maximum Segment Lifetime):MSL是指任何报文段被丢弃前在网络内滞留的最长时间,它与ip数据包的TTL(可经过的最多路由跳数)有关。

服务端出现大量TIME_WAIT和CLOSE_WAIT

linux服务器下可以用netstat 命令看到处于各个状态下的连接数。比如ESTABLISHED 表示正在通信,TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭。

大量连接处于TIME_WAIT或CLOSE_WAIT状态会导致大量的socket被占用,服务器无法处理新的请求。

TIME_WAIT

原因:服务端主动关闭连接,但因为网络问题或者客户端问题导致一直需要重发第四次握手。

解决方法:修改系统内核的TCP参数,快速回收和重用TIME_WAIT的连接。(开启net.ipv4.tcp_tw_reuse和net.ipv4.tcp_tw_recycle可以快速回收处于TIME_WAIT状态的资源。)

在高并发短连接的TCP服务器上,当服务器处理完请求后立刻主动正常关闭连接。这个场景下会出现大量socket处于TIME_WAIT状态(这里短连接表示“业务处理+传输数据的时间 远远小于 TIMEWAIT超时的时间”的连接)。

CLOSE_WAIT

服务端被动关闭连接,如果有大量连接处于CLOSE_WAIT状态(半关闭),那么原因肯定就是服务端还没有调用close函数关闭连接,具体有两种情况。

1、服务器在半关闭的状态下处理速度过慢,或者说仍在发送大量的数据给客户端。(具体情况具体处理)

2、服务器出现了错误,比如说忘记写发送第三次挥手的语句之类的,需要检查代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值