TCP三次握手、四次挥手考点梳理(一)

198 阅读5分钟

前言: TCP的三次握手建立连接,和四次挥手断开连接的过程你能清楚的把过程描述出来吗?你清楚里面的细节考点吗,比如为什么要三次握手建立连接?? 这一篇带你梳理这里面的考点,面试遇到不再畏惧

  1. 你先说说TCP的三次握手过程

(要记住TCP的连接建立是通过状态机维持的,三次握手可围绕状态的变化进行描述)

  • 首先服务端的状态从close->listen状态(联系socket编程,首先bind,listen)
  • 客户端发送syn的tcp报文(通过把TCP报文的标志位syn位置置为1),从close->syn_sent;
  • 服务端收到后,会返回syn+ack报文给客户端。listen->syn_revd
  • 客户端收到,返回ack;syn_sent->established
  • 服务端收到ack;syn_revd->established

自此TCP三次握手建立了,下面可以挖掘挖掘这里面的考点

2. 可以两次或者四次建立TCP连接吗?

通过上面过程分析可知,TCP连接三次握手可以保证双方具有接收和发送的能力。那四次也可以,为什么不四次呢,把syn+ack,分别发送?因为syn+ack可以一起发送,没必要多一次。

那两次建立TCP连接有什么安全隐患吗?

历史连接 同步序列号 避免资源浪费

  • [ 历史连接]: 两次握手:如果客户端先发送syn,这网络阻塞,客户端挂了又重启,又发送一个新的syn,这时服务端收到syn之后,会进入established状态,可以向客户端发送数据,那客户端收到后,检查是历史连接,会返回RST,那服务端发送的数据和连接建立资源浪费了 如果是三次握手,服务器收到旧的syn,会发送syn+ack给客户端,客户端根据自身的上下文判断这是个历史连接,会返回RST给服务器,断开连接

  • [ 同步序列号]:客户端发送syn的时候,会随机生成序列号发送给服务端,表示服务端指定客户端的序列号,服务端也会随机生成序列号和ack一起发送给客户端,客户端会返回ack给服务端,服务端就知道客户端已经同步了我的序列号。如果是两次握手,只能保证一方的序列号传递成功

  • [避免浪费资源 ]:如果客户端发送的syn,由于网络阻塞,未能及时到达服务端,客户端无法及时收到ACK。那触发TCP的超时重传机制,会重新发送SYN。在两次握手情况下,会造成冗余无效连接,重复分配资源;服务端收到一个SYN,就会建立一个连接,进入established状态,因为服务端发送的ack+syn给客户端,服务端无法知晓客户端是否接受到,所以无法判断客户端是否建立了连接,只能来一个建立一个

  1. TCP三次握手中客户端和服务端的序列号每次都是一样的吗? 序列号有什么用?

序列号用处

  • 接受方可根据序列号去重
  • 接受方可根据序列号按需接受数据
  • 可通过ack序列号判断哪些包已被接受

客户端和服务端每次初始化的序列号不一样: 在一定程度上防止历史报文被下一个同样的TCP四元组接受。举个例子:客户端和服务端已经建立了TCP连接,客户端发送序列号为1的数据包在网络中阻塞,这时服务端因为某种原因重启,重新建立了相同的TCP连接,初始化序列号为1,这时这个数据包刚好落在服务端的接收窗口里,所以这就会造成数据错乱,接收了历史报文。

那么怎么生成序列号: TCP生成序列号是:时钟+hash; 时钟:4 微秒 + 1,转一圈要 4.55 个小时。 hash: 根据源 IP、目的 IP、源端口、目的端口生成一个随机数值。选择合适的hash算法

4. TCP三次握手过程中,说明一下每个握手丢失带来的后果

第一次握手丢失: 客户端发送给服务端的syn丢失,那么会触发TCP超时重传机制,客户端会重传SYN,超时重传的间隔时间会以2的倍数增加,内核规定了重传的次数和超时时间。如果SYN一直丢失,客户端不会再发送,关闭连接

第二次握手丢失: 服务端收到客户端传来的syn,返回syn+ack给客户端,syn+ack丢失。这时客户端收不到ACK,会超时重传SYN;服务端收不到ack,会超时重传syn+ack;所以第二次握手丢失,客户端和服务端都会重传,具体次数由内核规定

第三次握手丢失:客户端发送给服务端的ack丢失。ack不会重传,服务端会重传syn+ack;

  1. SYN攻击你了解吗?如何避免SYN攻击?

SYN攻击,就是黑客伪造不同IP地址的SYN发送给服务端,沾满服务端的半连接队列,导致正常的连接请求被拒绝。

修改内核参数:可以修改半连接队列大小,和服务端能接受的syn-revd的连接数

启动cookie: 如果半连接队列满了后,其他的连接返回计算出的cookie,通过syn+ack返回给客户端。客户端检查ack的合法性,合法,会放入全连接队列,可通过accept()函数取出连接