如何在go中查询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)

在TCP连接的客户端,我试图尽可能地重用已建立的连接,以避免每次需要连接时拨号的开销。从根本上说,这是连接池,尽管从技术上讲,我的池大小恰好是一个

我遇到了一个问题,如果一个连接闲置足够长的时间,另一端就会断开连接。我尝试使用以下类似的方法来保持连接的活力:

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


      套接字api不允许您访问连接状态。您可以从内核以各种方式查询当前状态(例如linux上的
      /proc/net/tcp[6]
      ),但这不能保证进一步发送会成功

      有一点我有点困惑。我的客户只发送数据。除了确认数据包外,服务器不返回任何内容。阅读似乎不是确定连接状态的合适方法,因为没有什么东西需要阅读

      套接字API的定义使您能够通过返回0字节的读取来检测闭合连接。这就是它的工作方式。在Go中,这被转换为读取返回
      io.EOF
      。这通常是检测断开连接的最快方法

      那么,我应该发送任何错误并对其采取行动吗?如果是这样的话,那就是一个问题,因为我观察到,当我试图通过一个破裂的管道发送数据时,我通常不会得到任何错误——这似乎是完全错误的

      如果仔细观察TCP是如何工作的,这就是预期的行为。如果连接在远程端关闭,则第一次发送将触发来自服务器的RST,从而完全关闭本地连接。您或者需要读取连接以检测关闭,或者如果再次尝试发送,您将得到一个错误(假设您等待数据包往返的时间足够长),比如linux上的“断管”

      为了澄清。。。我可以拨号,拔下以太网线,仍然可以发送无误。这些信息显然无法通过,但我没有收到任何错误

      如果连接真的断开了,或者服务器完全没有响应,那么您就不知道在哪里发送数据包了。TCP堆栈无法区分真正缓慢的数据包、数据包丢失、拥塞或断开的连接。系统需要等待重传超时,并在失败之前重试数据包多次。仅重试的标准配置可能需要13到30分钟才能触发错误

      在代码中可以做的是

      • 打开keepalive。这将更快地通知您断开的连接,因为空闲连接总是在测试中
      • 从插座读取数据。进行并发读取,或者使用select/poll/epoll检查要首先读取的内容(Go通常使用第一个)
      • 为每件事设定时间(围棋中的最后期限)
      如果您不希望从连接中获得任何数据,那么在Go中检查关闭的连接非常容易;分派一个goroutine从连接中读取,直到出现错误

      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