嵌入式设备ping不通?tcpdump 5分钟找到凶手,比加printf快10倍
嵌入式开发调试网络问题,最常见的画面:开发板ping不通网关,或者跟服务器连不上。然后呢?打着手电筒看网口灯、拿示波器点PHY芯片管脚、在代码里拼命加printk打网络数据——emmm,你确定要这样?
我见过一个兄弟,调试一个MQTT断连问题,在代码里加了30多行printk打数据包内容,编译烧录一次5分钟,折腾了一整天没找到原因。我过去敲了一行tcpdump,30秒定位是服务器端TLS证书过期了。
今天这篇不讲花哨的,就跟你聊tcpdump在嵌入式场景下的5种实战用法。随便哪种,都能让你少加100行printk。
前提:你的板子上有tcpdump吗?
大部分嵌入式Linux系统(Buildroot/Yocto出来的)默认没有tcpdump。别慌,两个办法:
方案一:交叉编译
# 下载tcpdump源码,交叉编译扔到板子上就行./configure--host=arm-linux-gnueabihf--prefix=/opt/tcpdumpmake&&makeinstall# 把tcpdump和libpcap.so拷到板子上arm-linux-gnueabihf-strip tcpdump# 减到500K左右scptcpdump root@板子IP:/usr/sbin/方案二:用Busybox自带的(阉割版)
# 如果Busybox编译时勾选了CONFIG_TCPSUPPORT# 有个阉割版能用,功能少但够用tcpdump-ieth0-n如果空间极度紧张(Flash只有4MB),还有一个骚招:把tcpdump编译成静态链接扔到/tmp里,反正tmpfs是内存。跑完就没了,不占Flash空间。
场景一:板子ping不通网关——看ARP就知道谁在搞鬼
嵌入式设备最常见场景:ping 192.168.1.1,卡住不动了。
# 在板子上抓ARP包tcpdump-ieth0-narp输出长这样:
12:34:56.789012 ARP, Request who-has 192.168.1.1 tell 192.168.1.100, length 46 12:34:57.789012 ARP, Request who-has 192.168.1.1 tell 192.168.1.100, length 46 12:34:58.789012 ARP, Request who-has 192.168.1.1 tell 192.168.1.100, length 46只发不收——说明网关没理你。这时候原因只有三个:
- IP不在同一网段(最常见):板子配了192.168.1.100/24,但网关是192.168.2.1
- MAC地址过滤:交换机的端口安全功能把陌生MAC拦了
- 物理层没通:PHY芯片auto-negotiation失败,Link没起来
如果看到:
ARP, Request who-has 192.168.1.1 tell 192.168.1.100 ARP, Reply 192.168.1.1 is-at 00:11:22:33:44:55ARP通了但ping还不行——那就不是链路层问题了,查路由表或防火墙。
场景二:TCP连接被拒——别猜,看RST包
另一个经典场景:板子上的应用连服务器,connect返回-1,errno=ECONNREFUSED。
tcpdump-ieth0-n'tcp port 8080'输出:
12:34:56.789 IP 192.168.1.100.12345 > 10.0.0.1.8080: Flags [S], seq 100 12:34:56.790 IP 10.0.0.1.8080 > 192.168.1.100.12345: Flags [R.], seq 0, ack 101SYN包发出去,立刻收到RST——服务器端口没开或者防火墙拦了。不需要猜,不需要看代码。
如果看到:
12:34:56.789 IP 192.168.1.100.12345 > 10.0.0.1.8080: Flags [S], seq 100 12:34:56.790 IP 10.0.0.1.8080 > 192.168.1.100.12345: Flags [S.], seq 200, ack 101 12:34:56.790 IP 192.168.1.100.12345 > 10.0.0.1.8080: Flags [.], ack 201三次握手完成——这时如果应用还报错,那是应用层的问题(协议解析、认证、TLS握手等),跟网络无关了。
场景三:嵌入式设备做服务端——看看谁在扫你
你的板子当服务器(比如HTTP API),有客户端连不上来,先抓包看看有没有人来找你:
tcpdump-ieth0-n'tcp port 80'如果根本没包——是客户端找不到你,跟板子没关系。查DNS解析、查路由可达性。
如果有SYN但没回复:
12:34:56.789 IP 192.168.1.200.54321 > 192.168.1.100.80: Flags [S], seq 789 # ... 没下文了说明你的服务端程序压根没在监听,或者防火墙把入站连接丢了。netstat -tlnp看一眼80端口有没有LISTEN就清楚了。
场景四:嵌入式设备上网慢——看TCP重传
设备联网了,但奇慢无比。一条AT指令要等好几秒?这就是TCP重传的典型症状。
tcpdump-ieth0-n'tcp[13] & 0x0c != 0'# 只抓RST和SYN包,精确定位连接问题或者更直接的:
# 抓重传包tcpdump-ieth0-n'tcp[13] & 4 != 0'看到大量重传(RST标志位),基本可以确定:
- WiFi/4G信号弱(嵌入式无线设备最常见)
- 服务器太远延迟太高
- 缓冲区太小,TCP window满了
进一步看看延迟:
# 带时间戳抓包,看延迟tcpdump-ieth0-n-tttt'host 服务器IP'对比每个包的时间戳,如果RTT超过500ms,那不管你怎么优化代码都没用——瓶颈在网络本身。
场景五:嵌入式板子没DHCP地址?抓DHCP包
tcpdump-ieth0-n-eport67or port68DHCP有四步握手:
# DISCOVER:板子找DHCP服务器 IP 0.0.0.0.68 > 255.255.255.255.67: DHCP-DISCOVER # OFFER:服务器回复 IP DHCP服务器.67 > 255.255.255.255.68: DHCP-OFFER # REQUEST:板子确认 IP 0.0.0.0.68 > 255.255.255.255.67: DHCP-REQUEST # ACK:服务器最终确认 IP DHCP服务器.67 > 255.255.255.255.68: DHCP-ACK缺了哪一步就查哪一步。没有OFFER=网络里没有DHCP服务器(或者说DHCP中继没配)。有OFFER没ACK=IP冲突或服务器拒绝了。
几个嵌入式场景下的tcpdump骚操作
场景:Flash空间只剩2MB
# 不要-i eth0全量抓,先指定过滤条件缩小# 抓完用-W限制文件大小,-C做轮转tcpdump-ieth0-n-C10-W5-w/tmp/capture.pcap'host 目标IP'# 最多5个文件,每个10MB,循环覆盖# 抓完了scp拿下来慢慢分析场景:分析之前抓的包
# 不在板子上看,把pcap拉回PC用Wireshark# 或者在板子上离线读取tcpdump-r/tmp/capture.pcap-n场景:板子没屏幕没键盘
# 开机自动抓包,出问题后分析# 加到/etc/init.d/rcS里tcpdump-ieth0-C5-W10-w/tmp/netlog.pcap'not port 22'&# 排除SSH端口避免把自己抓进去总结
嵌入式网络调试,顺序应该是:
看灯 → 抓包 → 看代码
先物理层,再链路层,再网络层,最后才是应用层代码。大多数时候,tcpdump在第二三步就把问题解决了,根本不需要改代码。
我见过太多人一上来就翻代码、加log、反复编译烧录——折腾半天发现是IP配错了或者网线松了。工具先上,脑子后用。
课后练习
- 你的板子ping不通外网,arp回复有,默认网关能ping通——怎么排查?
- 板子上跑HTTP服务器,客户端connect一直超时,tcpdump看不到任何SYN包到板子——问题可能在哪?
- 嵌入式4G模块上网,偶尔断连。怎么用tcpdump抓完整网络日志又不占太多Flash?
答案我就不写了,自己抓两把包就全明白了。