如何在go中查询TCP连接状态?
在TCP连接的客户端,我试图尽可能地重用已建立的连接,以避免每次需要连接时拨号的开销。从根本上说,这是连接池,尽管从技术上讲,我的池大小恰好是一个 我遇到了一个问题,如果一个连接闲置足够长的时间,另一端就会断开连接。我尝试使用以下类似的方法来保持连接的活力:如何在go中查询TCP连接状态?,tcp,go,Tcp,Go,在TCP连接的客户端,我试图尽可能地重用已建立的连接,以避免每次需要连接时拨号的开销。从根本上说,这是连接池,尽管从技术上讲,我的池大小恰好是一个 我遇到了一个问题,如果一个连接闲置足够长的时间,另一端就会断开连接。我尝试使用以下类似的方法来保持连接的活力: err = conn.(*net.TCPConn).SetKeepAlive(true) if err != nil { fmt.Println(err) return } err = conn.(*net.TCPConn)
err = conn.(*net.TCPConn).SetKeepAlive(true)
if err != nil {
fmt.Println(err)
return
}
err = conn.(*net.TCPConn).SetKeepAlivePeriod(30*time.Second)
if err != nil {
fmt.Println(err)
return
}
但这没用。事实上,这导致了我的连接更快地关闭。我很确定这是因为(在Mac上)这意味着连接健康状况在30秒后开始被探测,然后每隔30秒被探测8次。服务器端不能支持keepalive,因此4分30秒后,客户端将断开连接
我可能无法无限期地保持空闲连接的活动状态,如果有某种方法可以让我至少检测到一个连接已关闭,这样我就可以无缝地用一个新连接替换它,那就完全可以了。唉,即使在阅读了所有的文档并在博客圈中寻找帮助之后,我仍然找不到任何方法来查询TCP连接的状态
一定有办法。有人对如何实现这一目标有什么见解吗?非常感谢所有这样做的人
编辑:
理想情况下,我想学习如何使用纯go处理这个低级问题,而不使用第三方库来实现这一点。当然,如果有这样的库,我不介意被指向它的方向,这样我就可以看到它们是如何做到这一点的。- 根据设计,没有“TCP连接状态”这样的东西。只有当你发送东西时才会发生什么。没有任何一个TCP API,在任何一个低到硅的级别上,都可以告诉您TCP连接的当前状态。你必须试着使用它
- 如果您正在发送keepalive探测,服务器除了做出适当的响应外别无选择。服务器甚至不知道它们是keepalive。他们不是。它们只是重复的ACK。支持keepalive仅仅意味着支持发送keepalive
- 根据设计,没有“TCP连接状态”这样的东西。只有当你发送东西时才会发生什么。没有任何一个TCP API,在任何一个低到硅的级别上,都可以告诉您TCP连接的当前状态。你必须试着使用它
- 如果您正在发送keepalive探测,服务器除了做出适当的响应外别无选择。服务器甚至不知道它们是keepalive。他们不是。它们只是重复的ACK。支持keepalive仅仅意味着支持发送keepalive
/proc/net/tcp[6]
),但这不能保证进一步发送会成功
有一点我有点困惑。我的客户只发送数据。除了确认数据包外,服务器不返回任何内容。阅读似乎不是确定连接状态的合适方法,因为没有什么东西需要阅读
套接字API的定义使您能够通过返回0字节的读取来检测闭合连接。这就是它的工作方式。在Go中,这被转换为读取返回io.EOF
。这通常是检测断开连接的最快方法
那么,我应该发送任何错误并对其采取行动吗?如果是这样的话,那就是一个问题,因为我观察到,当我试图通过一个破裂的管道发送数据时,我通常不会得到任何错误——这似乎是完全错误的
如果仔细观察TCP是如何工作的,这就是预期的行为。如果连接在远程端关闭,则第一次发送将触发来自服务器的RST,从而完全关闭本地连接。您或者需要读取连接以检测关闭,或者如果再次尝试发送,您将得到一个错误(假设您等待数据包往返的时间足够长),比如linux上的“断管”
为了澄清。。。我可以拨号,拔下以太网线,仍然可以发送无误。这些信息显然无法通过,但我没有收到任何错误
如果连接真的断开了,或者服务器完全没有响应,那么您就不知道在哪里发送数据包了。TCP堆栈无法区分真正缓慢的数据包、数据包丢失、拥塞或断开的连接。系统需要等待重传超时,并在失败之前重试数据包多次。仅重试的标准配置可能需要13到30分钟才能触发错误
在代码中可以做的是
- 打开keepalive。这将更快地通知您断开的连接,因为空闲连接总是在测试中
- 从插座读取数据。进行并发读取,或者使用select/poll/epoll检查要首先读取的内容(Go通常使用第一个)
- 为每件事设定时间(围棋中的最后期限)
notify := make(chan error)
go func() {
buf := make([]byte, 1024)
for {
n, err := conn.Read(buf)
if err != nil {
notify <- err
return
}
if n > 0 {
fmt.Println("unexpected data: %s", buf[:n])
}
}
}()
notify:=make(chan错误)
go func(){
buf:=make([]字节,1024)
为了{
n、 错误:=conn.Read(buf)
如果错误!=零{
通知0{
fmt.Println(“意外数据:%s”,buf[:n])
}
}
}()
套接字api不允许您访问连接状态。您可以通过各种方式从内核查询当前状态(例如linux上的/proc/net/tcp[6]
),但这不能保证进一步发送wi