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.SetsockoptInt和syscall.GetsockoptInt)操作 Linux 下 TCP socket 的用户超时时间。 - 这些操作需要底层系统支持,并且只对 TCP 连接有效。
- 提供了封装,方便上层 Go 代码设置或获取 TCP 特性。