什么是 TCP

  1. TCP 是一个全双工面向字节流的基于 IP 协议的协议。
  2. TCP 端到端的准确传输。
    1. 对于每一个字节进行确认
    2. 对于恶劣的网络情况的处理
      1. 超时重传
      2. 拥塞控制
    3. 效率提升
      1. 采用滑动窗口协议
  3. TCP 是一个面向连接的协议。

既然面向连接那这个连接是怎么建立的?

也就是下面的问题如果建立一个虚拟的链路采用三次握手。

三次挥手是怎么发生的

详细操作

image-20200331164958404

从码出高效扒了一张图下来,我们来讲一下三次握手的流程:

  • A 机器首先会计算出一个 seq 索引 x 表示当前发送的数据包的位置并且包的标示为 SYN。
  • B 机器接受到了这个包,并且将包中的数据存到自己的缓冲区中,因为这个包的大小为 1 字节,所以缓存区的索引是 x + 1 同步到对方的发送 seq 位置,返回一个 SYN 和 ACK 标示的包,并且将自己的发送 seq 索引 y 以及告诉对方自己收到了这个数据包所以 ack + 1。
  • C 机器收到这个带有 ACK 和 SYN 的包需要返回一个 ACK 表示自己能够收到对方的包,所以发送一个 ACK 和自己当前的发送 seq 以及自己的接受 seq。

为啥要握三次

至于为啥要握三次

主要有两点:

确保数据的对等性

  1. 首先需要确保双方的 seq 是彼此的接受与发送的缓冲区索引

  2. 确保彼此的接受和发送能力

    第三次握手能保证 B 机器的发报能力,以及 A 机器的接受能力

    image-20200331170448728

防止脏连接

image-20200331171058004

A 机器发送一个 SYN 包给 B 机器但是这个包被因为网络原因没有及时发到,又由于 TCP 的超时时间小于 TTL 因为如果 TCP 的超时间太长,那么重发封包的效率会很慢。

所以 A 机器又会发送一个 TCP,并且建立了连接,此时这个包已经到了 B 机器。

B 机器重新建立了连接,返回一个 ACK 给 A 机器。

如果只有两次握手的话,在 B 机器的视角就是已经建立了连接,但是 A 收到 B 的 Ack 的时候由于不是 SYN_SEND 所以直接丢弃,B 也无法感知,也就 B 存在单方面的脏连接了。

三次握手的话,B 需要有一次 A 的 ACK 确保自己的发送能力,同时也避免了脏连接,A 不会发送 ACK 给 B 所以 B 的视角也不会存在连接。

四次挥手是如何发生的

详细操作

image-20200331174147939

确保双方的数据都处理完成。

  • A 发送剩余数据已经 FIN 给 B 处于 FIN_WAIT
  • B 回复 ACK 给 A
  • B 等待一个 CLOSE_WAIT 再发送剩余的数据给 A
  • A 回复 ACK 表示数据收到并等待 TIME_WAIT

为啥要四次挥手

需要保证双方的数据都处理完毕,并且彼此都知道。

第三次挥手是因为 A 机器告诉 B 机器不能传输数据并且 B 机器 ACK 之后,B 机器需要等待应用程序做一个处理才能发送一个 FIN 告诉 A 机器自己不能传输数据了。

第四次挥手是告诉 B 机器自己已经接受到 B 机器无法发送请求的事实。

TCP keepalive vs Http keepalive

HTTP

Http 如果在 header 添加 keepalive = true 就会使多个 http 请求在一条 TCP 连接上,不会像之前一样一个请求握手挥手一次。

优点:

降低服务端负载,在高并发的服务器下,服务端负载会减小

降低每个 http 请求的时间,因为如果是 http 请求都会有 SSL 或者 TSL 的行为和三次握手四次挥手,所以会很慢,但是 reduce 到一个连接就不会这样了。

TCP

是 OS 来维护的,因为每个 TCP 连接都有各种各样的定时器,TCP 也有 keepalive 的定时器,当 TCP 的 keepalive 定时器到达 0 的时候,就会向对方发送一个 ACK 为开启的探测包,因为 TCP 是面向流的协议。另一方面,您将收到来自远程主机的答复。并且这两个数据包的数据为空。

优点:

判断对方是否是 dead peer

防止由于网络不活动而断开连接。