TCP可靠传输和UDP实现可靠传输
为什么有了TCP还要QUIC?
我们知道TCP可以支持可靠传输,但是为什么还需要基于UDP在应用层再实现一个可靠传输的QUIC协议?QUIC协议在HTTP3被使用,为了解决HTTP2的TCP队头阻塞的问题(当某个TCP分片丢失,后续的TCP分片都无法被确认)、TCP握手的时延问题、一方更换IP需要重新建立连接等问题,将传输层协议由TCP改成了UDP,但是UDP是不保证报文段可以到达对方的,只是尽最大努力交付,而下层的IP协议也是不可靠的,我们只好在应用层实现一个可靠的协议,也就是QUIC协议。
QUIC协议如何实现?
那么TCP主要干了两件事情,一个是让乱序的包有序(这样可以知道哪些包丢失了)、一个是包重传和流量、拥塞控制。
QUIC Frame Header
先来看看为什么包会乱序,也可以说是HTTP请求乱序?一开始的TCP连接并没有实现HTTP并行,也就是必须要等到上一个HTTP的请求收到响应之后才能发出下一个HTTP请求这种一问一答的形式,后面增加了滑动窗口这个机制(在内核实现一个缓存),让HTTP可以在窗口大小的范围内实现并发,每个HTTP请求都对应有发出的顺序(也就是seq序列号)进行排序,只有收到这个HTTP请求的所有响应数据之后,滑动窗口才会移动,每个包在TCP头部都有一个seq字段(序列号)配合ACK表明数据包是否丢失,通过包的seq判断包对应的HTTP请求的顺序。
而QUIC的实现是用了QUIC Frame Header的offset字段类似这个seq字段的作用,用于表明HTTP请求的顺序,同时有Stream ID来看看是哪个HTTP请求。
Packet Header
TCP发现丢包之后,会重传相同seq的包,直到收到ACK或者重传次数超过上限。
在Packet Header实现了类似TCP握手的过程,用Packet Number字段将TCP的seq代替,而Packet Number字段是严格递增的,包重传的Packet Number是不同的,收到的ACK也不同,这样可以支持乱序确认,而TCP是需要等到这个请求的所有响应包收到之后才能收下一个HTTP请求的包(TCP不就是需要有序性吗),那如何保证这个包和重传的包是一样的数据呢?或者说如何确是否丢包呢?通过QUIC Frame Header的offset字段和Stream ID字段比较可以确定。