golang gc竟然可以自动关闭tcp连接

2020-07-15  本文已影响0人  guonaihong

事情由来

在golang最近经常写http或者grpc服务,带着这种习惯写了tcp服务,最后看了下代码,tcp连接没有调用fd.Close()方法,竟然没有报错。是测试童鞋没有测试出来,还是另外有玄机?

来个demo模拟

服务端代码,保存为server.go

package main

import (
        "fmt"
        "log"
        "net"
)

func main() {

        addr := "0.0.0.0:8787"
        tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
        if err != nil { 
                log.Fatalf("net.ResovleTCPAddr fail:%s", addr) 
        }

        listener, err := net.ListenTCP("tcp", tcpAddr)
        if err != nil {
                log.Fatalf("listen %s fail: %s", addr, err)
        }
        log.Println("listening", addr)

        for {
                conn, err := listener.Accept()
                if err != nil {
                        log.Println("listener.Accept error:", err)
                        continue
                }
                fmt.Printf("%p\n", conn)
        }
}

客户端代码,保存为client.go

package main

import (
    "fmt"
    "net"
    "os"
)

func main() {

    for i := 0; i < 1000; i++ {
        conn, err := net.Dial("tcp", "127.0.0.1:8787")
        if err != nil {
            fmt.Println("dial failed:", err)
            os.Exit(1)
        }
        conn.Close()
    }
}

开始模拟

go run server.go
go run client.go
lsof -i:8787 #观察当前tcp状态,肯定是一堆close wait
# 等待1-2分钟
lsof -i:8787 #观察当前tcp状态,应该没有close wait

原因

通过参考https://studygolang.com/articles/7680 文章得知
,net/fd_unix.go文件里面setAddr调用了runtime.SetFinalizer方法,该方法,就是在对象没有引用时,调用netFD传的回调函数(*netFD).Close,现在明朗了。就是gc可以关闭tcp连接的

func (fd *netFD) setAddr(laddr, raddr Addr) { 
        fd.laddr = laddr
        fd.raddr = raddr
        runtime.SetFinalizer(fd, (*netFD).Close)
}

上一篇 下一篇

猜你喜欢

热点阅读