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

时间:2016-05-23 08:37:35

标签: go

我正在尝试实现非阻塞Accept(),我到目前为止最好的是以下代码片段(它是一个正在运行的Go v1.6.2程序):

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()
}

问题是我总是得到Timeout error!。据我所知,这是因为当听众的AcceptTCP()被调用时,之前设定的截止日期已经过期。尝试将其更改为time.Microsecond,您可能会得到相同的结果(除非您的CPU比我的慢)。只有在截止日期至少为time.Second时,事情才会开始改变。那是我开始获得Accepted new connection! / Managed to dial!

的时候

所以我认为我已经解决了这个问题。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

接受应该是阻止的。您不希望在listen / Accept上设置截止日期,因为您希望它永久地侦听新连接。

你需要把accept放在一个循环中,基本上启动一个新的go例程来处理连接并返回等待新的客户端连接(Accept)。

以下是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()
}

您可以使用shell中的以下命令连接它:

telnet localhost 12819

输入命令,您的请求将被处理和处理。

如您所见,accept命令旨在故意阻止。服务器上的SetDeadline通常在处理阶段进一步完成,以便在读取来自客户端的数据时超时。