duanletao9487 2016-05-23 08:37
浏览 139

通过SetDeadline()为TCP侦听器设置超时

I'm trying to implement non-blocking Accept() and the best I've come so far is the following code snippet (it's a working Go v1.6.2 program):

package main

import (
    "net"
    "log"
    "time"
)

func createClient() {
    tcpConn, err := net.DialTCP("tcp4", nil, &net.TCPAddr{
        IP:     net.IPv4(127, 0, 0, 1),
        Port:   12819,
    })
    if err != nil {
        log.Fatalln("Error connecting to the server!")
    }
    log.Println("Managed to dial!")
    tcpConn.Close()
}

func main() {
    go createClient()
    l, err := net.ListenTCP("tcp4", &net.TCPAddr{
        IP:     net.IPv4(127, 0, 0, 1),
        Port:   12819,
    })
    if err != nil {
        log.Fatalln("Can't listen on provided IP/port!")
    }
    defer l.Close()
    if err = l.SetDeadline(time.Now().Add(time.Nanosecond)); err != nil {
        log.Fatalln("Can't set appropriate deadline!")
    }
    tcpConn, err := l.AcceptTCP()
    if err != nil {
        if opError, ok := err.(*net.OpError); ok && opError.Timeout() {
            log.Fatalln("Timeout error!")
        }
        log.Fatalln("Error while accepting connection!")
    }
    log.Println("Accepted new connection!")
    tcpConn.Close()
}

The problem is that I always get Timeout error!. As far as I understand that's because by the time listener's AcceptTCP() gets called the deadline previously set will have already expired. Try changing it to time.Microsecond and you'd probably get the same result (unless you have CPU slower than mine). Things start to change only when the deadline gets at least time.Second. That's when I start to get Accepted new connection!/Managed to dial!.

So I think I nailed the problem. Any thoughts?

  • 写回答

1条回答 默认 最新

  • douweng5420 2016-05-23 09:18
    关注

    Accept is supposed to be blocking. You do not want to set deadline on listen / Accept, as you want it to permanently listen to new connections.

    You need to put the accept inside a loop and basically start a new go routine to process the connexion and return to waiting to new client connexion (Accept).

    Here is a typical server in Go:

    package main
    
    import (
        "fmt"
        "log"
        "net"
        "os"
    )
    
    func main() {
        l, err := net.Listen("tcp", "localhost:12819")
        if err != nil {
            log.Fatalln("Can't listen on provided IP/port!")
        }
        defer l.Close()
    
        for {
            // Listen for an incoming connection.
            conn, err := l.Accept()
            if err != nil {
                fmt.Println("Error accepting: ", err.Error())
                os.Exit(1)
            }
    
            // Handle connections in a new goroutine.
            go handleRequest(conn)
        }
    }
    
    func handleRequest(conn net.Conn) {
        buf := make([]byte, 1024)
        if _, err := conn.Read(buf); err != nil {
            fmt.Println("Error reading:", err.Error())
        }
        conn.Write([]byte("Message received."))
        conn.Close()
    }
    

    You can connect with it with the following command from your shell:

    telnet localhost 12819
    

    Type a command and your request will be handled and processed.

    As you see, the accept command is intended to be blocking on purpose. SetDeadline on server is generally used further done in the processing phase to timeout on read on data coming from client.

    评论

报告相同问题?

悬赏问题

  • ¥15 c程序不知道为什么得不到结果
  • ¥40 复杂的限制性的商函数处理
  • ¥15 程序不包含适用于入口点的静态Main方法
  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置