什么是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

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