设备调试中发现 4G 模块进行 MQTT 通信总是出问题,即 QoS 为 1 的情况下,总是收到重复的 Publish Message。即便回复了正确的 Pub ACK 包,也依旧会收到重复的 Publish Message。但是 Wifi 模块下就没有这个问题。
之前 Wifi 模块是通过笔记本 Wifi 共享,在笔记本上使用 Wireshark 进行抓包调试的。但是 4G 模块由于是直连腾讯云 MQTT 服务器,所以没法使用这种方案调试。后来想了个方案就是在自己的公网服务器上设置个转发服务,本地设备通过这个转发服务跟腾讯云 MQTT 服务器通信。这样就能在服务器上对数据包用 tcpdump 进行抓包分析了。
使用 Nginx 配置 TCP 代理转发服务
vim 打开 nginx.conf
在与 http 平级,http block 右括号的下方添加 include 配置
http {
...
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
# 以先为添加配置
include /etc/nginx/tcp.d/*.conf;
新建一个 mqtt.conf 配置文件,需要将域名替换为自己的 MQTT 域名。
mkdir tcp.d
cd tcp.d
vim mqtt.conf
stream{
upstream tcp_mqtt{
hash $remote_addr consistent;
server xxxxxx.iotcloud.tencentdevices.com:1883 max_fails=3 fail_timeout=10s;
}
server{
listen 1883;
proxy_connect_timeout 20s;
proxy_timeout 5m;
proxy_pass tcp_mqtt;
}
}
测试配置没问题之后,重新加载 Nginx 配置。
sudo nginx -t
sudo nginx -s reload
抓包工具 tcpdump 的使用方法
例如要对 https 请求做数据抓包,只抓 5 条:
$ sudo tcpdump -i any -c5 -nn port 443
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
11:46:20.036729 IP x.x.x.x.2747 > x.x.x.x.443: Flags [S], seq 3369075412, win 64240, options [mss 1400,nop,wscale 8,nop,nop,sackOK], length 0
11:46:20.036761 IP x.x.x.x.443 > x.x.x.x.2747: Flags [S.], seq 396179077, ack 3369075413, win 64240, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
11:46:20.039989 IP x.x.x.x.2748 > x.x.x.x.443: Flags [S], seq 3276788361, win 64240, options [mss 1400,nop,wscale 8,nop,nop,sackOK], length 0
11:46:20.040030 IP x.x.x.x.443 > x.x.x.x.2748: Flags [S.], seq 1465393500, ack 3276788362, win 64240, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
11:46:20.067003 IP x.x.x.x.2747 > x.x.x.x.443: Flags [.], ack 1, win 1028, length 0
5 packets captured
5 packets received by filter
0 packets dropped by kernel
显示数据包内容
To see the packet content, tcpdump provides two additional flags: -X to print content in hex, and ASCII or -A to print the content in ASCII.
但是,无论是 hex 还是 ascii ,输出都非常不直观,导出文件试试
To save packets to a file instead of displaying them on screen, use the option -w (for write):
如果要对 MQTT 协议进行抓包,并写入 pcap 文件,可以使用:
sudo tcpdump -i any -nn port 1883 -x -w webserver.pcap
抓包效果确实立竿见影,日志铁证如山,确实是我们的 bug ...
pcap 文件查看
本地 Windows 电脑下载 wireshark 并安装,从服务器上 scp 下来 pcap 文件,双击打开即可查看。
测试
telnet www.xxxx.com 1883
pcap 文件的数据落地问题
联调的时候,我以为 tcpdump 的数据是实时写入到 pcap 文件的,所以用 tail 命令一直查看文件的变化, 但实际上 tcpdump 是积攒到 4kB 之后才会写入文件,所以数据量小时 tail 一直观察不到变化,只有退出 tcpdump 时才能看到数据写入。否则一直是 0KB。
nginx: [emerg] "stream" directive is not allowed here in /etc/nginx/tcp.d/mqtt.conf:1
这是一个错误的配置示范。如果 steam 直接放在 http block 中,即 sites enabled 下方
include /etc/nginx/sites-enabled/*;
include /etc/nginx/tcp.d/*.conf;
会报错
$ sudo nginx -t
nginx: [emerg] "stream" directive is not allowed here in /etc/nginx/tcp.d/mqtt.conf:1
nginx: configuration file /etc/nginx/nginx.conf test failed
原因是,stream 要与 http block 平级。
参考
- tcpdump 的使用:https://opensource.com/article/18/10/introduction-tcpdump
- nginx 做 tcp 转发:https://blog.51cto.com/moerjinrong/2287680
微信关注我哦 👍
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式