Go TCP读取是非阻塞的。

huangapple go评论86阅读模式
英文:

Go TCP read is non blocking

问题

我正在尝试在Go语言中创建一个服务器和客户端,我已经成功地实现了服务器和客户端之间的通信。但是我遇到的问题是,Golang中的TCP读取是非阻塞的。我想知道是否可能使Golang中的读取操作像C语言中的读取操作一样是阻塞的。谢谢。

编辑:

这是服务器的源代码:

func Init_tcp() *net.TCPListener {
    laddr, err := net.ResolveTCPAddr("tcp", ":4243")
    if err != nil {
        log.Fatal(err)
    }
    tcp, err := net.ListenTCP("tcp", laddr)
    if err != nil {
        log.Fatal(err)
    }
    return tcp
}

func main() {
    tcp := Init_tcp()
    conn, _ := tcp.Accept()
    data := make([]byte, 512)
    conn.SetNoDelay(false)
    for {
        conn.Read(data)
        fmt.Println(data)
    }
}

这是客户端的源代码:

func Init_tcp() *net.TCPConn {
    laddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:4243")
    if err != nil {
        log.Fatal(err)
    }
    tcp, err := net.DialTCP("tcp", nil, laddr)
    if err != nil {
        log.Fatal(err)
    }
    return tcp
}

func main() {
    tcp := Init_tcp()
    tcp.Write([]byte("hello world"))
}
英文:

I am trying to make a server and client in Go, I have managed to communicate with the server and client. But the problem I have is that the TCP read in golang is non-blocking.
What I would like to know if is it possible for the read in golang to be blocking like read in C.
Thank You

EDIT:

Here is the source code of the server:

func Init_tcp() *net.TCPListener {
    laddr, err := net.ResolveTCPAddr("tcp", ":4243")
    if err != nil {
            log.Fatal(err)
    }
    tcp, err := net.ListenTCP("tcp", laddr)
    if err != nil {
            log.Fatal(err)
    }
    return tcp
}

func main() {
    tcp := Init_tcp()
    conn, _ := tcp.Accept()
    data := make([]byte, 512)
    conn.SetNoDelay(false)
    for {
            conn.Read(data)
            fmt.Println(data)
    }
}

and my client:

func Init_tcp() *net.TCPConn {
    laddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:4243")
    if err != nil {
            log.Fatal(err)
    }
    tcp, err := net.DialTCP("tcp", nil, laddr)
    if err != nil {
            log.Fatal(err)
    }
    return tcp
}

func main() {
   tcp := Init_tcp()
   tcp.Write([]byte("hello world"))
}

答案1

得分: 36

读者可以返回部分数据。根据文档的说明,"如果有一些数据可用但不足len(p)字节,Read通常会返回可用的数据,而不是等待更多数据"。

这是任何语言中的一个问题,即使在C语言中,如果这样的情况对你起作用,TCP只提供了可以随时写入的字节流。单个写操作可能会被分成多个数据包进行传输,并且没有内置的信号告诉接收方单个写入/消息/请求的结束位置。应用程序必须找到自己的方法来标识边界。这可以是分隔符(\n)或隐式或显式的字节计数(HTTP的Content-Length是一个显式的计数)。

要读取特定数量的输入字节,可以使用io.ReadAtLeastio.ReadFull。要读取直到满足某个任意条件,只需在Read调用上循环,只要没有错误即可。(然后,您可能希望在输入过大时出错,以防止糟糕的客户端占用服务器资源。)如果您正在实现基于文本的协议,应考虑使用net/textproto,它在连接前面放置了一个bufio.Reader,以便您可以读取行。要限制等待读取完成的时间(以防止行为不端的客户端挂起并永远使用内存等资源),请查看带有Deadline名称的net函数(与Error类型上的Timeout函数相关)。context包有助于管理超时、截止时间和取消操作,如果您正在编写一个每个请求都要执行多个网络操作的复杂服务器,它尤其有用。

示例代码可能存在一个可能无关但重要的问题:它丢弃了ReadWrite的错误。这可能掩盖了简单问题,并使其非常难以调试。如果在考虑到部分读取后仍然存在问题,请在寻求更多帮助之前检查所有错误。可以使用errcheck来确保此类错误不会进入生产环境。

英文:

Readers can return partial data. From the docs, "If some data is available but not len(p) bytes, Read conventionally returns what is available instead of waiting for more."

This is an issue in any language, even if something like this happened to work for you in C: TCP just provides a stream of bytes that can be written to any time. Single writes might, by design, be broken up into multiple packets for transmission, and there's no built-in signal to the receiver saying where a single write/message/request ends. The application has to figure out its own way to signal boundaries. That can mean delimiters (\n) or implicit or explicit byte counts (HTTP's Content-Length is an explicit one).

To read a specific number of input bytes, you want io.ReadAtLeast or io.ReadFull. To read until some arbitrary condition is met you should just loop on the Read call as long as there is no error. (Then you may want to error out on on too-large inputs to prevent a bad client from eating server resources.) If you're implementing a text-based protocol you should consider net/textproto, which puts a bufio.Reader in front of the connection so you can read lines. To limit how long you'll wait to finish reading (so that a misbehaving client can't leave a goroutine hanging and using memory, etc. forever), look at the net functions with Deadline in the name (which are related to the Timeout functions on the Error types). The context package helps manage timeouts, deadlines, and cancellation, and is especially useful if, for example, you're writing a complex server that's going to do many network operations every request.

The sample code has a possibly unrelated but important problem: it throws away errors from the Read and Write. That could mask simple problems and make them very hard to debug. If you have problems after accounting for partial reads, check all errors before asking for more help. Look at errcheck to make sure mistakes like this don't get into production.

huangapple
  • 本文由 发表于 2014年11月19日 00:52:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/26999615.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定