fix: tx-debug-udp 日志的写入以及发送日志调试

This commit is contained in:
2026-03-24 18:02:38 +08:00
parent 9503862eda
commit 97eb3163db
6 changed files with 570 additions and 98 deletions

View File

@@ -11,22 +11,32 @@ import (
)
// UDPConn 是对 UDP 连接的轻量封装。
// server 侧共享一个 net.UDPConnSend 时通过 peerAddr 指定对端地址
// peer 侧:独立的 net.UDPConn已通过 Dial 连接到 serverSend 直接写即可。
// server 侧共享一个 net.UDPConn通过 SendTo 指定目标地址
// peer 侧使用已连接的 net.UDPConn直接 Send 即可。
type UDPConn struct {
conn *net.UDPConn
peerAddr *net.UDPAddr // server 侧为对端地址peer 侧为 nil连接模式下直接 Write
raw syscall.RawConn // 底层 syscall 句柄,用于 Linux socket timestamping
peerAddr *net.UDPAddr
raw syscall.RawConn
logger latencylog.Logger
txTimestampDebugLogger TXTimestampDebugLogger
nodeRole string // 日志中记录的节点角色,例如 "server" 或 "peer"
nodeID string // 日志中记录的节点 ID
writeMu sync.Mutex // 保护 Send 的互斥锁
txPacketSeq uint32
pendingTX map[uint32]udpTXPendingRecord
nodeRole string
nodeID string
writeMu sync.Mutex
closeOnce sync.Once
closeErr error
}
type udpTXPendingRecord struct {
msg protocol.Message
sendCallIndex int
bytesWritten int
expectedTXID uint32
observedTimestamps map[string]int64
}
// UDPOption 用于为 UDPConn 注入可选行为。
type UDPOption func(*UDPConn)
@@ -39,7 +49,7 @@ func WithUDPLogger(logger latencylog.Logger, nodeRole, nodeID string) UDPOption
}
}
// WithUDPTXTimestampDebugLogger 为 UDP 连接注入可选的 TX errqueue 调试日志器。
// WithUDPTXTimestampDebugLogger 为 UDP 连接注入 TX errqueue 调试日志器。
func WithUDPTXTimestampDebugLogger(logger TXTimestampDebugLogger) UDPOption {
return func(conn *UDPConn) {
conn.txTimestampDebugLogger = logger
@@ -47,13 +57,12 @@ func WithUDPTXTimestampDebugLogger(logger TXTimestampDebugLogger) UDPOption {
}
// NewUDPConn 创建 UDP transport 连接封装。
// peerAddr 为 nil 时表示 peer 侧已连接模式conn 已 Dial 到 server
// peerAddr 非 nil 时表示 server 侧Send 时需要指定目标地址。
func NewUDPConn(conn *net.UDPConn, peerAddr *net.UDPAddr, opts ...UDPOption) (*UDPConn, error) {
udpConn := &UDPConn{
conn: conn,
peerAddr: peerAddr,
logger: latencylog.NoopLogger{},
conn: conn,
peerAddr: peerAddr,
logger: latencylog.NoopLogger{},
pendingTX: make(map[uint32]udpTXPendingRecord),
}
for _, opt := range opts {
@@ -72,39 +81,34 @@ func NewUDPConn(conn *net.UDPConn, peerAddr *net.UDPAddr, opts ...UDPOption) (*U
}
// Send 将一条协议消息编码为 UDP 数据报并发送。
// 多个 goroutine 可以并发调用,内部会串行化写入。
func (c *UDPConn) Send(msg protocol.Message) error {
c.writeMu.Lock()
defer c.writeMu.Unlock()
latencylog.LogMessageEvent(c.logger, c.nodeRole, c.nodeID, latencylog.EventSendHandoffBegin, msg)
latencylog.LogMessageEvent(c.logger, c.nodeRole, c.nodeID, latencylog.EventSendHandoffBegin, msg)
if err := c.sendMessageLinux(msg); err != nil {
return fmt.Errorf("transport: udp send message: %w", err)
}
latencylog.LogMessageEvent(c.logger, c.nodeRole, c.nodeID, latencylog.EventSendHandoffEnd, msg)
return nil
}
// SendTo 将一条协议消息编码为 UDP 数据报并发送到指定地址。
// 主要用于 server 侧向特定 peer 发送消息。
func (c *UDPConn) SendTo(msg protocol.Message, addr *net.UDPAddr) error {
c.writeMu.Lock()
defer c.writeMu.Unlock()
latencylog.LogMessageEvent(c.logger, c.nodeRole, c.nodeID, latencylog.EventSendHandoffBegin, msg)
latencylog.LogMessageEvent(c.logger, c.nodeRole, c.nodeID, latencylog.EventSendHandoffBegin, msg)
if err := c.sendMessageToLinux(msg, addr); err != nil {
return fmt.Errorf("transport: udp send message to %s: %w", addr, err)
}
latencylog.LogMessageEvent(c.logger, c.nodeRole, c.nodeID, latencylog.EventSendHandoffEnd, msg)
return nil
}
// Receive 从 UDP 连接读取一条完整协议消息。
// 返回解码后的消息和来源地址peer 侧来源地址始终为 server 地址)。
func (c *UDPConn) Receive() (protocol.Message, *net.UDPAddr, error) {
msg, addr, err := c.receiveMessageLinux()
if err != nil {
@@ -115,7 +119,6 @@ func (c *UDPConn) Receive() (protocol.Message, *net.UDPAddr, error) {
}
// ReceiveLoop 持续从 UDP 连接读取消息并交给 handler 处理。
// handler 的第二个参数是消息来源地址。
func (c *UDPConn) ReceiveLoop(handler func(protocol.Message, *net.UDPAddr) error) error {
for {
msg, addr, err := c.Receive()
@@ -130,8 +133,6 @@ func (c *UDPConn) ReceiveLoop(handler func(protocol.Message, *net.UDPAddr) error
}
// Close 关闭底层 UDP 连接,保证重复调用安全。
// 注意server 侧多个 UDPConn 共享同一个 net.UDPConn 时,
// 只应由 UDPHub 负责关闭底层连接,不应通过此方法关闭。
func (c *UDPConn) Close() error {
c.closeOnce.Do(func() {
c.closeErr = c.conn.Close()