基于UDP的可靠传输协议QUIC协议

  • 基于 UDP 协议实现的可靠传输协议的成熟方案了,那就是 QUIC 协议,已经应用在了 HTTP/3。

  • QUIC是如何实现可靠传输的

    • 基于 UDP 协议实现的可靠传输协议的成熟方案了,那就是 QUIC 协议,已经应用在了 HTTP/3。

    • Packet header

      • Packet Header 首次建立连接时和日常传输数据时使用的 Header 是不同的

      • QUIC 也是需要三次握手来建立连接的,主要目的是为了协商连接 ID。协商出连接 ID 后,后续传输时,双方只需要固定住连接 ID,从而实现连接迁移功能。

      • Short Packet Header 中的 Packet Number 是每个报文独一无二的编号,它是严格递增的,也就是说就算 Packet N 丢失了,重传的 Packet N 的 Packet Number 已经不是 N,而是一个比 N 大的值。

      • 为什么要这么设计呢?

        • QUIC 报文中的 Pakcet Number 是严格递增的, 即使是重传报文,它的 Pakcet Number 也是递增的,这样就能更加精确计算出报文的 RTT。

        • 还有一个好处,QUIC 使用的 Packet Number 单调递增的设计,可以让数据包不再像 TCP 那样必须有序确认,QUIC 支持乱序确认,当数据包Packet N 丢失后,只要有新的已接收数据包确认,当前窗口就会继续向右滑动

    • QUIC Frame Header

      • 一个 Packet 报文中可以存放多个 QUIC Frame。

      • 每一个 Frame 都有明确的类型,针对类型的不同,功能也不同,自然格式也不同。

      • 引入 Frame Header 这一层,通过 Stream ID + Offset 字段信息实现数据的有序性,通过比较两个数据包的 Stream ID 与 Stream Offset ,如果都是一致,就说明这两个数据包的内容一致。

      • QUIC 通过单向递增的 Packet Number,配合 Stream ID 与 Offset 字段信息,可以支持乱序确认而不影响数据包的正确组装

  • QUIC是如何解决TCP的队头阻塞问题的

    • 没有队头阻塞的QUIC

      • 在一条 QUIC 连接上可以并发发送多个 HTTP 请求 (Stream)。

      • QUIC 给每一个 Stream 都分配了一个独立的滑动窗口,这样使得一个连接上的多个 Stream 之间没有依赖关系,都是相互独立的,各自控制的滑动窗口。

      • 假如 Stream2 丢了一个 UDP 包,也只会影响 Stream2 的处理,不会影响其他 Stream,与 HTTP/2 不同,HTTP/2 只要某个流中的数据包丢失了,其他流也会因此受影响。

  • QUIC是如何做流量控制的

    • QUIC 实现流量控制的方式:

      • 通过 window_update 帧告诉对端自己可以接收的字节数,这样发送方就不会发送超过这个数量的数据。

      • 通过 BlockFrame 告诉对端由于流量控制被阻塞了,无法发送数据。

      • QUIC 是基于 UDP 传输的,而 UDP 没有流量控制,因此 QUIC 实现了自己的流量控制机制,QUIC 的滑动窗口滑动的条件跟 TCP 有一点差别,但是同一个 Stream 的数据也是要保证顺序的,不然无法实现可靠传输,因此同一个 Stream 的数据包丢失了,也会造成窗口无法滑动。

      • QUIC 的 每个 Stream 都有各自的滑动窗口,不同 Stream 互相独立,队头的 Stream A 被阻塞后,不妨碍 StreamB、C的读取。

      • QUIC 实现了两种级别的流量控制,分别为 Stream 和 Connection 两种级别:

        • Stream 级别的流量控制:Stream 可以认为就是一条 HTTP 请求,每个 Stream 都有独立的滑动窗口,所以每个 Stream 都可以做流量控制,防止单个 Stream 消耗连接(Connection)的全部接收缓冲。

        • Connection 流量控制:限制连接中所有 Stream 相加起来的总字节数,防止发送方超过连接的缓冲容量。

      • Stream 级别的流量控制

        • 接收窗口的左边界取决于接收到的最大偏移字节数,此时的接收窗口 = 最大窗口数 - 接收到的最大偏移数

        • 看出 QUIC 的流量控制和 TCP 有点区别了:

          • TCP 的接收窗口只有在前面所有的 Segment 都接收的情况下才会移动左边界,当在前面还有字节未接收但收到后面字节的情况下,窗口也不会移动。

          • QUIC 的接收窗口的左边界滑动条件取决于接收到的最大偏移字节数。

      • Connection 流量控制

        • Connection 级别的流量窗口,其接收窗口大小就是各个 Stream 接收窗口大小之和

        • 上图所示的例子,所有 Streams 的最大窗口数为 120,其中

          • Stream 1 的最大接收偏移为 100,可用窗口 = 120 - 100 = 20

          • Stream 2 的最大接收偏移为 90,可用窗口 = 120 - 90 = 30

          • Stream 3 的最大接收偏移为 110,可用窗口 = 120 - 110 = 10

        • 那么整个 Connection 的可用窗口 = 20 + 30 + 10 = 60

          可用窗口 = Stream 1 可用窗口 + Stream 2 可用窗口 + Stream 3 可用窗口

  • QUIC对拥塞控制改进

    • QUIC 是处于应用层的,应用程序层面就能实现不同的拥塞控制算法,不需要操作系统,不需要内核支持

    • QUIC 可以随浏览器更新,QUIC 的拥塞控制算法就可以有较快的迭代速度。

    • QUIC 处于应用层,所以就可以针对不同的应用设置不同的拥塞控制算法

  • QUIC更快的连接建立

    • QUIC 内部包含了 TLS,它在自己的帧会携带 TLS 里的“记录”,再加上 QUIC 使用的是 TLS1.3,因此仅需 1 个 RTT 就可以「同时」完成建立连接与密钥协商,甚至在第二次连接的时候,应用数据包可以和 QUIC 握手信息(连接信息 + TLS 信息)一起发送,达到 0-RTT 的效果。

  • QUIC是如何迁移连接的

    • 基于 TCP 传输协议的 HTTP 协议,由于是通过四元组(源 IP、源端口、目的 IP、目的端口)确定一条 TCP 连接。

    • 当移动设备的网络从 4G 切换到 WIFI 时,意味着 IP 地址变化了,那么就必须要断开连接,然后重新建立 TCP 连接。

    • QUIC 协议没有用四元组的方式来“绑定”连接,而是通过连接 ID来标记通信的两个端点,客户端和服务器可以各自选择一组 ID 来标记自己,因此即使移动设备的网络变化后,导致 IP 地址变化了,只要仍保有上下文信息(比如连接 ID、TLS 密钥等),就可以“无缝”地复用原连接,消除重连的成本,没有丝毫卡顿感,达到了连接迁移的功能。

相关推荐

  1. 基于UDP可靠传输协议QUIC协议

    2024-03-31 11:44:06       14 阅读
  2. 基于udp可靠传输协议kcp介绍,C++测试kcp示例

    2024-03-31 11:44:06       28 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-31 11:44:06       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-31 11:44:06       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-31 11:44:06       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-31 11:44:06       20 阅读

热门阅读

  1. AtCoder_ABC130_Rectangle Cutting

    2024-03-31 11:44:06       12 阅读
  2. 什么是计算机视觉?计算机视觉:从基础到前沿

    2024-03-31 11:44:06       14 阅读
  3. 算法与数据结构 顺序表

    2024-03-31 11:44:06       17 阅读
  4. sql注入相关题目

    2024-03-31 11:44:06       11 阅读
  5. node.js 常用命令

    2024-03-31 11:44:06       12 阅读
  6. C# comboBox

    2024-03-31 11:44:06       12 阅读
  7. MyBatis——动态SQL

    2024-03-31 11:44:06       11 阅读
  8. 在Python中,当你执行 print(2, 3) 时

    2024-03-31 11:44:06       14 阅读
  9. LeetCode刷题--- 回文子串

    2024-03-31 11:44:06       17 阅读
  10. Mysql数据库调优

    2024-03-31 11:44:06       15 阅读
  11. leetcode 704. 二分查找

    2024-03-31 11:44:06       15 阅读
  12. SQLAlchemy中常用的查询方法[示例学习]

    2024-03-31 11:44:06       13 阅读