V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
ppolanwind
V2EX  ›  Go 编程语言

在 golang 中,怎么判断一个 socket 连接是否关闭?

  •  
  •   ppolanwind · 2022-07-27 02:22:01 +08:00 · 4953 次点击
    这是一个创建于 876 天前的主题,其中的信息可能已经有所发展或是发生改变。

    golang 小白求教

    26 条回复    2022-08-01 19:59:05 +08:00
    neoblackcap
        1
    neoblackcap  
       2022-07-27 03:23:08 +08:00
    如果你是问标准库里面的 socket 连接,那么是没有直接的判断方式的。唯有你自己写一个。
    方法便是设置 socket 连接的读超时,如果连接读取超时则认为是 socket 已经关闭了
    1423
        2
    1423  
       2022-07-27 03:26:20 +08:00 via iPhone   ❤️ 1
    err eof 就是关闭啊
    Goooooos
        3
    Goooooos  
       2022-07-27 07:50:20 +08:00
    系统的 keepalive 或者自己心跳监控
    bthulu
        4
    bthulu  
       2022-07-27 08:09:21 +08:00   ❤️ 3
    服务器响应心跳, 客户端发送心跳, 除此以外的一切判断方法都会出现线路断开了而报正常.
    fzdwx
        5
    fzdwx  
       2022-07-27 08:52:41 +08:00 via Android
    go 没有提供这样的 api ,一般是往里面写,来判断。
    aladdinding
        6
    aladdinding  
       2022-07-27 08:56:09 +08:00
    对一个已经关闭的连接读写的话通常会 rest by peer 和 broken pipe
    djoiwhud
        7
    djoiwhud  
       2022-07-27 09:19:03 +08:00 via Android   ❤️ 1
    read---->EOF ,已关闭
    write---->broken pipe ,已关闭
    wangyu17455
        8
    wangyu17455  
       2022-07-27 09:39:31 +08:00 via Android
    读超时设置 0 ,然后直接读,error 就是关了
    lysS
        9
    lysS  
       2022-07-27 09:55:01 +08:00
    如果是系统接口的 socket 本身,它断了,读和写都会报错 closed

    如果是物理意义上的通信链路断,就需要加 keepalive 、心跳包
    ppolanwind
        10
    ppolanwind  
    OP
       2022-07-27 10:38:06 +08:00 via iPhone
    @wangyu17455 读超时设置 0 是指不设置超时时间吗?
    ppolanwind
        11
    ppolanwind  
    OP
       2022-07-27 10:42:40 +08:00 via iPhone
    @bthulu 监控心跳的 socket 和接发数据的 socket 是同一个吗
    wangyu17455
        12
    wangyu17455  
       2022-07-27 11:55:26 +08:00
    @ppolanwind SetReadDeadline(time.Unix(0,0))
    haoliang
        13
    haoliang  
       2022-07-27 12:21:20 +08:00
    @lysS > 如果是物理意义上的通信链路断,就需要加 keepalive 、心跳包
    链路层(data link layer)断了,连接还能通过 keepalive 、心跳包恢复,第一眼看到时我觉得不可思议,想了下还是觉得不可思议
    ppolanwind
        14
    ppolanwind  
    OP
       2022-07-27 12:31:49 +08:00
    @haoliang 可以详细解释一下嘛
    ppolanwind
        15
    ppolanwind  
    OP
       2022-07-27 12:35:01 +08:00
    @wangyu17455 这样设置的意思是立即超时?那么接下来的读操作不会直接返回超时 err 嘛?
    lysS
        16
    lysS  
       2022-07-27 13:36:52 +08:00
    @haoliang 不是恢复,是判断链路是否还是通的
    stephenxiaxy
        17
    stephenxiaxy  
       2022-07-27 15:27:38 +08:00
    借楼问个问题,epoll 里面也是用的 keepalive 来触发的吗
    xuyang2
        18
    xuyang2  
       2022-07-27 15:54:19 +08:00
    bthulu
        19
    bthulu  
       2022-07-27 16:00:40 +08:00
    @ppolanwind 你要判断这个 socket 是否关闭, 那就只能是这个 socket 的心跳来判断.
    wangyu17455
        20
    wangyu17455  
       2022-07-27 16:02:29 +08:00
    @ppolanwind 这么做的意思是非阻塞读,如果 socket 缓冲区里有东西那就能读到东西,如果没有就直接返回,如果 socket 已经关闭那你调用 read 会得到 error ,调用 SetReadDeadline 是为了防止连接没有关闭然后阻塞在读取上
    pastor
        21
    pastor  
       2022-07-27 16:10:12 +08:00   ❤️ 4
    @wangyu17455 这样做是 Read 能得到 err 了,但是 socket 如果本身还是活跃的,这就是误杀了

    还是我来做课代表吧!

    @ppolanwind 正确的做法:
    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 就没必要了
    bz5314520
        22
    bz5314520  
       2022-07-27 17:38:19 +08:00   ❤️ 1
    @pastor 还得是课代表
    EminemW
        23
    EminemW  
       2022-07-28 00:29:52 +08:00
    读的时候判断 io.EOF
    写的时候判断 broken pipe
    gam2046
        24
    gam2046  
       2022-07-28 15:44:08 +08:00
    @pastor #21 有个问题想咨询课代表了,那么如何优雅的主动关闭一个 socket 呢?
    pastor
        25
    pastor  
       2022-07-28 16:56:47 +08:00
    @gam2046 不同的服务类型和框架对优雅的定义、代码的封装都不太一样,分类展开了说有点多。。给个详细点的业务类型?
    lesismal
        26
    lesismal  
       2022-08-01 19:59:05 +08:00
    这个课代表,能处
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5778 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 01:36 · PVG 09:36 · LAX 17:36 · JFK 20:36
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.