【问题标题】:Detect TCP Connection Disconnection检测 TCP 连接断开
【发布时间】:2019-12-17 03:19:18
【问题描述】:

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

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

我使用 TCP keep alive 的实现,我关注了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 的概念。

请帮忙。

【问题讨论】:

  • 只需使用for ever 循环,它在开始时连接。让Read阻塞和超时,调整它们,当它返回连接丢失错误时,在循环开始时返回。您还可以添加一个标志来检测首次运行,从而确定它是否重新连接。如果服务器发送退出命令,不清楚,只需打破循环。
  • 在任何情况下,在读取返回之前您都不能退出。
  • 在超时期间读取块,我将无法在该时间间隔内断开连接
  • TCP 中不存在“断开连接”消息。您从连接中读取,直到它关闭。就是这样。
  • 使用SetKeepAliveSetKeepAlivePeriod 设置保持活动状态。读取连接,直到 read 返回错误。仅此而已。

标签: go tcpclient


【解决方案1】:

这是一个建议的代码。

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

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

SetDeadLine 放在Read 之前。当死线开始时,我们确实会收到 Timeout() 错误。请注意,我相信当保持活动失败时,我们也可能会遇到超时。

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
}

【讨论】:

    猜你喜欢
    • 2013-02-10
    • 1970-01-01
    • 2020-07-04
    • 1970-01-01
    • 2013-06-23
    • 2013-11-16
    • 2014-01-24
    • 2014-05-16
    • 2013-11-22
    相关资源
    最近更新 更多