Difference between listen, read and write functions in the net package

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

Difference between listen, read and write functions in the net package

问题

我是你的中文翻译助手,以下是你要翻译的内容:

我刚开始学习Go语言,作为我的第一个测试项目,我想编写一个简单的客户端/服务器程序,使用UDP协议。我已经让它工作了,但有很多方法可以实现,我想知道哪种方法是最好的。

net.Listen() vs net.ListenUDP() vs net.ListenPacket()

net.Read() vs net.ReadFrom() vs net.ReadFromUDP()

net.Write() vs net.WriteTo() vs net.WriteToUDP()

英文:

I'm new to Go, and as one of my first test project I would like to write a simple client/server program that uses UDP. I got it to work, but there are a lot of ways to do it and I would like to know which is the best way.

net.Listen() vs net.ListenUDP() vs net.ListenPacket()

net.Read() vs net.ReadFrom() vs net.ReadFromUDP()

net.Write() vs net.WriteTo() vs net.WriteToUDP()

答案1

得分: 27

让我们来分析一下你的问题。

1. net.Listen() vs. net.ListenUDP() vs. net.ListenPacket()

net.Listen()函数用于在本地网络地址上进行监听。网络net必须是面向流的网络,如"tcp"、"tcp4"、"tcp6"、"unix"或"unixpacket"。laddr参数的语法请参考Dial函数。

使用示例 #1:

tcpSock, err := net.Listen("tcp", "0.0.0.0:8080")

使用示例 #2:

unixSock, err := net.Listen("unix", "/var/app/server.sock")

我们可以在源代码中看到,net.Listen()函数是一个switch语句,根据不同的情况调用net.ListenTCP、net.ListenUnix或默认的错误处理函数:

func Listen(net, laddr string) (Listener, error) {
    la, err := resolveAddr("listen", net, laddr, noDeadline)
    if err != nil {
        return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
    }
    var l Listener
    switch la := la.toAddr().(type) {
    case *TCPAddr:
        l, err = ListenTCP(net, la)
    case *UnixAddr:
        l, err = ListenUnix(net, la)
    default:
        return nil, &OpError{
            Op:   "listen",
            Net:  net,
            Addr: la,
            Err:  &AddrError{Err: "unexpected address type", Addr: laddr},
        }
    }
    if err != nil {
        return nil, err // l is non-nil interface containing nil pointer
    }
    return l, nil
}

更多信息请参考net.Listen()文档

因此,我们可以将net.ListenUDP()从初始比较中排除,并查看net.ListenPacket()。

net.ListenPacket()函数用于在本地网络地址上进行监听。网络net必须是面向数据包的网络,如"udp"、"udp4"、"udp6"、"ip"、"ip4"、"ip6"或"unixgram"。laddr参数的语法请参考Dial函数。

使用示例 #1:

pListener, err := net.ListenPacket("ip4", "0.0.0.0:9090")

如果我们深入了解,可以发现它的工作方式与net.Listen()非常相似:

func ListenPacket(net, laddr string) (PacketConn, error) {
    la, err := resolveAddr("listen", net, laddr, noDeadline)
    if err != nil {
        return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
    }
    var l PacketConn
    switch la := la.toAddr().(type) {
    case *UDPAddr:
        l, err = ListenUDP(net, la)
    case *IPAddr:
        l, err = ListenIP(net, la)
    case *UnixAddr:
        l, err = ListenUnixgram(net, la)
    default:
        return nil, &OpError{
            Op:   "listen",
            Net:  net,
            Addr: la,
            Err:  &AddrError{Err: "unexpected address type", Addr: laddr},
        }
    }
    if err != nil {
        return nil, err // l is non-nil interface containing nil pointer
    }
    return l, nil
}

2. net.Read() vs. net.ReadFrom() vs net.ReadFromUDP()

这些函数用于从各种net连接中读取数据。

net.Read()函数是从实现了net.Conn接口的类型中读取数据。具体实现如下:

  • IPConn.Read
  • TCPConn.Read
  • UDPConn.Read
  • UnixConn.Read

net.Conn接口定义如下:

type Conn interface {
    // Read reads data from the connection.
    // Read can be made to time out and return a Error with Timeout() == true
    // after a fixed time limit; see SetDeadline and SetReadDeadline.
    Read(b []byte) (n int, err error)

    // Write writes data to the connection.
    // Write can be made to time out and return a Error with Timeout() == true
    // after a fixed time limit; see SetDeadline and SetWriteDeadline.
    Write(b []byte) (n int, err error)

    // Close closes the connection.
    // Any blocked Read or Write operations will be unblocked and return errors.
    Close() error

    // LocalAddr returns the local network address.
    LocalAddr() Addr

    // RemoteAddr returns the remote network address.
    RemoteAddr() Addr

    // SetDeadline sets the read and write deadlines associated
    // with the connection. It is equivalent to calling both
    // SetReadDeadline and SetWriteDeadline.
    //
    // A deadline is an absolute time after which I/O operations
    // fail with a timeout (see type Error) instead of
    // blocking. The deadline applies to all future I/O, not just
    // the immediately following call to Read or Write.
    //
    // An idle timeout can be implemented by repeatedly extending
    // the deadline after successful Read or Write calls.
    //
    // A zero value for t means I/O operations will not time out.
    SetDeadline(t time.Time) error

    // SetReadDeadline sets the deadline for future Read calls.
    // A zero value for t means Read will not time out.
    SetReadDeadline(t time.Time) error

    // SetWriteDeadline sets the deadline for future Write calls.
    // Even if write times out, it may return n > 0, indicating that
    // some of the data was successfully written.
    // A zero value for t means Write will not time out.
    SetWriteDeadline(t time.Time) error
}

因此,实际上并没有net.Read()函数,而是在实现net.Conn接口的类型上操作的Read()函数。

net.ReadFrom()函数也是类似的,所有的实现都来自于实现了net.PacketConn接口的类型。

  • IPConn.ReadFrom
  • UDPConn.ReadFrom
  • UnixConn.ReadFrom

PacketConn接口定义如下:

type PacketConn interface {
    // ReadFrom reads a packet from the connection,
    // copying the payload into b.  It returns the number of
    // bytes copied into b and the return address that
    // was on the packet.
    // ReadFrom can be made to time out and return
    // an error with Timeout() == true after a fixed time limit;
    // see SetDeadline and SetReadDeadline.
    ReadFrom(b []byte) (n int, addr Addr, err error)

    // WriteTo writes a packet with payload b to addr.
    // WriteTo can be made to time out and return
    // an error with Timeout() == true after a fixed time limit;
    // see SetDeadline and SetWriteDeadline.
    // On packet-oriented connections, write timeouts are rare.
    WriteTo(b []byte, addr Addr) (n int, err error)

    // Close closes the connection.
    // Any blocked ReadFrom or WriteTo operations will be unblocked
    // and return errors.
    Close() error

    // LocalAddr returns the local network address.
    LocalAddr() Addr

    // SetDeadline sets the read and write deadlines associated
    // with the connection.
    SetDeadline(t time.Time) error

    // SetReadDeadline sets the deadline for future Read calls.
    // If the deadline is reached, Read will fail with a timeout
    // (see type Error) instead of blocking.
    // A zero value for t means Read will not time out.
    SetReadDeadline(t time.Time) error

    // SetWriteDeadline sets the deadline for future Write calls.
    // If the deadline is reached, Write will fail with a timeout
    // (see type Error) instead of blocking.
    // A zero value for t means Write will not time out.
    // Even if write times out, it may return n > 0, indicating that
    // some of the data was successfully written.
    SetWriteDeadline(t time.Time) error
}

注意:TCPConn.ReadFrom是通过实现io.ReaderFrom的ReadFrom方法来实现的。

3. net.Write()

net.Write()函数也是类似的,通过实现接口来实现。你可以根据上面的解释自行查找这个特定方法以及它的工作方式。

你可以先阅读一下Effective Go关于接口的部分

更多的net包信息可以在源代码GoDoc中找到。

英文:

Let's examine your question.

1. net.Listen() vs. net.ListenUDP() vs. net.ListenPacket()

net.Listen()

> Listen announces on the local network address laddr. The network net must be a stream-oriented network: "tcp", "tcp4", "tcp6", "unix" or "unixpacket". See Dial for the syntax of laddr.

Usage Example #1:

tcpSock, err := net.Listen("tcp", "0.0.0.0:8080")

Usage Example #2

unixSock, err := net.Listen("unix", "/var/app/server.sock")

We can see in the source that net.Listen() works as a switch statement that calls either net.ListenTCP or net.ListenUnix or the default error:

func Listen(net, laddr string) (Listener, error) {
	la, err := resolveAddr("listen", net, laddr, noDeadline)
	if err != nil {
		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
	}
	var l Listener
	switch la := la.toAddr().(type) {
	case *TCPAddr:
		l, err = ListenTCP(net, la)
	case *UnixAddr:
		l, err = ListenUnix(net, la)
	default:
		return nil, &OpError{
			Op:   "listen",
			Net:  net,
			Addr: la,
			Err:  &AddrError{Err: "unexpected address type", Addr: laddr},
		}
	}
	if err != nil {
		return nil, err // l is non-nil interface containing nil pointer
	}
	return l, nil
}

Additional info at net.Listen() Docs

So then, we can eliminate net.ListenUDP from the initial comparison; and look at net.ListenPacket().

net.ListenPacket()

> ListenPacket announces on the local network address laddr. The network net must be a packet-oriented network: "udp", "udp4", "udp6", "ip", "ip4", "ip6" or "unixgram". See Dial for the syntax of laddr.

Usage Example #1:

pListener, err := net.ListenPacket("ip4", "0.0.0.0:9090")

And, if we look under the hood, we can see that it operates in much the same way as net.Listen():

func ListenPacket(net, laddr string) (PacketConn, error) {
	la, err := resolveAddr("listen", net, laddr, noDeadline)
	if err != nil {
		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
	}
	var l PacketConn
	switch la := la.toAddr().(type) {
	case *UDPAddr:
		l, err = ListenUDP(net, la)
	case *IPAddr:
		l, err = ListenIP(net, la)
	case *UnixAddr:
		l, err = ListenUnixgram(net, la)
	default:
		return nil, &OpError{
			Op:   "listen",
			Net:  net,
			Addr: la,
			Err:  &AddrError{Err: "unexpected address type", Addr: laddr},
		}
	}
	if err != nil {
		return nil, err // l is non-nil interface containing nil pointer
	}
	return l, nil
}

2. net.Read() vs. net.ReadFrom() vs net.ReadFromUDP()

As you might expect, these functions are used to read from the various net connections.

net.Read()

If you look at the net package - you can see that all of the Read() functions come from types that implement the Conn interface.

The Conn interface is defined as:

> ... a generic stream-oriented network connection.

In order to implement net.Conn you need to have the following methods:

type Conn interface {
    // Read reads data from the connection.
    // Read can be made to time out and return a Error with Timeout() == true
    // after a fixed time limit; see SetDeadline and SetReadDeadline.
    Read(b []byte) (n int, err error)

    // Write writes data to the connection.
    // Write can be made to time out and return a Error with Timeout() == true
    // after a fixed time limit; see SetDeadline and SetWriteDeadline.
    Write(b []byte) (n int, err error)

    // Close closes the connection.
    // Any blocked Read or Write operations will be unblocked and return errors.
    Close() error

    // LocalAddr returns the local network address.
    LocalAddr() Addr

    // RemoteAddr returns the remote network address.
    RemoteAddr() Addr

    // SetDeadline sets the read and write deadlines associated
    // with the connection. It is equivalent to calling both
    // SetReadDeadline and SetWriteDeadline.
    //
    // A deadline is an absolute time after which I/O operations
    // fail with a timeout (see type Error) instead of
    // blocking. The deadline applies to all future I/O, not just
    // the immediately following call to Read or Write.
    //
    // An idle timeout can be implemented by repeatedly extending
    // the deadline after successful Read or Write calls.
    //
    // A zero value for t means I/O operations will not time out.
    SetDeadline(t time.Time) error

    // SetReadDeadline sets the deadline for future Read calls.
    // A zero value for t means Read will not time out.
    SetReadDeadline(t time.Time) error

    // SetWriteDeadline sets the deadline for future Write calls.
    // Even if write times out, it may return n > 0, indicating that
    // some of the data was successfully written.
    // A zero value for t means Write will not time out.
    SetWriteDeadline(t time.Time) error
}

Source code

So, that should make it clear that there is actually no net.Read(); but, rather, Read() functions that operate on types which implement the net.Conn interface.

net.ReadFrom()

Just as with net.Read(), all of the implementations come from implementing an interface. In this case, that interface is net.PacketConn

> PacketConn is a generic packet-oriented network connection.

type PacketConn interface {
    // ReadFrom reads a packet from the connection,
    // copying the payload into b.  It returns the number of
    // bytes copied into b and the return address that
    // was on the packet.
    // ReadFrom can be made to time out and return
    // an error with Timeout() == true after a fixed time limit;
    // see SetDeadline and SetReadDeadline.
    ReadFrom(b []byte) (n int, addr Addr, err error)

    // WriteTo writes a packet with payload b to addr.
    // WriteTo can be made to time out and return
    // an error with Timeout() == true after a fixed time limit;
    // see SetDeadline and SetWriteDeadline.
    // On packet-oriented connections, write timeouts are rare.
    WriteTo(b []byte, addr Addr) (n int, err error)

    // Close closes the connection.
    // Any blocked ReadFrom or WriteTo operations will be unblocked
    // and return errors.
    Close() error

    // LocalAddr returns the local network address.
    LocalAddr() Addr

    // SetDeadline sets the read and write deadlines associated
    // with the connection.
    SetDeadline(t time.Time) error

    // SetReadDeadline sets the deadline for future Read calls.
    // If the deadline is reached, Read will fail with a timeout
    // (see type Error) instead of blocking.
    // A zero value for t means Read will not time out.
    SetReadDeadline(t time.Time) error

    // SetWriteDeadline sets the deadline for future Write calls.
    // If the deadline is reached, Write will fail with a timeout
    // (see type Error) instead of blocking.
    // A zero value for t means Write will not time out.
    // Even if write times out, it may return n > 0, indicating that
    // some of the data was successfully written.
    SetWriteDeadline(t time.Time) error
}

Note: the TCPConn.ReadFrom comes from implementing the io.ReaderFrom ReadFrom method.

3. net.Write()

As you might have guessed, we're looking at the same pattern over and over again. This is called implementing an interface. I'll leave you to look up this particular method and how it works using the above explanation as a road map.

You would do well to take a look at the Effective Go parts about interfaces first.

More net package info available at the source and GoDoc

答案2

得分: 1

如果你只使用UDP数据包,最好的解决方案是使用UDP函数。

例如,net.ListenUDP() 可以监听UDP、UDP4和UDP6数据包。net.ListenPacket() 可以监听所有UDP数据包,还可以监听IP、IP4、IP6和Unixgram数据包。net.Listen() 可以监听TCP、TCP4、TCP6、Unix和Unixpacket数据包。

来源:http://golang.org/pkg/net/

英文:

If you only work with UDP packets, the best solution is to use the UDP functions.

net.ListenUDP() for example could listen for udp, udp4 and udp6 packages. net.ListenPacket could listen for all UDP packets, but also for ip, ip4, ip6 and unixgram packets. net.Listen() could listen for tcp, tcp4, tcp6, unix and unixpacket packets.

Source: http://golang.org/pkg/net/

huangapple
  • 本文由 发表于 2014年7月24日 20:11:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/24933352.html
匿名

发表评论

匿名网友

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

确定