
所属计划:智能摄像头 30 天路线图 · 第一阶段(基础与全局)
实验日期:2026-09-30
实验环境:Raspberry Pi(
192.168.0.108,wlan0)+ Mac(192.168.0.106)+ Wireshark 4.4.8
一、当天目标与产出
| 项目 | 内容 |
|---|---|
| 目标 | 看到"连不上 / 卡顿 / 延迟"时,脑子里能浮现一条"包的旅程":从哪出发 → 经过哪些节点 → 在哪丢了或慢了 |
| 路线图实验 | 抓包观察一次 HTTP / TCP / UDP 通信 |
| 实际完成 | 实验 A(DNS)、B(HTTP/TCP)、C(UDP)、D(延迟与路径排查) |
| 产出文件 | dns.pcap、http.pcap、udp.pcap、Follow TCP Stream 截图 |
二、核心概念
1. 封装:一个包是层层"套信封"
应用数据(HTTP 请求 / RTSP 指令 / RTP 视频载荷)
└ 加 TCP/UDP 头(源端口、目的端口...) → 段 / 数据报
└ 加 IP 头(源 IP、目的 IP、TTL) → 包
└ 加以太网头(源 MAC、目的 MAC) → 帧
一句话:IP 决定"去哪台机器",端口决定"找哪个程序"。
2. TCP 与 UDP
| TCP | UDP | |
|---|---|---|
| 连接 | 三次握手建立,四次挥手关闭 | 无连接,直接发 |
| 可靠性 | 丢了重传,保证顺序 | 丢了就丢了,发送方不知道 |
| 头部大小 | 20 字节起(本次抓包含时间戳选项为 32 字节) | 固定 8 字节、4 个字段 |
| 摄像头里的用途 | HTTP API、RTSP 控制信令、鉴权 | RTP 视频 / 音频流 |
对应关系:控制面要可靠 → TCP;媒体面要实时 → UDP(迟到的旧帧没有价值,重传只会增加延迟)。
3. 局域网、NAT 与公网
- 私网地址段:
10.x、172.16--31.x、192.168.x,只在内部有效。 - NAT 把"私网 IP:端口"翻译成"公网 IP:端口"再发出。外部默认连不到内部设备。
- 所以摄像头产品几乎都走云中转或 P2P 打洞,而不是让用户自己做端口映射。
4. 防火墙要想到四层
- NAT(地址转换)
- 路由器防火墙
- 云服务商安全组(最容易忘)
- 设备本机防火墙
5. TTL 与逐跳转发
IP 头里的 TTL 每经过一台路由器减 1,减到 0 时该路由器丢弃包并回一个 ICMP 超时消息。traceroute 就是利用这一点,把每一跳的路由器找出来。
6. 路由选"最具体的"
路由表按最长前缀匹配 选路。VPN 软件常加 0.0.0.0/1 和 128.0.0.0/1 两条路由来覆盖全部公网流量,而 192.168.0.0/24 因前缀更长,局域网流量仍然直连。
三、实验记录
实验 A:DNS(UDP 53)
bash
sudo tcpdump -i wlan0 -n udp port 53 -w dns.pcap
dig example.com
- 抓到 2 个包:1 个查询、1 个应答。
- DNS 服务器
223.5.5.5,协议 UDP,耗时 36ms,返回两条 A 记录。
实验 B:HTTP over TCP
bash
# Pi
sudo tcpdump -i wlan0 -n tcp port 8080 -w http.pcap
# Mac
curl -v http://192.168.0.108:8080/
共抓到 14 个包 ,去掉 3 个重复包为 11 个有效包,整个过程约 19ms。
| No. | 方向 | 标志 | 含义 |
|---|---|---|---|
| 1 | Mac → Pi | SYN | 握手第 1 步 |
| 2 | Pi → Mac | SYN, ACK | 握手第 2 步 |
| 3、4 | (重复) | 见"问题 3" | |
| 5 | Mac → Pi | ACK | 握手第 3 步,连接建立 |
| 6 | (重复) | 重复的 ACK | |
| 7 | Mac → Pi | PSH, ACK,81 字节 | GET / HTTP/1.1 |
| 8 | Pi → Mac | ACK | 确认收到请求(Ack=82) |
| 9 | Pi → Mac | PSH, ACK,112 字节 | 响应头 |
| 10 | Pi → Mac | FIN, PSH, ACK,15 字节 | 响应体 camera-demo ok,并带 FIN,服务端先关闭 |
| 11 | Mac → Pi | ACK | 确认响应头(Ack=113) |
| 12 | Mac → Pi | ACK | 确认响应体和 FIN(Ack=129) |
| 13 | Mac → Pi | FIN, ACK | 客户端关闭 |
| 14 | Pi → Mac | ACK | 最后确认,连接关闭 |
包数分类:握手 3 + 重复 3 + 带数据 3(7、9、10)+ 纯确认 2(8、11)+ 挥手 3(12、13、14)= 14。
字节数核对
- 请求 81 字节:
GET / HTTP/1.1\r\n(16)+Host: ...(26)+User-Agent: curl/8.7.1(24)+Accept: */*(13)+ 空行(2)。 - 响应头 112 字节:状态行 17 + Server 行 36 + Date 行 37 + Content-Length 行 20 + 空行 2。
- 响应体 15 字节 =
camera-demo ok+ 换行,与Content-Length: 15一致。 - 整个对话 81 + 112 + 15 = 208 字节,与 Follow TCP Stream 窗口显示一致。
HTTP/1.0 的特征 :第 10 包是服务端主动带 FIN,说明 Python BaseHTTP 是"一个请求一条连接,发完就关";HTTP/1.1 长连接不会这样。
实验 C:UDP
bash
# Pi 终端 1
sudo tcpdump -i wlan0 -n udp port 9999 -X -w udp.pcap
# Pi 终端 2
nc -u -l 9999
# Mac
echo "hello camera" | nc -u 192.168.0.108 9999
抓到 1 个包 :192.168.0.106.63658 > 192.168.0.108.9999: UDP, length 13。
IP 头(20 字节) 45 00 0029 ... 40(TTL=64) 11(协议=UDP) ... c0a8006a(源) c0a8006c(目的)
UDP 头(8 字节) f8aa(源端口 63658) 270f(目的端口 9999) 0015(长度 21) ccc8(校验和)
数据(13 字节) 68 65 6c 6c 6f 20 63 61 6d 65 72 61 0a = "hello camera\n"
- 数据区之后多出的一个
00不属于 UDP 数据(UDP 长度字段只有 13 字节数据),推测是以太网最小帧长的填充。 - 客户端端口随机(63658)、服务端端口固定(9999),与 TCP 一致。
nc -u发完不会自己退出:UDP 没有连接关闭的概念。
实验 D:延迟与路径排查
bash
ping -c 10 154.8.173.130
ss -tn
traceroute -n 223.5.5.5
sudo traceroute -I -n 223.5.5.5
D-1 云服务器不可达(分层排查)
| 检查项 | 结果 | 结论 |
|---|---|---|
ping 192.168.0.1 |
0% 丢包,约 2ms | Pi 到路由器正常 |
ping 223.5.5.5 |
0% 丢包,约 40ms | 公网出口正常 |
ping 154.8.173.130 |
100% 丢包 | 只有这台服务器不可达 |
ss -tnp |
到 154.8.173.130:1883 一直 SYN-SENT,进程为 Python(pid 4502) |
握手第 1 步后无回应 |
| 最终确认 | 腾讯云服务器到期未续费 | 根因 |
超时与拒绝的区别
| 现象 | 含义 |
|---|---|
Connection refused(收到 RST) |
服务器在线,但端口没有程序监听 |
一直 SYN-SENT / 超时 |
服务器无回应:关机、不存在,或被防火墙静默丢弃 |
D-2 ss -tn 的其他观察
- 1883 是 MQTT 默认端口,1935 是 RTMP 默认端口,Pi 上有程序在尝试连云服务器这两个服务。
- 本机
8554(常见 RTSP 备用端口)有一条连接Send-Q约 2.2MB、对端Recv-Q约 112KB,说明客户端读得比服务端送得慢,数据在堆积(背压)。这是 Day 09--11 视频卡顿的典型成因之一。
D-3 traceroute 对照(223.5.5.5,Pi,ICMP 模式,共 16 跳)
| 跳 | 地址 | 耗时 | 含义 |
|---|---|---|---|
| 1 | 192.168.0.1 | ≈3ms | 第一层路由器(默认网关) |
| 2 | 192.168.1.1 | ≈3ms | 第二层网关(私网) |
| 3 | 10.12.128.1 | ≈8ms | 运营商内部接入设备(私网) |
| 4--5 | 120.80.x / 120.82.x | 7--10ms | 运营商本地网络 |
| 6 | 219.158.7.225 | ≈47ms | 延迟跳升,进入跨城骨干链路 |
| 7--9 | 125.33.x / 61.148.x / 61.49.x | ≈39ms | 骨干 / 目标区域网络 |
| 10--15 | * * * |
无 | 设备转发了包但不回应探测 |
| 16 | 223.5.5.5 | ≈42--46ms | 终点 |
- 家里有两层私网网关 (
192.168.0.1→192.168.1.1)加运营商的10.x,说明包出门前经过多次地址转换。 - 跳数多不等于慢;慢主要来自"跨了多远"(第 5→6 跳多出约 37ms)。
ping的ttl=49与 16 跳的路径量级吻合(假设对端初始 TTL 为 64,则回程经过约 15 台路由器)。
D-4 UDP 与 ICMP 两种探测方式
| 方式 | 命令 | 结果 |
|---|---|---|
| UDP(默认) | traceroute -n 223.5.5.5 |
第 9 跳后全是 *,没走到终点 |
| ICMP | sudo traceroute -I -n 223.5.5.5 |
第 16 跳到达 223.5.5.5 |
同一台 Pi、同一个(可达的)目标,换一种探测方式结果就不同。* * * 只表示该跳没有回应探测包,不等于包被丢了。
D-5 Mac 开关 VPN 的对照
VPN 开(utun4) |
VPN 关(直连) | |
|---|---|---|
route -n get 223.5.5.5 |
128.0.0.0/1,网关 10.8.0.1,接口 utun4 |
--- |
| traceroute 第 1 跳 | 10.8.0.1,≈50ms |
192.168.0.1,≈3ms |
| 路径 | 进入隧道对端内部网络 | 家里路由 → 二级网关 → 运营商 |
四、问题与解决汇总
| # | 现象 | 原因 | 解决 / 结论 |
|---|---|---|---|
| 1 | http.pcap 为 0 字节,0 packets captured |
在 Pi 上 curl Pi 自己的 IP,流量走回环接口 lo,不经过 wlan0;且过滤条件写了 host 154.8.173.130,与该次通信两端无关 |
改为 Mac curl Pi,Pi 上抓 wlan0 的 tcp port 8080。知识点:同一台机器内部通信不出网卡 |
| 2 | http.pcap 中第 3、4、6 包为红色(Out-Of-Order / Dup ACK) | 第 4 包是第 2 包的完整复制(Pi 收到重复 SYN 后重发 SYN-ACK);第 3 包是 Mac 的第二个 SYN(缺 ECE/CWR 标志);第 6 包是第 5 包的重复 | 能确定它们是什么,但不能确定根本原因(Wi-Fi 链路延迟 / macOS 的 ECN 回退 / 多接口,均未验证)。不影响通信结果。红色异常 ≠ 故障 |
| 3 | UDP 首次抓到的不是 hello camera |
先启动了 nc -l 收到数据后才启动 tcpdump;抓到的是 Pi 端 nc 里按回车产生的 1 字节(0a)回包 |
先抓包后发送,且不在 nc 终端按回车。重抓得到 13 字节数据包 |
| 4 | ping 腾讯云 100% 丢包,ss 显示 SYN-SENT |
云服务器到期未续费 | 见实验 D-1 |
| 5 | Mac 的 traceroute 第 1 跳 ≈50ms、走 10.8.0.1 |
Mac 开了 VPN,公网流量经 utun4 隧道 |
测公网延迟前先确认 VPN 状态 |
| 6 | 同一目标 traceroute 末尾全是 * * *,看似不可达 |
默认 UDP 探测不一定被回应 | 用 -I 走 ICMP 对照;* * * 不能单独作为不可达的证据 |
| 7 | 《包的旅程》第 1 题包数分类有误 | "1 个数据"实为 3 个带数据包 + 2 个纯 ACK;"4 个挥手"实为 3 个(首个 FIN 搭在第 10 包) | 按第三节"包数分类"修正 |
五、关键认知
- 同机通信走
lo,不出网卡。抓包前先想清楚流量会经过哪个接口。 - 抓包三步法:先看方向(谁发给谁)→ 再看标志(SYN / ACK / FIN)→ 最后看序号(数据是否连续)。
- Ack 是"我期望收到的下一个字节编号";FIN 也占 1 个序号。
- 红色异常包 ≠ 故障,要看是否持续出现、是否影响最终结果。
- 超时 ≠ 拒绝:超时查网络和服务器本身,拒绝查服务进程。
- 没有对照组的观察容易被当成结论 。traceroute、ping、
ss要互相印证。 - 排查要在出问题的那台设备上做,且要先确认 VPN 等变量。
- 路径由路由表的最长前缀匹配决定,VPN 与局域网可同时存在而互不干扰。
- 客户端端口随机、服务端端口固定,TCP 和 UDP 都一样。
- UDP 发送方不知道对方是否收到;TCP 靠 ACK 确认并重传。
六、命令速查
bash
# 抓包(Pi)
sudo tcpdump -i wlan0 -n tcp port 8080 -w http.pcap # 抓并存文件
tcpdump -n -r http.pcap # 回放摘要
tcpdump -n -X -r udp.pcap # 回放并显示十六进制
# 拷贝到 Mac
scp h***x@192.168.0.108:~/http.pcap ~/Desktop/
# 连通性与路径
ping -c 3 192.168.0.1 # 网关
ping -c 3 223.5.5.5 # 公网 IP(不依赖 DNS)
sudo traceroute -I -n 223.5.5.5 # ICMP 方式,判断是否到达
ip route # 路由表(Linux)
route -n get 223.5.5.5 # 路由(macOS),看 interface 是否为 utun
# 连接状态
ss -tn # TCP 连接
sudo ss -tnp | grep -E '1883|1935' # 带进程
# UDP 手动通信
nc -u -l 9999 # 接收
echo "hello camera" | nc -u <ip> 9999 # 发送
Wireshark 显示过滤器
tcp.port == 8080 ip.addr == 192.168.0.108
udp.port == 9999 dns
tcp.flags.syn == 1 tcp.analysis.flags
tcp.analysis.retransmission
七、下一步
Day 04 · HTTP / API:控制链入口 ------ 理解 REST、状态码、鉴权、超时、重试、幂等;实验:写一个最小设备管理 API,把"接口异常"变成可定位的问题。