nc — Read and write raw TCP / UDP data — port probes, listeners, file transfer across all 5 shells
Equivalents in every shell
nc -zv host 80`-z` zero-I/O port-scan mode (just check if accept() works); `-v` verbose. Three flavours exist on Linux: `nc.openbsd` (modern, default on Ubuntu), `nc.traditional` (older, slightly different flags), and `ncat` (Nmap project, scriptable Lua engine). `update-alternatives --config nc` switches the system default.
nc -zv host 80Calls the same `/usr/bin/nc` binary. Zsh has no builtin TCP equivalent, but `/dev/tcp/host/port` redirection works (`exec 3<>/dev/tcp/example.com/80; echo "GET /" >&3`) — a bash feature zsh also supports.
nc -zv host 80External `nc` binary, identical syntax. Fish lacks bash's `/dev/tcp` virtual file — `nc` (or its successor `ncat`) is the only socket primitive.
Test-NetConnection -ComputerName host -Port 80`Test-NetConnection` is the canonical replacement (pwsh 5.1+ on Windows). Returns a `[TestNetConnectionResult]` object with `TcpTestSucceeded`, `PingReplyDetails`, latency. For scriptable raw socket I/O, use `New-Object System.Net.Sockets.TcpClient` + `.GetStream()`. The `ncat.exe` from a Nmap install gives full nc parity on Windows.
powershell -NoProfile -Command "Test-NetConnection host -Port 80"No native cmd netcat. Best options: shell out to pwsh (above), use `ncat.exe` from a Nmap install (full nc compatibility), or `PortQry.exe` (Microsoft's legacy tool — TCP/UDP probe with detailed output). Windows 10+ has `Test-NetConnection` available from cmd via the pwsh shim, but no native cmd equivalent.
Worked examples
Probe whether a TCP port is open (no data exchange)
nc -zv example.com 443nc -zv example.com 443Test-NetConnection example.com -Port 443powershell -Command "Test-NetConnection example.com -Port 443"One-shot listener — print first line received then exit
nc -l 8080 # OpenBSD nc; -p 8080 on traditionalnc -l 8080ncat.exe -l 8080 # requires Nmap installncat.exe -l 8080 # requires Nmap installSend a file over TCP (receiver listens, sender pipes)
# receiver:\nnc -l 9000 > received.bin\n# sender:\nnc -N receiver-host 9000 < send.binnc -l 9000 > received.bin # receiver\nnc -N receiver-host 9000 < send.bin # sender$tcp = New-Object Net.Sockets.TcpClient("host", 9000); $s = $tcp.GetStream(); [byte[]]$b = [IO.File]::ReadAllBytes("send.bin"); $s.Write($b, 0, $b.Length); $tcp.Close()Gotchas
- Linux `nc` flag set diverges across flavours: `nc.openbsd` uses `-l <port>` to listen; `nc.traditional` uses `-l -p <port>` (must include `-p`). Cross-distro scripts break silently — Ubuntu 22.04 ships OpenBSD nc, RHEL 9 ships nmap-ncat (different flag set again). Pin with full path (`/usr/bin/ncat`) or use `ncat` everywhere for stable semantics.
- `nc -z host port` does NOT send data — it does a TCP handshake and immediately closes. Some services (databases, queues) log the failed connect as an ERROR even though it's benign — DBA pages can fire from a Kubernetes readiness probe. Prefer a real protocol-aware probe (`pg_isready`, `redis-cli ping`) over a blind `nc -z` when noise matters.
- Listening with `nc -l 8080` accepts ONE connection then exits — fine for tests, terrible for long-running services. Use `ncat --keep-open -l 8080` (Nmap nc) for multi-client, or `socat TCP-LISTEN:8080,fork EXEC:cmd` for full proxy/fork semantics. Don't roll a production server on bare `nc`.
- `nc -l 0.0.0.0 8080` binds to ALL interfaces — including the public-facing NIC. On a cloud VM with an open security group, that's an unauthenticated TCP echo open to the internet. Always bind to `127.0.0.1` for local testing (`nc -l 127.0.0.1 8080`), or run with strict firewall rules.
- pwsh `Test-NetConnection` does ICMP ping THEN TCP probe by default — fails on hosts that block ICMP (most cloud VMs do). The TCP probe still runs and reports `TcpTestSucceeded: True`, but the `PingSucceeded: False` confuses operators. Use `Test-NetConnection -Port 80 -InformationLevel Quiet` to skip the ping noise.
WSL & PowerShell Core notes
Common tasks using nc
- Find which process is listening on a port
Identify the PID and process name bound to a local TCP/UDP port — for debugging "address already in use" errors, auditing what's exposed, and killing a zombie server holding port 3000.
- Scan a port range on a host
Check which TCP/UDP ports are open on a target host — for service discovery, firewall validation, post-deploy "is the new server reachable?" smoke tests, or troubleshooting connectivity ahead of an SSH/HTTP call that's timing out.
- Send raw TCP data to a port
Push arbitrary bytes (an HTTP request, a SMTP greeting, a custom protocol probe) to a remote TCP port and inspect the reply — for debugging service compatibility, capturing banners, reproducing protocol-level bugs, or scripting integrations with text-based protocols.
- Test a TCP connection with nc
Confirm whether you can open a TCP socket to host:port — the basic "is this thing reachable" check before debugging deeper protocol issues.