quicgo

quic-go/quic-go 简介: Go语言实现的QUIC协议。(QUIC是一个兼顾TCP连接的可靠性,同时大幅降低延迟的通用网络传输层协议) | GitHub 中文社区

https://www.github-zh.com/projects/55637575-quic-go

quic-go 是 Go 中 QUIC 协议(RFC 9000、RFC 9001、RFC 9002)的实现。它支持 HTTP/3 (RFC 9114),包括 QPACK (RFC 9204) 和 HTTP 数据报 (RFC 9297)。

除了这些基本 RFC 之外,它还实现以下 RFC:

不可靠的数据报扩展 (RFC 9221)
数据报数据包化层路径 MTU 发现(DPLPMTUD、RFC 8899)
QUIC 版本 2 (RFC 9369)
使用 qlog 的 QUIC 事件日志记录(draft-ietf-quic-qlog-main-schema 和 draft-ietf-quic-qlog-quic-events)
在 webtransport-go 中实现了对基于 HTTP/3 的 WebTransport (draft-ietf-webtrans-http3) 的支持。

由于 HTTP 数据报支持是 HTTP/3 扩展,因此需要先使用 HTTP/3 设置进行协商,然后才能使用。由于 SETTINGS 是以单向流形式发送的,因此不能保证 SETTINGS 在 QUIC 握手完成后立即可用。

例如,如果客户端在握手完成后立即发送请求,并且包含 SETTINGS 的 QUIC 数据包丢失,则在收到重新传输之前,SETTINGS 将不可用。

要使用 HTTP 数据报,服务器需要检查是否实际启用了支持。

验证 HTTP 数据报后,可以通过类型断言 http 来“接管”流。ResponseWriter 添加到 http3.HTTPStreamer 并调用 HTTPStream 方法。返回的 http3.Stream 有两种方法 SendDatagram 和 ReceiveDatagram,分别用于发送和接收数据报。

调用 HTTPStream 后,流在读取、写入和流取消方面的行为类似于 QUIC 流。

当写入 http.ResponseWriter,HTTP/3 层使用 HTTP/3 DATA 帧应用帧。通过接管流,我们可以访问底层的 QUIC 流:传递给 Write 的数据直接写入流,Read 直接从流中读取。这是 RFC 9297 第 3 节中定义的 Capsule 协议的要求。

在客户端,客户端需要使用 http3。SingleDestinationRoundTripper。使用 http3 时,无法使用 HTTP 数据报。往返。

http3.SingleDestinationRoundTripper 管理到远程服务器的单个 QUIC 连接。

客户端需要通过检查 SETTINGS 来检查服务器启用的 HTTP 数据报是否支持:

// ... dial a quic.Connection to the target server
// make sure to set the "h3" ALPN
rt := &http3.SingleDestinationRoundTripper{
    Connection:      qconn,
    EnableDatagrams: true,
}
conn := rt.Start()
// wait for the server's SETTINGS
select {
case <-conn.ReceivedSettings():
case <-conn.Context().Done():
    // connection closed
    return
}
settings := conn.Settings()
if !settings.EnableDatagrams {
    // no datagram support
    return
}

由于 HTTP/3 服务器可以以 0.5-RTT 数据发送 SETTINGS,因此 SETTINGS 通常在 QUIC 握手完成后立即可用(除非数据包丢失或未优化的 HTTP/3 服务器实现)。

str, err := rt.OpenRequestStream(ctx)
// ... handle error ...

// send the HTTP request
err = str.SendRequestHeader(req)
// ... handle error ...
// It now takes (at least) 1 RTT until we receive the server's HTTP response.
// We can start sending HTTP datagrams now.
go func() {
    // send an HTTP datagram
    err := str.SendDatagram([]byte("foobar"))
    // ... handle error ...

    // receive an HTTP datagram
    data, err := str.ReceiveDatagram(context.Background())
    // ... handle error ...
}()

// read the server's HTTP response
rsp, err := str.ReadResponse()
// ... handle error ...
SingleDestinationRoundTripper 将 HTTP 请求的发送和 HTTP 响应的接收拆分为两个单独的 API 调用(将其与标准库的 RoundTrip 函数进行比较)。原因是发送 HTTP 请求和从服务器接收 HTTP 响应需要(至少)一次网络往返。RFC 9297 允许在发送请求后立即发送 HTTP 数据报。

你可能感兴趣的:(开发语言)