BSD nc (netcat) does not terminate on EOF

I, too, was puzzled by netcat's behavior, so I dug into the code. Here's the whole story:

nc servers (nc -l) and clients only exit after the mutual connection was closed. That is, if each of the parties sent a FIN packet to the other party.

A server always sends a FIN packet after receiving a FIN packet from the client. (Unless the server already sent a FIN packet.)

A client sends a FIN packet either:

  • after EOF on stdin, when run with argument -N
  • after EOF on stdin, when the server already sent a FIN packet

Option -d always implies EOF on stdin.

Option -N always implies sending FIN after encountering EOF on stdin.

Ways to exit the nc processes after exchanging data:

  1. Georg's answer

    server$ echo hello | nc -l -N 2000
    client$ nc -d localhost 2000
    

    After sending hello, the server encounters EOF on stdin an sends FIN because of -N.

    The client receives the message and, due to -d, sees EOF on stdin and sends FIN, because the server already sent FIN.

    The connection is closed, both the client and the server exit.

  2. Client initiates the close

    server$ echo hello | nc -l 2000
    client$ nc -dN localhost 2000
    

    The server keeps the connection open after EOF on stdin.

    The client sees EOF on stdin and sends FIN, because of -N.

    The server sends FIN after receiving the client's FIN.

    The connection is closed, both the client and the server exit.


nc establishes a bi-directional connection. I.e. it sends stdin from host B to host A as well as the desired one from A to B.

Use -d on host B to ignore stdin. -N on host A is still needed to close the TCP connection on EOF.


In summary

Host A:

tar cf -  stuff | dd | nc  -N -l 12987

Host B:

nc -d a.example.com 12987 | dd | tar tf -