2 回答
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])
}
}
}()
TA贡献1877条经验 获得超6个赞
按照设计,没有“TCP 连接状态”这样的东西。只有当你发送一些东西时才会发生什么。没有任何级别的 TCP API 可以告诉您 TCP 连接的当前状态,在任何级别上都没有硅。你必须尝试使用它。
如果您要发送 keepalive 探测,服务器别无选择,只能做出适当的响应。服务器甚至不知道它们是保活的。他们不是。它们只是重复的 ACK。支持keepalive就是支持发送keepalive。
- 2 回答
- 0 关注
- 1057 浏览
添加回答
举报