Timeouts and Hangs
Sooner or later every netcat user meets the hang: the command was run, the bytes were sent, and now terminal and tool sit looking at each other. Nothing is broken. Something is waiting — and chapter 2 told you why: the two directions are separate streets, and netcat's default is to keep its street open until the other side closes. The fixture echoes and waits. You finished typing and wait. Each is doing exactly what it was asked.
The lab's demonstration, with a
lifeguard (timeout) so it can be
captured at all:
$ time (printf "hello\n" | timeout 3 nc 127.0.0.1 45002 >/dev/null)
# no -N, no -w: stdin ends, but nc stays on the line,
# waiting for the fixture, which is waiting for nc.
real 0m3.003s
stdin ended almost instantly; netcat was still connected when the lifeguard pulled it out at 3 seconds. That is the whole mystery, and it has exactly two cures, both measured below with netcat timed directly (a pipeline's clock measures its slowest member, so these runs feed netcat from a file or a held-open pipe instead):
nc -N (input ends; -N says goodbye at once) : exit 0 after 0.0s
nc -w 2 (input ends; -w waits 2s for a reply) : exit 0 after 2.0s
nc -w 2 (input held open but silent) : exit 0 after 2.0s
-N: say goodbye
-N answers the question "when am I
done?" with "when my input ends."
Netcat shuts down the sending side of
the socket — a proper protocol goodbye
— the peer sees end-of-input, finishes,
and closes; netcat exits. Measured:
0.0s after input. This is the flag
that makes transfers end (chapter 6),
makes receivers exit, and makes scripts
terminate. Its one contraindication: a
peer whose protocol says "the input
ending means nothing; my reply comes
when it comes." For those, leaving
-N off and waiting is correct — and
if the wait needs a bound, that's the
second cure.
-w: bound the silence
-w seconds is netcat's patience: if
the connection sits idle — no bytes
either way — longer than that, netcat
leaves. Both measurements above show
its character:
- After input ended,
-w 2granted the fixture 2.0s to say anything more, then exited cleanly (exit 0 — a timeout here is a plan, not an error). - With input held open but silent — the terminal user who connected and then just sat there — the same 2.0s of mutual silence ended it.
-w also bounds the connect itself:
chapter 5's silent-port check only
terminated politely because -w 2
said so. Rules of thumb measured by
this chapter: interactive use, your
own Ctrl-C is the timeout; scripts and
checks, -w always, with the number
chosen as "how long is a legitimate
silence in this protocol?" — 1–3
seconds covers most honest ones on a
LAN; a slow service finishing a long
answer is chapter 2's reason the
default is infinite, and why you
choose on purpose.
A relative worth naming: -q seconds
(on this OpenBSD nc) delays quitting
after input ends — the same
neighbourhood as -N, with a pause
first, for peers that need a beat
before the goodbye. It wasn't needed
in the lab; it's here so the flag
isn't a stranger in nc -h.
Diagnosing someone else's hang
When a script's netcat hangs, read it as a sentence about the peer: the peer hasn't closed, because in its protocol the conversation isn't over — or because it died mid-sentence and nothing told the socket. The fixes, in the order mortals need them:
- Sender forgot
-N→ receiver waits forever for the rest of the file. - Nobody set
-w→ any silence, from any cause, is forever. - The receiver is a plain
nc -lthat already served its one caller (chapter 4) → the sender isn't hanging, it's refused... unless it's queued in a backlog behind a call that never ends. Back to 1.
Check: connect to the fixture by hand
(nc 127.0.0.1 45002), type a line,
get the echo — then do nothing. That
stillness is the un--w default,
working as specified. Ctrl-C is a
perfectly good timeout at a terminal;
the chapter exists for everywhere
else.