开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情
一、QUIC流的状态机
QUIC流的类型分为单向和双向,QUIC流的状态机也被设计成两种:
- 发送状态机
- 接收状态机
当使用单向流时,发送端使用发送状态机,接收端使用接收状态机。
若使用双向流,两端均会启用两种状态机。
本文主要介绍QUIC的发送端状态机。
二、QUIC流发送端状态机详解
QUIC流的发送端状态机包括一种初始状态,三种中间状态和两种结束状态。
先看图片,对状态机的状态流转有一个整体的印象,下面会逐个解释每个状态的含义,以及在其状态下能做哪些动作、响应哪几种流帧。
初始状态
Ready
当一个发送流(可以是单向流,也可以是双向流的发送部分)被创建后,它的初始状态即是Ready。
在Ready状态下是不能发送应用数据的,需要先发送一个STREAM帧或STREAM_DATA_BLOCKED帧进入Send状态。
虽然在Ready状态下不能向对端发送数据,但在实现QUIC协议时是否允许上层传入将要发送的数据呢?答案是可以的,虽然不能直接发给对端,但可以将数据缓存起来,当状态从Ready变更为Send的时候再将缓存的数据发送出去。这样做的一个好处是减少了与上层的状态交互。
如果还未发送数据,就要将流关闭怎么办?这时就需要发送一个RESET_STREAM帧通知接收端进入Reset Sent状态。
总结下Ready的状态转换:
三种中间状态
Send
Send是由Ready状态转换来的,只有处于这个状态时才能向对端发送新的数据。
处于这个状态时还必须要接收并处理对端发来的MAX_STREAM_DATA帧,该类型的帧里面包含了流控限制信息,实现QUIC协议时要注意发送的数据不超过此限制。
若发送端要发送的数据较多,超过了流控的限制出现被阻塞的情况,则需要通知接收端"发送被阻塞"的情况,会持续发送STREAM_DATA_BLOCKED帧。
可以看到MAX_STREAM_DATA和STREAM_DATA_BLOCKED两种类型的帧是QUIC实现流控的关键。
数据发送完成后,想正常的关闭流,这时发送端会发送一个设置了FIN位的STREAM帧给接收端,进入Data Sent状态。
数据没有发送完,但有突发情况要中断流,这时发送端会发送RESET_STREAM帧,然后进入Reset Sent状态。
总结下Send的状态转换:
Data Sent
Data Sent状态是由Send状态转换而来,表明数据已经发送完毕,但该状态仍是一个中间状态,为什么不是最终状态呢?
因为虽然本端的数据都已经发送完毕了,但还不能确认对端将数据接收完整,若发生了网络丢包现象,本端还要向对端重传数据。所以在Data Sent状态下仍是可以发送数据的,只不过不能发送新数据,只能重传数据。
另外,处于Data Sent状态时,可能仍会收到对端发送的MAX_STREAM_DATA帧,但不需要处理,直接忽略就可以了。
那什么时候进入下一个状态呢?当本端知道所有已发送的数据都被对端正常接收后,也就是收到了所有已发送数据的ACK响应时,就可以进入Data Recvd的结束状态了。
总结下Data Sent的状态转换:
Reset Sent
Reset Sent可以由Ready、Send、Data Sent三种状态转换而来。
可以看出Reset是一种更暴力的中断流的方法,无论发送端是否发送了数据,无论数据是否发送完成,无论是否有数据还未收到确认,都可以通过发送RESET_STREAM进入Reset Sent状态。
总结下Reset Sent的状态转换:
两种结束状态
Data Recvd
Data Recvd是一种结束状态,由Data Sent转换而来。
该状态代表数据发送完成后所有已发送的数据都被正常接收,此时可以释放资源了。
Reset Recvd
Reset Recvd也是一种结束状态,由Reset Sent转换而来,一旦收到对端的Recv Ack就可以进入Reset Recvd状态了。
该状态代表了对端已经收到了RESET_STREAM帧,知晓该流要被关闭了,发送端处于此状态下可以释放资源了。
三、总结与思考
我们可以看到QUIC的发送端状态机状态设计足够简洁,它只有六个状态,且状态之间的转换也很清晰。
去掉起始状态与两种结束状态,只有三个中间状态的有特定的行为。
- Send状态 可以发送数据、重传数据,接收对端发来的数据ACK和流控通知。
- Data Sent状态 只能发送重传数据,接收对端的数据ACK。
- Reset Sent状态 只接收对端的 Reset ACK。
为了理解的更深刻,在了解QUIC发送端状态机时,可以设想去掉某个状态是否可行,去掉某个状态后"流"的功能还能否完整实现,会给"流"的自由度带来哪些损失。
无论是用某种语言实现一个QUIC库,还是去设计一种新的"流",理解好QUIC流的状态机都有一定的价值。
如果本文的内容有错误或疏漏欢迎在评论区指正、补充。
如果您觉得本文有用,不妨点个赞,感谢您的鼓励。