为了账号安全,请及时绑定邮箱和手机立即绑定

go中如何查询TCP连接状态?

go中如何查询TCP连接状态?

Go
跃然一笑 2021-11-15 15:19:51
在 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 来处理低级别的问题。当然,如果有一些图书馆这样做,我不介意指出它的方向,这样我就可以看到他们是如何做到的。
查看完整描述

2 回答

?
qq_遁去的一_1

TA贡献1725条经验 获得超7个赞

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

我在这里有点困惑。我的客户只发送数据。除了确认数据包外,服务器不会返回任何内容。阅读似乎不是确定连接状态的合适方法,因为有注意阅读。

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

那么我是否应该只发送并处理发生的任何错误?如果是这样,这是一个问题,因为我观察到在尝试通过损坏的管道发送时,我通常根本不会收到任何错误——这似乎完全错误

如果您仔细观察 TCP 的工作原理,就会发现这是预期的行为。如果连接在远程端关闭,那么您的第一次发送将触发来自服务器的 RST,完全关闭本地连接。您要么需要从连接中读取数据以检测关闭,或者如果您再次尝试发送,您将收到一个错误(假设您等待数据包来回的时间足够长),例如 linux 上的“管道损坏” .

澄清一下......我可以拨号,拔下以太网电缆,然后仍然没有错误地发送。显然,消息没有通过,但我没有收到任何错误

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

你可以在你的代码中做的是

  • 开启保活。这将更快地通知您连接断开,因为空闲连接始终在测试中。

  • 从套接字读取。要么进行并发读取,要么使用 select/poll/epoll 检查要先读取的内容(Go 通常使用第一个)

  • 为所有内容设置超时(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])

        }

    }

}()


查看完整回答
反对 回复 2021-11-15
?
慕哥9229398

TA贡献1877条经验 获得超6个赞

  • 按照设计,没有“TCP 连接状态”这样的东西。只有当你发送一些东西时才会发生什么。没有任何级别的 TCP API 可以告诉您 TCP 连接的当前状态,在任何级别上都没有硅。你必须尝试使用它。

  • 如果您要发送 keepalive 探测,服务器别无选择,只能做出适当的响应。服务器甚至不知道它们是保活的。他们不是。它们只是重复的 ACK。支持keepalive就是支持发送keepalive。


查看完整回答
反对 回复 2021-11-15
  • 2 回答
  • 0 关注
  • 1057 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信