通过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?

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.