专栏文章
专栏文章
网络协议专栏
1. 网络协议专栏 #01:TCP/IP 协议栈 2. 网络协议专栏 #02:HTTP 协议 3. 网络协议专栏 #03:HTTPS 与 TLS 4. 网络协议专栏 #04:网络编程速查

网络协议专栏 #04:网络编程速查

发布于 2026-06-08 07:51 👁 7 次阅读
#cheatsheet#linux#network#debug

网络排查与编程常用命令速查,涵盖 ping/traceroute/dig/curl/tcpdump/Wireshark/netstat/ss/iptables,以及常见网络问题(超时/丢包/DNS 慢)的排查思路。

网络系列TCP-IP 协议栈 · HTTP 协议 · HTTPS 与 TLS · 相关:Shell 常用命令速查

⚠️ 约定<> 表示必填占位符,[] 表示可选项。命令示例均在 Linux/macOS 下验证。


目录

章节 说明
连通性探测 ping、traceroute/tracert
DNS 解析 dig、nslookup、host
HTTP 调试 curl、wget
抓包分析 tcpdump、Wireshark
连接状态查看 netstat、ss
防火墙基础 iptables
常见网络问题排查思路 超时/丢包/DNS 慢

连通性探测

ping

测试目标主机是否可达,以及往返时延(RTT)。

# 基础用法
ping <host>

# 指定发包次数
ping -c 4 8.8.8.8

# 指定包大小(字节)
ping -s 1400 <host>

# 指定发包间隔(秒)
ping -i 0.2 <host>

# 不解析域名(只显示 IP)
ping -n <host>

输出解读

PING 8.8.8.8: 56 data bytes
64 bytes from 8.8.8.8: icmp_seq=1 ttl=117 time=4.32 ms
...
--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 4.1/4.3/4.6/0.2 ms
字段 含义
ttl 剩余跳数,可估算网络路径长度
time 单次 RTT
packet loss 丢包率,>1% 需关注
mdev RTT 抖动,越小越稳定

traceroute / tracert

追踪数据包经过的每一跳路由,定位网络瓶颈。

# Linux/macOS
traceroute <host>
traceroute -n <host>          # 不解析域名,更快
traceroute -T <host>          # 使用 TCP(穿透防火墙)
traceroute -p 443 <host>      # 指定端口

# Windows
tracert <host>
tracert -d <host>             # 不解析域名

输出解读

 1  192.168.1.1   1.234 ms  1.123 ms  1.098 ms   ← 网关
 2  10.0.0.1      5.432 ms  5.211 ms  5.198 ms
 3  * * *                                          ← 该跳不响应 ICMP(不一定是问题)
 4  8.8.8.8      15.234 ms 14.987 ms 15.001 ms

* * * 表示该跳的路由器不回应,但后续跳如果正常,说明网络通畅。


DNS 解析

dig

最强大的 DNS 查询工具。

# 查询 A 记录(默认)
dig example.com

# 查询指定记录类型
dig example.com A
dig example.com AAAA          # IPv6
dig example.com MX            # 邮件服务器
dig example.com CNAME
dig example.com TXT
dig example.com NS            # 名称服务器

# 指定 DNS 服务器
dig @8.8.8.8 example.com

# 精简输出(只看结果)
dig +short example.com

# 追踪完整解析过程
dig +trace example.com

# 反向解析(IP → 域名)
dig -x 8.8.8.8

输出关键字段

;; ANSWER SECTION:
example.com.    300    IN    A    93.184.216.34
                ↑TTL        ↑类型  ↑IP

nslookup

交互式 DNS 查询(Windows/Linux 均可用)。

nslookup example.com
nslookup example.com 8.8.8.8   # 指定 DNS 服务器
nslookup -type=MX example.com  # 查询 MX 记录

host

简洁的 DNS 查询工具。

host example.com
host -t MX example.com
host 8.8.8.8                   # 反向解析

HTTP 调试

curl

功能最全面的 HTTP 命令行工具。

# GET 请求
curl https://example.com

# 显示响应头
curl -I https://example.com          # 只看头部(HEAD 请求)
curl -i https://example.com          # 头部 + body

# POST 请求
curl -X POST -d 'key=value' https://example.com/api
curl -X POST -H 'Content-Type: application/json' \
     -d '{"key":"value"}' https://example.com/api

# 自定义请求头
curl -H 'Authorization: Bearer <token>' https://example.com/api

# 跟随重定向
curl -L https://example.com

# 保存响应到文件
curl -o output.html https://example.com
curl -O https://example.com/file.zip  # 使用远程文件名

# 显示详细连接信息(调试 TLS、重定向等)
curl -v https://example.com

# 显示计时信息
curl -w "\nTime: %{time_total}s\n" -o /dev/null -s https://example.com

# 忽略 TLS 证书验证(仅调试用)
curl -k https://self-signed.example.com

# 设置超时
curl --connect-timeout 5 --max-time 30 https://example.com

# 通过代理
curl -x http://proxy:8080 https://example.com

curl 计时模板(排查慢请求必备):

curl -w "
DNS:          %{time_namelookup}s
Connect:      %{time_connect}s
TLS Handshake:%{time_appconnect}s
TTFB:         %{time_starttransfer}s
Total:        %{time_total}s
" -o /dev/null -s https://example.com

wget

适合下载文件。

wget https://example.com/file.zip
wget -O output.zip https://example.com/file.zip
wget -c https://example.com/file.zip    # 断点续传
wget -r -np https://example.com/docs/   # 递归下载目录

抓包分析

tcpdump

命令行抓包,适合服务器环境。

# 基础用法:抓指定网卡的包
tcpdump -i eth0

# 抓取指定主机的包
tcpdump -i any host 192.168.1.1

# 抓取指定端口的包
tcpdump -i any port 80
tcpdump -i any port 443

# 抓取 HTTP 流量(不加密)
tcpdump -i any -A port 80

# 组合过滤
tcpdump -i any host 192.168.1.1 and port 443

# 保存到文件(供 Wireshark 分析)
tcpdump -i eth0 -w capture.pcap

# 从文件读取
tcpdump -r capture.pcap

# 显示 IP 和端口(不解析域名,更快)
tcpdump -n -i any port 80

# 常用参数
# -n       不解析 IP/端口为域名/服务名
# -A       以 ASCII 显示包内容
# -X       以十六进制+ASCII 显示
# -v/-vv   更详细的输出
# -c <N>   只抓 N 个包
# -s <N>   每包抓取字节数(0 = 全部)

常用过滤表达式

# TCP SYN 包(新连接)
tcpdump 'tcp[tcpflags] & tcp-syn != 0'

# TCP RST 包(异常断开)
tcpdump 'tcp[tcpflags] & tcp-rst != 0'

# 排除 SSH 流量(避免干扰)
tcpdump -i eth0 not port 22

# 抓取 DNS 查询
tcpdump -i any port 53

Wireshark 分析要点

Wireshark 是图形化抓包工具,适合详细分析。

常用显示过滤器

# HTTP 流量
http

# 指定 IP
ip.addr == 192.168.1.1
ip.src == 192.168.1.1
ip.dst == 192.168.1.1

# 指定端口
tcp.port == 443
tcp.port == 80

# TCP 握手
tcp.flags.syn == 1

# TCP 重传
tcp.analysis.retransmission

# HTTP 状态码
http.response.code == 404
http.response.code >= 500

# TLS 握手
tls.handshake.type == 1   # ClientHello
tls.handshake.type == 2   # ServerHello

分析 TCP 问题的常用视图


连接状态查看

netstat(传统工具)

# 查看所有监听端口
netstat -tlnp        # TCP 监听,显示进程
netstat -ulnp        # UDP 监听

# 查看所有连接
netstat -anp

# 统计各状态连接数
netstat -ant | awk '{print $6}' | sort | uniq -c | sort -rn

# 查看某个端口的连接
netstat -anp | grep :8080

ss(现代替代工具,更快)

# 查看所有 TCP 连接
ss -t

# 查看监听端口
ss -tlnp             # TCP 监听
ss -ulnp             # UDP 监听

# 查看所有连接(含状态)
ss -antp

# 过滤指定状态
ss -t state ESTABLISHED
ss -t state TIME-WAIT
ss -t state CLOSE-WAIT

# 过滤指定端口
ss -t sport = :8080
ss -t dport = :443

# 统计 TIME_WAIT 数量
ss -t state TIME-WAIT | wc -l

TCP 连接状态速查

状态 说明 常见问题
ESTABLISHED 连接正常
TIME_WAIT 主动关闭方等待 2MSL 大量 TIME_WAIT 说明短连接过多
CLOSE_WAIT 被动关闭方收到 FIN 后 大量 CLOSE_WAIT 说明应用未及时关闭连接
SYN_SENT 客户端发出 SYN 等待响应 连接超时,目标不可达
SYN_RCVD 服务端收到 SYN 大量可能是 SYN Flood 攻击

防火墙基础

iptables

Linux 内核防火墙,规则链:INPUT(入)、OUTPUT(出)、FORWARD(转发)。

# 查看规则
iptables -L -n -v
iptables -L INPUT -n --line-numbers

# 允许端口
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 拒绝端口
iptables -A INPUT -p tcp --dport 8080 -j DROP

# 允许特定 IP
iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT

# 删除规则(按行号)
iptables -D INPUT 3

# 清空所有规则
iptables -F

# 保存规则(CentOS/RHEL)
service iptables save
# Ubuntu
iptables-save > /etc/iptables/rules.v4

常见网络问题排查思路

连接超时

排查步骤:
1. ping <目标IP>
   → 丢包/超时:网络层不通,检查路由、防火墙
   → 正常:继续下一步

2. telnet <目标IP> <端口> 或 nc -zv <目标IP> <端口>
   → 连接拒绝(Connection refused):端口未监听,检查服务是否启动
   → 连接超时:端口被防火墙拦截

3. traceroute <目标IP>
   → 找到在哪一跳开始丢包/超时

4. 检查服务端 netstat/ss
   → 确认端口是否在监听
   → 是否有大量 SYN_RCVD(可能是 SYN Flood)

丢包

排查步骤:
1. ping -c 100 <目标IP>
   → 统计丢包率和 RTT 抖动(mdev)

2. mtr <目标IP>(实时版 traceroute+ping)
   → 找到丢包发生在哪一跳

3. tcpdump 抓包
   → 看 TCP 重传次数(tcp.analysis.retransmission)

4. 检查网卡错误
   → ifconfig eth0 或 ip -s link show eth0
   → 看 errors/dropped/overruns 字段

DNS 解析慢

排查步骤:
1. 测量 DNS 解析时间
   → time dig example.com
   → curl 的 time_namelookup 字段

2. 对比不同 DNS 服务器
   → dig @8.8.8.8 example.com
   → dig @1.1.1.1 example.com
   → dig @<本地DNS> example.com

3. 检查 /etc/resolv.conf
   → nameserver 配置是否合理
   → 是否有多个 nameserver(按顺序尝试,第一个超时才用第二个)

4. 检查 /etc/hosts
   → 是否有错误的本地解析覆盖

5. 使用 nscd 或 systemd-resolved 本地 DNS 缓存

快速参考卡

场景 命令
检查端口是否开放 nc -zv <host> <port>
查看当前监听端口 ss -tlnp
查看 ESTABLISHED 连接数 ss -t state ESTABLISHED | wc -l
抓 443 端口流量 tcpdump -i any port 443 -w /tmp/cap.pcap
查 DNS 解析结果 dig +short example.com
测试 HTTP 接口 curl -v -X POST -H 'Content-Type: application/json' -d '{}' https://api/endpoint
查看网卡流量 iftop -i eth0nload eth0
查看路由表 ip route showroute -n
测试 TLS 证书 openssl s_client -connect example.com:443
检查端口占用 lsof -i :8080

参考资料

  • 《趣谈网络协议》— 刘超,极客时间,第 7、18、19 讲
  • man tcpdumpman ssman iptables
  • Wireshark 官方文档

Socket 编程实战

本节内容来自极客时间《网络编程实战》(盛延敏)和《网络排查案例课》(胜辉)。

TCP Socket 完整编程流程

TCP 连接本质是四元组 (clientIP:clientPort, serverIP:serverPort) 唯一确定的一条双向通道。

服务端流程

// 1. 创建监听 socket
int listenfd = socket(AF_INET, SOCK_STREAM, 0);

// 2. 绑定地址和端口
struct sockaddr_in servaddr;
servaddr.sin_family      = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port        = htons(12345);
bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

// 3. 开始监听(backlog 为半连接队列 + 全连接队列上限)
listen(listenfd, 1024);

// 4. 接受连接(阻塞直到有客户端连入)
int connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);

// 5. 读写数据
read(connfd, buf, sizeof(buf));
write(connfd, response, len);

// 6. 关闭连接(触发 FIN,进入四次挥手)
close(connfd);

客户端流程

// 1. 创建 socket
int sockfd = socket(AF_INET, SOCK_STREAM, 0);

// 2. 发起连接(触发三次握手)
struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_port   = htons(12345);
inet_pton(AF_INET, "192.168.1.1", &servaddr.sin_addr);
connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

// 3. 发送数据
send(sockfd, data, len, 0);

// 4. 接收数据
recv(sockfd, buf, sizeof(buf), 0);

// 5. 关闭
close(sockfd);

关键原则

函数 阻塞行为 注意事项
write/send 等待数据全部拷贝到发送缓冲区后返回 返回成功 ≠ 对端已收到
read/recv 接收缓冲区有数据就立即返回,不等满 返回 0 表示对端发送了 FIN
accept 阻塞直到有完成三次握手的连接 建议设为非阻塞,避免 RST 后卡死
connect 阻塞直到三次握手完成或超时 非阻塞时立即返回 EINPROGRESS

非阻塞 Socket 与 epoll 事件驱动

阻塞 vs 非阻塞

模式 read 无数据时 write 缓冲区满时
阻塞 挂起等待 挂起等待
非阻塞 立即返回 EAGAIN/EWOULDBLOCK 写入尽可能多,返回实际写入字节数

设置非阻塞

int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);

epoll 三步走

// 1. 创建 epoll 实例
int efd = epoll_create1(0);

// 2. 注册感兴趣的事件(边缘触发 ET)
struct epoll_event ev;
ev.events  = EPOLLIN | EPOLLET;   // 可读 + 边缘触发
ev.data.fd = connfd;
epoll_ctl(efd, EPOLL_CTL_ADD, connfd, &ev);

// 3. 等待事件(-1 表示永不超时)
struct epoll_event events[128];
int n = epoll_wait(efd, events, 128, -1);
for (int i = 0; i < n; i++) {
    if (events[i].data.fd == listenfd) {
        // 新连接到来
        int fd = accept(listenfd, ...);
        make_nonblocking(fd);
        ev.data.fd = fd;
        epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ev);
    } else {
        // 已连接 socket 可读
        while ((n = read(events[i].data.fd, buf, sizeof(buf))) > 0) { ... }
        if (errno == EAGAIN) { /* 数据读完,继续等待 */ }
    }
}

ET vs LT 对比

触发模式 含义 要求
LT(条件触发,默认) 只要缓冲区有数据就持续通知 每次处理部分数据即可
ET(边缘触发) 仅在状态变化时通知一次 必须一次性读完所有数据,否则不再通知

ET 模式效率更高,但必须搭配非阻塞 I/O,否则读完后 read 会阻塞。

select / poll / epoll 对比

特性 select poll epoll
fd 数量限制 1024(FD_SETSIZE) 无限制 无限制
时间复杂度 O(n) 遍历所有 fd O(n) O(就绪事件数)
内核态/用户态拷贝 每次调用都拷贝 每次调用都拷贝 只注册时拷贝一次
适用场景 小并发、跨平台 小并发 高并发(C10K+)

粘包/拆包问题与解决方案

TCP 是字节流协议,没有天然的消息边界。发送 "hello" 和 "world" 两次,接收端可能一次收到 "helloworld"(粘包),也可能分两次收到 "hel" 和 "loworld"(拆包)。

三种解决方案

方案 原理 示例
定长消息 每条消息固定 N 字节 简单但浪费带宽
分隔符 用特殊字符(如 \r\n)标记消息结束 HTTP header 用 \r\n\r\n
长度前缀(推荐) 消息头部包含消息体长度字段 [4字节长度][消息体]

长度前缀实现(发送端)

struct Message {
    uint32_t length;   // 消息体字节数(网络字节序)
    uint32_t type;     // 消息类型
    char     body[0];  // 消息体(变长)
};

// 发送时:
message.length = htonl(body_len);  // 主机序 → 网络序
send(sockfd, &message, sizeof(uint32_t)*2 + body_len, 0);

长度前缀实现(接收端)

// 先读 4 字节长度
uint32_t msg_len;
readn(fd, &msg_len, 4);
msg_len = ntohl(msg_len);   // 网络序 → 主机序

// 再读消息体
char buf[msg_len];
readn(fd, buf, msg_len);    // readn 循环读直到读满

字节序转换函数速查

htons(x)   // host → network,16位(端口号用这个)
htonl(x)   // host → network,32位(IP地址/长度字段用这个)
ntohs(x)   // network → host,16位
ntohl(x)   // network → host,32位

网络排查案例:TIME_WAIT 过多

现象ss -t state TIME-WAIT | wc -l 数量很大(数千甚至数万)。

原因:TIME_WAIT 是主动关闭方在发出最后一个 ACK 后等待 2MSL(约 60 秒)的状态,目的是确保对端收到 ACK。大量 TIME_WAIT 说明服务端在主动关闭大量短连接(如 HTTP 短连接场景)。

排查与处理

# 查看 TIME_WAIT 数量
ss -t state TIME-WAIT | wc -l

# 查看哪些端口的 TIME_WAIT 最多
ss -t state TIME-WAIT | awk '{print $4}' | cut -d: -f2 | sort | uniq -c | sort -rn | head

# 内核参数调优(谨慎修改)
# 开启 TIME_WAIT 快速回收(仅在 NAT 环境外使用)
sysctl net.ipv4.tcp_tw_reuse=1     # 允许复用 TIME_WAIT 连接(客户端侧)
sysctl net.ipv4.tcp_fin_timeout=30 # 缩短 FIN_WAIT2 超时

根本解法:使用长连接(HTTP Keep-Alive、连接池),减少频繁建立/断开连接。

网络排查案例:连接超时

排查步骤:
1. ping <目标IP>
   → 丢包/超时:网络层不通,检查路由、防火墙
   → 正常:继续下一步

2. nc -zv <目标IP> <端口>
   → Connection refused:端口未监听,检查服务是否启动
   → 超时无响应:端口被防火墙拦截

3. traceroute -T -p <端口> <目标IP>
   → 找到在哪一跳开始丢包(TCP traceroute 可穿透部分防火墙)

4. 两侧同时抓包对比(关键!)
   → tcpdump -i any host <对端IP> -w /tmp/cap.pcap
   → 用 TCP 裸序列号定位两端的同一个 TCP 流
   → 对比报文到达时序,判断丢包位置

网络排查案例:DNS 解析慢

排查步骤:
1. 测量 DNS 解析耗时
   time dig example.com
   curl -w "DNS: %{time_namelookup}s\n" -o /dev/null -s https://example.com

2. 对比不同 DNS 服务器响应时间
   dig @8.8.8.8 example.com
   dig @1.1.1.1 example.com
   dig @<本机DNS> example.com

3. 检查 /etc/resolv.conf
   → nameserver 配置的 DNS 服务器是否可达
   → options timeout:2 attempts:2 可缩短超时

4. 检查 ndots 配置(容器环境常见问题)
   → ndots:5(K8s 默认)会导致短域名先尝试 5 次带集群后缀的查询
   → 对外部域名加 "." 结尾可跳过搜索域:dig example.com.

网络排查案例:TCP 重传与 Nginx 499

TCP 重传类型速查

类型 触发条件 特征
超时重传 RTO 内未收到 ACK 时间间隔呈指数增长(200ms→400ms→800ms...)
快速重传 收到 3 个重复 ACK(DupAck) 无需等待 RTO,立即重传
Spurious 重传 已被确认的包再次发送 影响较小,一般忽略

Nginx 499 根因:客户端在服务端返回响应前主动关闭了连接(发送 FIN)。常见原因:


参考资料

  • 《网络编程实战》— 盛延敏,极客时间
  • 《网络排查案例课》— 胜辉,极客时间
← 返回列表

评论 (0)

暂无评论,来留下第一条吧。

发表评论