在 golang 中,怎么判断一个 socket 连接是否关闭? - V2EX
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 5496 次点击
    这是一个创建于 1177 天前的主题,其中的信息可能已经有所发展或是发生改变。

    golang 小白求教

    26 条回复    2022-08-01 19:59:05 +08:00
    neoblackcap
        1
    neoblackcap  
       2022-07-27 03:23:08 +08:00
    如果你是问标准库里面的 socket 连接,那么是没有直接的判断方式的。唯有你自己写一个。
    方法便是设置 socket 连接的读超时,如果连接读取超时则认为是 socket 已经关闭了
    slowman
        2
    slowman  
       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
    服务器响应心跳, 客户端发送心跳, 除此以外的一切判断方法都会出现线路断开了而报正常.
    lllllliiii
        5
    lllllliiii  
       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     Solana     5282 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 07:17 PVG 15:17 LAX 00:17 JFK 03:17
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86