Golang Go语言中,怎么判断一个 socket 连接是否关闭?

发布于 1周前 作者 gougou168 来自 Go语言

golang 小白求教


Golang Go语言中,怎么判断一个 socket 连接是否关闭?
27 回复

如果你是问标准库里面的 socket 连接,那么是没有直接的判断方式的。唯有你自己写一个。
方法便是设置 socket 连接的读超时,如果连接读取超时则认为是 socket 已经关闭了

更多关于Golang Go语言中,怎么判断一个 socket 连接是否关闭?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


err eof 就是关闭啊

系统的 keepalive 或者自己心跳监控

服务器响应心跳, 客户端发送心跳, 除此以外的一切判断方法都会出现线路断开了而报正常.

go 没有提供这样的 api ,一般是往里面写,来判断。

对一个已经关闭的连接读写的话通常会 rest by peer 和 broken pipe

read---->EOF ,已关闭
write---->broken pipe ,已关闭

读超时设置 0 ,然后直接读,error 就是关了

如果是系统接口的 socket 本身,它断了,读和写都会报错 closed

如果是物理意义上的通信链路断,就需要加 keepalive 、心跳包

读超时设置 0 是指不设置超时时间吗?

监控心跳的 socket 和接发数据的 socket 是同一个吗

SetReadDeadline(time.Unix(0,0))

> 如果是物理意义上的通信链路断,就需要加 keepalive 、心跳包
链路层(data link layer)断了,连接还能通过 keepalive 、心跳包恢复,第一眼看到时我觉得不可思议,想了下还是觉得不可思议

可以详细解释一下嘛

这样设置的意思是立即超时?那么接下来的读操作不会直接返回超时 err 嘛?

不是恢复,是判断链路是否还是通的

借楼问个问题,epoll 里面也是用的 keepalive 来触发的吗

你要判断这个 socket 是否关闭, 那就只能是这个 socket 的心跳来判断.

这么做的意思是非阻塞读,如果 socket 缓冲区里有东西那就能读到东西,如果没有就直接返回,如果 socket 已经关闭那你调用 read 会得到 error ,调用 SetReadDeadline 是为了防止连接没有关闭然后阻塞在读取上

这样做是 Read 能得到 err 了,但是 socket 如果本身还是活跃的,这就是误杀了

还是我来做课代表吧!

正确的做法:
1. 不要通过调用判断是否断开的方法去判断是否断开(比如 IsClosed )
2. 正常使用 Conn ,根据使用的返回值判断,比如 Read/Write 时返回了 err ,就是断开了

以上两条只是说怎么处理,实际实现 Conn 封装时通常要做的:
1. 单独一个协程处理读
2. 如果需要广播功能,单独一个协程处理写,否则可以不用单独协程、直接写就行

前面已经有人提到 keepalive ,但不够全面,仍需注意:
1. TCP 的 keepalive (传输层,4 层)只是检测连接健康状态,但不能用于判断连接的活跃状态。比如链路通顺、4 层 keepalive 是健康的,但 7 层应用层没有数据交互,这种属于僵尸连接了,对于正常的服务器,是应该踢掉这种长时间不活跃的僵尸连接的。所以 TCP 的 keepalive 选项不能解决僵尸连接的问题
2. 7 层应该自己进行 keepalive 协议包的收发比如 websocket 的 ping/pong ,来相互判断。业务协议活跃时可以节约掉 ping/pong 、一段时间没有业务协议交互再 ping/pong ,但 keepalive 间隔本来也比较大所以即使不节约这点也没关系。
3. 既然 7 层应该有自己的 keepalive ,其实 4 层的 keepalive 就没必要了

还得是课代表

读的时候判断 io.EOF
写的时候判断 broken pipe

#21 有个问题想咨询课代表了,那么如何优雅的主动关闭一个 socket 呢?

不同的服务类型和框架对优雅的定义、代码的封装都不太一样,分类展开了说有点多。。给个详细点的业务类型?

这个课代表,能处

在 Golang 中判断一个 socket 连接是否关闭,通常可以通过以下几种方式来进行:

  1. 读写操作中的错误处理: 当你尝试从 socket 读取数据或向 socket 写入数据时,如果连接已经关闭,这些操作会返回错误。例如,Read 方法会返回 (0, io.EOF) 表示连接正常关闭,或者返回一个其他错误表示异常关闭。类似地,Write 方法也会返回错误,如果连接已关闭。

  2. 使用 net.ConnClose 方法: 如果你控制了连接的关闭,可以通过调用 conn.Close() 来主动关闭连接,并在需要时设置一个标志位来表示连接状态。

  3. 设置读/写超时: 通过 SetReadDeadlineSetWriteDeadline 方法可以设置读写操作的超时时间。如果操作在超时时间内没有完成,将返回一个超时错误,你可以根据这个错误来判断连接是否可能存在问题(虽然这并不直接说明连接已关闭,但可能表明连接不再可靠)。

  4. 心跳机制: 在长时间保持的连接中,实现一个心跳机制(定期发送或接收特定消息)可以帮助检测连接是否仍然活跃。如果心跳消息未能按时到达,可以认为连接可能已经关闭或出现问题。

综合以上方法,通常是通过捕获读写操作的错误来判断 socket 连接是否关闭,同时结合心跳机制等策略来确保连接的可靠性。

回到顶部