检测TCP连接断开

时间:2019-12-16 16:58:14

标签: go tcpclient

问题:客户端需要创建tcp连接,如果由于某种原因连接断开,则需要重新连接,也可以随时要求断开连接。

服务器不在我手中,连接上没有数据发送,只需要建立连接即可。

我使用TCP的实现保持有效,我遵循了https://thenotexpert.com/golang-tcp-keepalive/

func (s *State) spawnCtrlConnection() (quit chan struct{}) {
    quit = make(chan struct{}, 1)

    go func(addr string) {

        tcpAddr, err := net.ResolveTCPAddr("tcp", s.addr())
        if err != nil {
            s.HandleError(err)
            return
        }

        conn, err := net.DialTCP("tcp", nil, tcpAddr)
        if err != nil {
            s.HandleError(err)
            return
        }

        defer func() {
            conn.Close()
        }()

        conn.SetKeepAlive(true)
        conn.SetKeepAlivePeriod(time.Second * time.Duration(s.WaitInterval))

        rawConn, err := conn.SyscallConn()
        if err != nil {
            s.HandleError(err)
            return
        }

        rawConn.Control(
            func(fdPtr uintptr) {
                fd := int(fdPtr)

                // Ping amount
                err = syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPCNT, s.PingAmount)
                if err != nil {
                    s.HandleError(err)
                    return
                }
                // Retry interval
                err = syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, s.RetryInterval)
                if err != nil {
                    s.HandleError(err)
                    return
                }
            })

        for {
            select {
            case <-quit:
                return
            default:

                data := make([]byte, 1)
                _, err = conn.Read(data)
                // it blocks here forever and (<- quit will never receive anything)

                // setting explicit timeout doesn't help either, as it will timeout for obvious reason
                //  conn.SetDeadline(time.Now().Add(time.Second * time.Duration(s.WaitInterval)))

                //  if err != nil {
                //      if err, ok := err.(net.Error); ok && err.Timeout() {
                //          fmt.Println("timeout", err.Error())
                //      } else {
                //          fmt.Println("I am here", err.Error())
                //      }
                //  }

                // WHAT SHOULD I CODE


            }
        }
    }()
    return
}

我不明白,我应该编写什么代码来检测断开连接。

可能是我误解了tcp keep-alive的概念。

请帮助。

1 个答案:

答案 0 :(得分:1)

这是建议的代码。

只要没有关闭退出,for !done循环将在连接关闭后重新连接。

for conn != nil循环将重复执行选择。

SetDeadLine放在Read之前。当死线插入时,我们确实会收到Timeout()错误。请注意,我相信当keep alive失败时,我们也可能会超时。

func (s *State) spawnCtrlConnection() (quit chan struct{}) {
    quit = make(chan struct{})

    go func() {
        var done bool
        for !done {

            // ... open connection ...

            for conn != nil {
                var buf [1]byte
                select {
                case <-quit:
                    conn.Close()
                    conn = nil
                    done = true
                    continue
                default:
                    conn.SetDeadline(time.Now().Add(time.Duration(s.WaitInterval)*time.Second))
                    _, err = conn.Read(buf[:])
                    if err != nil {
                        if err == io.EOF {
                            conn.Close()
                            conn = nil
                            continue
                        }
                        if err, ok := err.(net.Error); ok && err.Timeout() {
                            continue
                        } else {
                            fmt.Println("I am here", err.Error())
                        }
                    }
                }
            }
        }
    }()

    return quit
}