如何实现一个可靠的 UDP

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

市面上的基于UDP协议实现的可靠传输协议的成熟方案,应用在HTTP/3上。
UDP报文头部和TCP报文头部夹着三层头部
如何实现一个可靠的 UDP_第1张图片

Packet Header

Packet Header细分这两种:

  • Long Packet Header 用于首次建立连接
  • Short Packet Header 用于日常传输数据
    如何实现一个可靠的 UDP_第2张图片
    QUIC也是需要三次握手来建立连接,主要目的是为了协商连接ID,协商出连接ID后,后续传输时,双方只需要固定住连接ID,从而实现连接迁移功能。
    Short Packet Header 中的 Packet Number 是每个报文独一无二的编号,它是严格递增的,也就是说就算 Packet N 丢失了,重传的 Packet N 的 Packet Number 已经不是 N,而是一个比 N 大的值。
    如何实现一个可靠的 UDP_第3张图片
    TCP重传报文时的序列号和原始报文的序列号一样的话:
  • 如果算成原始请求的响应,但实际上是重传请求的响应(上图左),会导致采样 RTT 变大。
  • 如果算成重传请求的响应,但实际上是原始请求的响应(上图右),又很容易导致采样 RTT 过小。

如何实现一个可靠的 UDP_第4张图片
RTO (超时时间)是基于 RTT 来计算的,那么如果 RTT 计算不精准,那么 RTO (超时时间)也会不精确,这样可能导致重传的概率事件增大。
QUIC 报文中的 Pakcet Number 是严格递增的, 即使是重传报文,它的 Pakcet Number 也是递增的,这样就能更加精确计算出报文的 RTT。
QUIC 使用的 Packet Number 单调递增的设计,可以让数据包不再像 TCP 那样必须有序确认,QUIC 支持乱序确认,当数据包Packet N 丢失后,只要有新的已接收数据包确认,当前窗口就会继续向右滑动
Packet Number 单调递增的两个好处:

  • 可以更加精确计算 RTT,没有 TCP 重传的歧义性问题;
  • 可以支持乱序确认,因为丢包重传将当前窗口阻塞在原地,而 TCP 必须是顺序确认的,丢包时会导致窗口不滑动;

QUIC Frame Header

一个Packet报文中可以存放多个QUIC Frame
如何实现一个可靠的 UDP_第5张图片
每个Frame都有明确的类型,针对类型的不同,功能也不桶,自然格式也不同。
比如Stream类型的Frame格式,Stream可以认为就是一条HTTP请求,它长的样子如下:
如何实现一个可靠的 UDP_第6张图片
Stream ID 作用:多个并发传输的 HTTP 消息,通过不同的 Stream ID 加以区别,类似于 HTTP2 的 Stream ID;
Offset 作用:类似于 TCP 协议中的 Seq 序号,保证数据的顺序性和可靠性;
Length 作用:指明了 Frame 数据的长度。
引入 Frame Header 这一层,通过 Stream ID + Offset 字段信息实现数据的有序性,通过比较两个数据包的 Stream ID 与 Stream Offset ,如果都是一致,就说明这两个数据包的内容一致。
下图中,数据包 Packet N 丢失了,后面重传该数据包的编号为 Packet N+2,丢失的数据包和重传的数据包 Stream ID 与 Offset 都一致,说明这两个数据包的内容一致。这些数据包传输到接收端后,接收端能根据 Stream ID 与 Offset 字段信息将 Stream x 和 Stream x+y 按照顺序组织起来,然后交给应用程序处理。
如何实现一个可靠的 UDP_第7张图片
QUIC 通过单向递增的 Packet Number,配合 Stream ID 与 Offset 字段信息,可以支持乱序确认而不影响数据包的正确组装。

你可能感兴趣的:(计算机基础&网络编程,网络)