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

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.

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

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

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

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


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/

Tags:

Go