为了账号安全,请及时绑定邮箱和手机立即绑定

如果连接没有每秒收到响应,我该如何使 TCP 连接超时?

如果连接没有每秒收到响应,我该如何使 TCP 连接超时?

Go
繁花如伊 2022-12-05 16:49:37
我正在尝试创建一个 TCP 服务器,如果客户端在每秒的范围内没有响应,它将超时。我试过了:func main() {    listener, err := net.Listen("tcp", "localhost:8000")    if err != nil {        log.Fatal(err)    }    for {        conn, err := listener.Accept()        conn.SetDeadline(time.Now().Add(timeout))        if err != nil {            log.Print(err)        }        go handleConn(conn)    }}超时是一秒钟但立即断开连接,甚至不等待回复。
查看完整描述

2 回答

?
茅侃侃

TA贡献1842条经验 获得超21个赞

您可以通过在侦听器上设置套接字选项来实现您想要的。根据您的需要调整值


请注意,这是它自己的 KeepAlive,不依赖于应用程序的传入/传出数据


func enableTCPKeepAlive(listener *net.TCPListener) error {

    rawConn, err := listener.SyscallConn()

    if err != nil {

        return err

    }

    cfg := config.TLSServerConfig()

    rawConn.Control(

        func(fdPtr uintptr) {

            // got socket file descriptor. Setting parameters.

            fd := int(fdPtr)

            //Idle time before sending probe.

            err = syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, cfg.TCPKAIdleTime)

            if err != nil {

                return err

            }

            //Number of probes.

            err := syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPCNT, cfg.TCPKANumProbes)

            if err != nil {

                return err

            }

            //Wait time after an unsuccessful probe.

            err = syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, cfg.TCPKAInterval)

            if err != nil {

                return err

            }

            // go syscall doesn't have the constant 0x12 (18) for TCP_USER_TIMEOUT.

            // 0x12 value referenced from linux kernel source code header:

            // include/uapi/linux/tcp.h

            err = syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, 0x12, cfg.TCPKAUserTimeout)

            if err != nil {

                return err

            }

        })

    return nil

}

可用的选项比我上面提到的要多。在 for 循环之前在您的侦听器上调用此函数。


func main() {

    listener, err := net.Listen("tcp", "localhost:8000")

    if err != nil {

        log.Fatal(err)

    }

    err = enableTCPKeepAlive(listener)

    if err != nil {

        log.Fatal(err)

    }

    for {

        conn, err := listener.Accept()

        conn.SetDeadline(time.Now().Add(timeout))

        if err != nil {

            log.Print(err)

        }

        go handleConn(conn)

    }


}


查看完整回答
反对 回复 2022-12-05
?
12345678_0001

TA贡献1802条经验 获得超5个赞

问题几乎总是出在未在此处发布的代码中。该功能显然很有魅力:


package main


import (

    "crypto/rand"

    "log"

    "net"

    "time"

)


func main() {

    listener, err := net.Listen("tcp", "localhost:8000")

    if err != nil {

        log.Fatal(err)

    }

    go func() {

        for {

            conn, err := listener.Accept()

            if err != nil {

                log.Print(err)

                return

            }

            go func(c net.Conn) {

                defer c.Close()


                conn.SetDeadline(time.Now().Add(2 * time.Second))

                if err != nil {

                    log.Print(err)

                    return

                }

                buf := make([]byte, 1<<19) // 512 KB

                for {

                    _, err := conn.Read(buf)

                    if err != nil {

                        log.Print(err)

                        break

                    }

                }

            }(conn)

        }

    }()


payload := make([]byte, 1<<20)

_, err = rand.Read(payload) // generate a random payload

if err != nil {

    log.Print(err)

}


conn, err := net.Dial("tcp", listener.Addr().String())

if err != nil {

    log.Fatal(err)

}

log.Println("Connected to server.")


time.Sleep(5 * time.Second)


_, err = conn.Write(payload)

if err != nil {

    log.Print(err)

}


listener.Close()

}


查看完整回答
反对 回复 2022-12-05
  • 2 回答
  • 0 关注
  • 101 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信