grpc timeout 代码分析

139 阅读2分钟

grpc keepalived 保活机制需要设置 tcp timeout,防止长时间占用

1. tcp 层面



// SetTCPUserTimeout sets the TCP user timeout on a connection's socket
func SetTCPUserTimeout(conn net.Conn, timeout time.Duration) error {
	tcpconn, ok := conn.(*net.TCPConn)
	if !ok {
		// not a TCP connection. exit early
		return nil
	}
	rawConn, err := tcpconn.SyscallConn()
	if err != nil {
		return fmt.Errorf("error getting raw connection: %v", err)
	}
	err = rawConn.Control(func(fd uintptr) {
		err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT, int(timeout/time.Millisecond))
	})
	if err != nil {
		return fmt.Errorf("error setting option on socket: %v", err)
	}

	return nil
}

// GetTCPUserTimeout gets the TCP user timeout on a connection's socket
func GetTCPUserTimeout(conn net.Conn) (opt int, err error) {
	tcpconn, ok := conn.(*net.TCPConn)
	if !ok {
		err = fmt.Errorf("conn is not *net.TCPConn. got %T", conn)
		return
	}
	rawConn, err := tcpconn.SyscallConn()
	if err != nil {
		err = fmt.Errorf("error getting raw connection: %v", err)
		return
	}
	err = rawConn.Control(func(fd uintptr) {
		opt, err = syscall.GetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT)
	})
	if err != nil {
		err = fmt.Errorf("error getting option on socket: %v", err)
		return
	}

	return
}



这两段代码定义了两个函数,分别用来设置和获取 TCP 连接的 用户超时时间(TCP User Timeout) ,是操作 Linux 系统底层 socket 的相关操作。

背景

  • TCP User Timeout:这是 TCP 协议提供的一个参数,表示如果一段时间内没有收到 ACK 或回应,连接会被主动关闭。它可以用于避免长时间挂起的连接。
  • 在 Linux 下,通过 setsockopt()getsockopt() 来设置或获取这个参数。

1. SetTCPUserTimeout

作用:设置某个 net.Conn 连接的 TCP 用户超时时间。

步骤

  • net.Conn 转换为 *net.TCPConn,因为只有 TCP 连接支持这个操作。

  • 调用 SyscallConn() 来获取底层的系统调用接口(file descriptor)。

  • 使用 rawConn.Control() 方法,在底层文件描述符上执行操作:

    • 调用 syscall.SetsockoptInt(),设置 TCP_USER_TIMEOUT 选项,时间单位为毫秒(timeout / time.Millisecond)。

注意

  • 如果连接不是 TCP,则直接返回 nil(不报错)。
  • 若获取或设置出错,会返回详细的错误信息。

2. GetTCPUserTimeout

作用:读取某个 net.Conn 连接的 TCP 用户超时时间。

步骤

  • 转换为 *net.TCPConn
  • 获取底层系统调用接口 rawConn
  • Control() 函数内调用 syscall.GetsockoptInt(),读取 TCP_USER_TIMEOUT 选项值。

返回值

  • 当前索设置的超时时间(单位:毫秒)。
  • 错误信息(如果有的话)。

总结

  • 这两段代码通过调用底层的系统调用(syscall.SetsockoptIntsyscall.GetsockoptInt)操作 Linux 下 TCP socket 的用户超时时间。
  • 这些操作需要底层系统支持,并且只对 TCP 连接有效。
  • 提供了封装,方便上层 Go 代码设置或获取 TCP 特性。

参考:

  1. github.com/grpc/grpc-g…