TCP 报文格式

三次握手

三次握手,其实就是指建立一个 TCP 连接时,需要客户端和服务端发送三个数据包,主要作用就是为了确认双方的接受能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备;

建立连接的步骤

  1. 第一次握手
    • 客户端向服务端发送一个数据包:SYN=1 代表要发起新的连接,并初始化序列号(随机生成) seq=x,此时客户端处于 SYN_SENT 状态;
    • SYN=1 的报文段不能携带数据,但要消耗掉一个序号;
  2. 第二次握手
    • 服务端接收到客户端发送的数据包之后:回应发出 SYN=1 服务端也发起新的连接,发送 ACK=1 标记 ack 确认序列号是有效的,并携带确认序列号 ack=x+1,初始化服务端的初始化序列号(随机生成) seq=y
  3. 第三次握手
    • 客户端收到了服务端发送的数据包之后:回应发出 ACK=1 标记 ack 确认序列号是有效的,并携带确认序列号 ack=y+1,初始化客户端初始序列号 seq=x+1 (初始为 seq=x,第二个报文段所以要+1);
    • 此时双方已经建立了连接;

问题

  1. 为什么 http 建立连接需要三次握手?
    • 三次握手的目的:就是为了确认服务端和客户端双方的接受能力和发送能力是否正常;
      • 第一次握手:客户端发送网络数据包,服务端收到了 —-服务端得出结论:客户端的发送能力、服务端的接受能力正常;
      • 第二次握手:服务端发送网络数据包,客户端收到了 —-客户端得出结论:客户端和服务端的发送、接受能力正常,服务端不能确定客户端的接受能力;
      • 第三次握手:客户端发送网络数据包,服务端收到了 —-服务端得出结论:客户端和服务端的发送、接受能力正常;
    • 因此需要三次握手才能确认双方的接受和发送能力是否正常;
  2. 假如 http 建立连接是两次握手会发生什么?
    • 如果是两次握手,B 收到 ASYN 包后状态即为:ESTABLISHED,此时 B 再给 A 发送一个 SYN+ACK 包,由于此时 B 已经为 ESTABLISHED,所以可以向 A 发送数据,如果数据包先于 SYN+ACK 包到达 AA 就尴尬了,A 没有收到 BISN ,没法判断这些数据包是否能用(< ISN 该直接丢弃),一个优雅牛逼的协议是没法容忍这些的;
    • 如果是三次握手,B 收到 ASYN 包后状态即为:SYN_RECV,是没法发送包的;
    • 但有一点是相同的,无论是 SYN_RECV 或者 ESTABLISHED,都是一种等待状态,都需要发送数据包确认对方是否还在(SYN_RECV 会出现 SYN flood);
  3. 什么是半连接队列?
    • 服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时双方还没有完全建立连接,服务器会把此状态下的请求放到一个半连接队列里面;
    • 当然还有一个全连接队列,就是已经完成三次握手建立连接的放入到全连接队列;如果队列满了就有可能出现丢包现象;
    • 注意:
      • 服务器发送完 SYN-ACK 包,如果没有收到客户端确认,会进行首次重传,等待一段时间仍未收到确认,会继续重传,超过重传次数之后,在半连接队列中清除该连接;
      • 每次重传的时间不一定相同,一般是指数增长;
  4. ISN(Initial Sequence Number)初始化序列号是固定的吗?
    • ISN 随时间变化,这样 ISN 在网络延迟中,即使又被传送,也不会导致某个连接对它有错误的解释;
    • 三次握手的重要功能是客户端和服务端相互交换 ISN,以便然给对方知道接下来接收数据的时候如何组装数据,如果 ISN 固定的,攻击者很容易猜出来后续的确认号;
  5. 三次握手过程中可以携带数据吗?
    • 第三次握手的时候,可以携带,前两次握手不能携带数据;
    • 如果前两次握手能够携带数据,那么一旦有人想攻击服务器,那么他只需要在第一次握手中的 SYN 报文中放大量数据,那么服务器势必会消耗更多的时间和内存空间去处理这些数据,增大了服务器被攻击的风险。而对于第三次握手,此时客户端已经建立了连接,已经能够确认服务器的接收、发送能力正常,这个时候相对安全了,可以携带数据。
  6. 如果第三次握手丢失了,客户端服务端会如何处理?
    • Server 端
      • 第三次的 ACK 在网络中丢失,那么 Server 端该 TCP 连接的状态为 SYN_RECV,并且会根据 TCP 的超时重传机制,会等待 3 秒、6 秒、12 秒后重新发送 SYN+ACK 包,以便 Client 重新发送 ACK 包;
      • Server 重发 SYN+ACK 包的次数,可以通过设置 /proc/sys/net/ipv4/tcp_synack_retries 修改,默认值为 5;
      • 如果重发指定次数之后,仍然未收到 client 的 ACK 应答,那么一段时间后,Server 自动关闭这个连接;
    • Client 端
      • client 在接收到 SYN+ACK 包,它的 TCP 连接状态就为 established (已连接),表示该连接已经建立;
      • 第三次握手中的 ACK 包丢失的情况下,Client 向 server 端发送数据,Server 端将以 RST 包响应,方能感知到 Server 的错误。
  7. SYN 攻击是什么?
    • Clint 在一段时间内伪造大量的不存在的 IP,不断的像服务器发送 SYN,服务器回复确认包;
    • 由于源地址不存在,则服务端不断重发直至超时;
    • 伪造的 SYN 包会长时间占用未连接队列,导致正常的 SYN 请求因队列满而被丢弃,从而引起网络堵塞甚至系统瘫痪;
  8. 如果已经建立了连接,但是客户端突然出现故障了怎么办?
    • TCP 还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源;
    • 服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为 2 小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔 75 秒钟发送一次;
    • 若一连发送 10 个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接;

四次挥手

四次挥手(waves four times),别名连接终止协议,网络数据通信术语,其性质为终止协议;

断开连接的步骤

  1. 第一次挥手:
    • 客户端进程发出连接 释放报文,并且停止发送数据;
    • 发送 FIN=1 要结束连接,初始化序列号为 seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入 FIN-WAIT-1(终止等待1)状态;
    • TCP 规定,FIN 报文段即使不携带数据,也要消耗一个序号;
  2. 第二次挥手:
    • 服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号 seq=v,此时,服务端就进入了 CLOSE-WAIT(关闭等待)状态;
    • TCP 服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个 CLOSE-WAIT 状态持续的时间;
    • 客户端收到服务器的确认请求后,此时,客户端就进入 FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据);
  3. 第三次挥手:服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了 LAST-ACK(最后确认)状态,等待客户端的确认;
  4. 第四次挥手:客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了 TIME-WAIT(时间等待)状态,注意此时 TCP 连接还没有释放,必须经过2MSL(最长报文段寿命)的时间后,才进入 CLOSED 状态;

问题

  1. 四次挥手释放连接时,等待 2MSL 的意义?
    • 必须假想网络是不可靠的,有可能最后一个 ACK 丢失,所以 TIME_WAIT 状态就是用来重发可能丢失的 ACK 报文;
    • Server 如果没有收到 ACK,将不断重复发送 FIN 片段。所以 Client 不能立即关闭,它必须确认 Server 接收到了该 ACK;
    • Client 会在发送出 ACK 之后进入到 TIME_WAIT 状态,如果直到 2MSL,Client 都没有再次收到 FIN,那么Client 推断 ACK 已经被成功接收,则结束 TCP 连接;
  2. 挥手为什么要四次?
    • 关闭连接时,当 Server 端收到 FIN 报文时,很可能并不会立即关闭 SOCKET,所以只能先回复一个 ACK 报文,告诉 Client 端,”你发的 FIN 报文我收到了”;
    • 只有等到我 Server 端所有的报文都发送完了,我才能发送 FIN 报文,因此不能一起发送。故需要四步;

打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于产品、设计、开发的问题和看法,还有技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程

了解更多

目录

  1. 1. TCP 报文格式
  2. 2. 三次握手
    1. 2.1. 建立连接的步骤
    2. 2.2. 问题
  3. 3. 四次挥手
    1. 3.1. 断开连接的步骤
    2. 3.2. 问题