nc (netcat) —— 网络瑞士军刀
一句话定义
nc(netcat)是个极简的 TCP/UDP 工具:可以做客户端连接、可以监听端口当 server、可以传文件、可以做端口扫描。nc -zv host port 是测端口连通最快的命令——比 ping 适合大多数场景。
典型场景
- 测端口连通(最常用):
nc -zv host 8080 - 当临时 server 调试:
nc -lk -p 8080 - 测 K8s Service 通不通:
kubectl exec pod -- nc -zv my-svc 8080 - 抓应用发出的协议(看 raw bytes)
- 简单文件传输
装
# Linux 通常自带(netcat-openbsd 或 netcat-traditional)
apt install -y netcat-openbsd # Ubuntu / Debian (推荐)
yum install -y nmap-ncat # CentOS / RHEL (用 nmap 那个版本)
# macOS 自带
which nc
三个不同的 nc 实现
| 包名 | 命令 | 特点 |
|---|---|---|
netcat-openbsd | nc | OpenBSD 版本,最普及 |
netcat-traditional | nc | 老传统版(功能不同,flag 不一样) |
nmap-ncat | ncat | nmap 出品,功能最强(支持 TLS / proxy / ssl) |
不同实现 flag 不一样、互不兼容。下面以 OpenBSD 版为主(K8s 节点最常见)。
1. 测端口连通(最实用)
$ nc -zv 10.0.24.28 6443
Connection to 10.0.24.28 6443 port [tcp/*] succeeded!
$ nc -zv 10.0.24.99 6443
nc: connect to 10.0.24.99 port 6443 (tcp) failed: Connection refused
$ nc -zv 10.0.24.99 6443
nc: connect to 10.0.24.99 port 6443 (tcp) failed: Operation timed out
flag:
| flag | 含义 |
|---|---|
-z | zero-I/O:只测连通、不真传数据 |
-v | verbose:显示结果 |
-w <sec> | 超时(默认很长、脚本里必加) |
三种结果含义(经典面试题)
| 返回 | 网络含义 | 排查方向 |
|---|---|---|
succeeded | TCP 握手通 = L4 可达 | OK |
Connection refused | 包到了对端、对端发 RST | 端口没监听 / 防火墙 REJECT |
Operation timed out | 包发出去没回应 | 网络不通 / 防火墙 DROP / 对端挂 |
refused vs timeout 区别:
- refused = 对端"主动拒"(网络通)
- timeout = "对端没反应"(网络不通 / 被防火墙静默丢)
排错时分清这两种节省一半时间。
加超时(脚本必加)
# 默认 nc 等 75 秒才超时
nc -zv example.com 443
# 脚本里设短超时
nc -zv -w 3 example.com 443
-w 3 让 nc 最多等 3 秒。
UDP 端口
# UDP 测试不可靠(UDP 没握手、对端不回也无法判断)
nc -zvu example.com 53
# 实际验证 UDP 用 dig / 应用层测试
2. 当临时 server 监听
# 简单监听 8080
nc -lk -p 8080
# 客户端连
nc <server-IP> 8080
> hello ← 客户端打、server 看到
hello
flag:
| flag | 含义 |
|---|---|
-l | listen 模式 |
-k | keep-alive:一个连接关了还接下一个(默认连完就退) |
-p <port> | 监听端口(OpenBSD 版 -l 后直接跟端口) |
OpenBSD vs traditional 语法不一致
# OpenBSD (Ubuntu 推荐版)
nc -l 8080 # 监听 8080
# Traditional
nc -l -p 8080 # 监听 8080
不确定哪个版本:先 nc --help 看 flag。
实用场景:临时 HTTP server
# 在节点上跑(监听 8080,每个连接返回固定内容)
$ while true; do
echo -e "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\nhello" | nc -l -p 8080 -q 1
done
# 测
$ curl http://<节点-IP>:8080
hello
适合调试 LB / NodePort / Ingress 路由——你不需要起完整应用。
测 K8s NetworkPolicy
# A pod 监听 8080
kubectl exec pod-a -- nc -l 8080 &
# B pod 测连通
kubectl exec pod-b -- nc -zv pod-a-ip 8080
# 加 deny NetworkPolicy 看是否生效
kubectl apply -f deny-all-ingress.yaml
# 再测
kubectl exec pod-b -- nc -zv pod-a-ip 8080
# timeout → policy 生效
3. 文件传输
# 接收端(server)
nc -l -p 8080 > received.bin
# 发送端(client)
nc <server-IP> 8080 < to-send.bin
比 scp 快(无加密 overhead)。仅限可信网络——明文。
进阶:tar + nc(整目录传输)
# 接收端
nc -l -p 8080 | tar xz
# 发送端
tar cz mydir/ | nc <server> 8080
scp -r 替代。大量小文件场景 tar + nc 快很多。
4. 排错应用协议
# 看 HTTP server 实际响应
$ nc example.com 80
GET / HTTP/1.1
Host: example.com
HTTP/1.1 200 OK
Server: ECS (...)
Content-Type: text/html
Content-Length: 1256
<!doctype html>
...
手动构造 HTTP 请求、看 server 怎么回——抓 raw bytes。
测 Redis
$ nc redis-server 6379
PING
+PONG
SET key val
+OK
GET key
$3
val
QUIT
+OK
不装 redis-cli 也能简单交互。
测 SMTP
$ nc smtp.example.com 25
220 smtp.example.com ESMTP
HELO myhost
250 hello
QUIT
5. ncat(nmap 版)—— 更强大
yum install -y nmap-ncat
apt install -y ncat
ncat 比 nc 多几个杀手锏:
5.1 支持 TLS
# nc 不会 TLS
$ nc example.com 443
GET / HTTP/1.1 # 没法看真实响应
# 因为 nc 没建 TLS
# ncat 可以
$ ncat --ssl example.com 443
GET / HTTP/1.1
Host: example.com
HTTP/1.1 200 OK
...
5.2 当 TLS server
$ ncat --ssl --ssl-cert cert.pem --ssl-key key.pem -l 8443
5.3 端口扫描(简易版 nmap)
$ nc -zv example.com 20-25
nc: connect to example.com port 20 (tcp) failed: Connection refused
nc: connect to example.com port 21 (tcp) failed: Connection refused
Connection to example.com 22 port [tcp/*] succeeded!
nc: connect to example.com port 23 (tcp) failed: Operation timed out
...
nc OpenBSD 版用 -z host port-port 扫一段。但用 nmap 才是正经端口扫描工具。
6. 真实场景
Case 1: K8s Service 端口连通快速测
# 起测试 pod
$ kubectl run test -it --rm --image=busybox:1.36 --restart=Never -- sh
/ # nc -zv my-svc 8080
my-svc (10.96.1.5:8080) open
/ # nc -zv -w 3 broken-svc 8080
nc: broken-svc (10.96.2.5:8080): Connection refused
busybox 自带的 nc 是 BusyBox 版(功能精简但够测连通)。
Case 2: 验证防火墙规则
# 节点上加 deny 规则
ssh m1 'iptables -I INPUT 1 -p tcp --dport 30080 -j DROP'
# 外部测
nc -zv -w 3 <m1-IP> 30080
# Operation timed out ← DROP 行为:静默丢
# 改成 REJECT
ssh m1 'iptables -R INPUT 1 -p tcp --dport 30080 -j REJECT'
# 再测
nc -zv -w 3 <m1-IP> 30080
# Connection refused ← REJECT 行为:发 RST 拒
排错时根据 nc 返回类型反推防火墙规则:
- timeout → 包被 DROP(隐式拒)
- refused → 包被 REJECT(显式拒)
- succeeded → 通
Case 3: 调试 LoadBalancer 路由
# K8s LoadBalancer service
kubectl get svc my-svc
# my-svc LoadBalancer 10.96.1.5 1.2.3.4 80:30080/TCP
# 外部测 LB IP
nc -zv 1.2.3.4 80
# succeeded → LB → NodePort 路径 OK
# 直接测 NodePort(绕过 LB)
nc -zv <node-IP> 30080
# succeeded → 节点 OK
# 测 ClusterIP(集群内)
kubectl exec test -- nc -zv 10.96.1.5 80
# succeeded → kube-proxy OK
逐层定位哪里挂。
Case 4: 调试 Pod 出网
$ kubectl exec my-pod -- nc -zv -w 3 github.com 443
nc: github.com (140.82.114.4:443): Operation timed out
# Pod 出网不通。查:
# DNS 通吗
$ kubectl exec my-pod -- nslookup github.com
# OK → DNS 解析对
# 节点能不能出
$ ssh m1 nc -zv -w 3 github.com 443
# OK → 节点能出 但 pod 不能
# → CNI / iptables 出向规则问题
# → NetworkPolicy egress 限制?
$ kubectl get netpol -A
Case 5: 简易 chat / IPC 调试
# 节点 A 监听
nc -lk -p 8080
# 节点 B 发
nc <A-IP> 8080
> hello
# A 收到 "hello"
实际用:进程间 IPC 调试、网络协议手撕。
7. 反面教材
反面 1:以为 nc -z 也测 UDP
nc -zvu host 53
# 几乎永远 "succeeded"
UDP 无连接、nc 发个包就算"成功"——不代表对端在监听。
测 UDP 应该用应用层:
# DNS:用 dig
dig @<host> kubernetes.default
# SNMP:snmpwalk
snmpwalk -v 2c -c public <host>
反面 2:把 nc -l 当生产 service 用
nc -lk -p 80 # 简易"server"
只适合临时调试:
- 单线程(一次一个连接)
- 没认证 / 不加密
- 进程挂了不会重启
- 收到 EOF 就退
生产用 nginx / 应用框架。
反面 3:传敏感数据没加密
nc -l -p 8080 > secret.txt
nc <server> 8080 < secret.txt
明文传输。任何中间人都能抓。用 scp / rsync / croc(端到端加密)。
反面 4:忘 -w timeout、脚本卡死
# 脚本里
if nc -zv host 8080; then ... fi
# 网络不通 → 等 75 秒才返回
nc -zv -w 3 host 8080
写脚本永远 -w N。
反面 5:用 nc 测 TLS 端口看不出问题
nc -zv example.com 443
# succeeded
只测了 TCP 握手——没真测 TLS 握手。证书过期 / SNI 错 / 协议不兼容 nc 都看不到。
用 openssl s_client 测 TLS:
openssl s_client -connect example.com:443 -servername example.com < /dev/null
# 看证书 / cipher
详见 openssl.md。
8. 备选 / 互补工具
| 工具 | 用途 | 比 nc |
|---|---|---|
nc / ncat | 通用 | 经典 |
socat | 更强大的双向数据流 | 支持 unix socket / pty / SSL / 高级路由 |
curl --connect-timeout | HTTP 专用 | L7 |
openssl s_client | TLS 调试 | 看证书 / cipher |
nmap | 端口扫描 | 专业 |
iperf3 | 带宽测试 | nc 不行 |
tcpdump | 抓包 | 看协议层 |
socat —— nc 的高级版
# nc 不能做:把 TCP 端口连到 unix socket
socat TCP-LISTEN:8080,fork UNIX-CONNECT:/var/run/docker.sock
# 让本地 8080 通过 SSH tunnel 到远端 service
socat TCP-LISTEN:8080,fork SOCKS4A:proxy:target-host:80
# unix socket pair
socat UNIX-LISTEN:/tmp/a,fork UNIX-CONNECT:/tmp/b
复杂场景换 socat。
9. 快速 cheatsheet
# 测端口连通(最常用)
nc -zv -w 3 host port
# 监听端口(调试)
nc -lk -p 8080
# 临时 HTTP server
while true; do echo -e "HTTP/1.1 200 OK\r\n\r\nhello" | nc -l -p 8080 -q 1; done
# 文件传输
nc -l -p 8080 > out.bin # 接收
nc host 8080 < in.bin # 发送
# 整目录
nc -l -p 8080 | tar xz # 接收
tar cz dir/ | nc host 8080 # 发送
# 手撕 HTTP
printf "GET / HTTP/1.1\r\nHost: x.com\r\n\r\n" | nc x.com 80
# TLS 端口(要 ncat)
ncat --ssl host 443
# 在 K8s pod 里测
kubectl exec pod -- nc -zv -w 3 svc port