dyhkwong:将底层 UDP 读取期限设为当前时间会使 quic-go 反复进入读取循环

在 Exclave #502 的高 CPU 占用反馈中,dyhkwong 给出一段与 Exclave 逻辑相似的 Go 示例:建立 QUIC 连接后,对底层 UDP socket 调用 SetReadDeadline(time.Now())。他说明,这会使所链接的 quic-go transport.go 读取循环不断重试,因为 net.Error.Temporary() 判断会持续成立。原帖附有完整示例和固定提交的源码行链接。

作者原文

Exclave has a similar logic like the following:

package main

import (
	"context"
	"crypto/tls"
	"fmt"
	"net"
	"time"

	"github.com/quic-go/quic-go"
)

func main() {
	packetConn, err := net.ListenUDP("udp", nil)
	if err != nil {
		fmt.Println(err)
		return
	}
	_, err = quic.Dial(context.Background(), packetConn, &net.UDPAddr{
		IP:   net.IPv4(223, 5, 5, 5),
		Port: 443,
	}, &tls.Config{
		ServerName: "223.5.5.5",
		NextProtos: []string{"h3"},
	}, nil)
	if err != nil {
		fmt.Println(err)
		return
	}
	packetConn.SetReadDeadline(time.Now())
	time.Sleep(time.Second * 300)
}

Setting read deadline on the underlying UDP socket causes quic-go always repeating the read loop in https://github.com/quic-go/quic-go/blob/d961427ce89f4c1b574d8ec9884516440360e0ed/transport.go#L529-L556 (nerr, ok := err.(net.Error); ok && nerr.Temporary() will always be successful).