2. MTU协商失败:MTU交换流程、常见失败原因与抓包分析方法
MTU协商,说白了就是蓝牙两端商量一个“最大数据包尺寸”。你发一个100字节的数据,对方说“我只能收50”,那你就得拆包。这个协商过程如果失败,后续的数据传输基本就废了。我在项目中遇到过好几次,联调时发现数据传不过去,最后定位都是MTU协商出了问题。
2.1 MTU交换的标准流程
MTU交换发生在GATT连接建立之后,由GATT Client发起。流程其实很简单,就两步:
- Client发送MTU Request:告诉Server“我能收的最大包是X字节”
- Server回复MTU Response:告诉Client“我能收的最大包是Y字节”
协商结果取两者中的较小值。举个例子,Client发来512,Server回复256,那最终MTU就是256。
关键点:MTU协商不是必须的。如果Client不发MTU Request,双方默认使用23字节的MTU。但23字节对于实际应用来说太小了,传个传感器数据都得拆好几包。
我个人习惯在连接建立后立即发起MTU协商,不要等。有些芯片的协议栈有bug,连接后等太久再发MTU Request,Server可能就不响应了。
2.2 常见失败原因分析
MTU协商失败,我归纳下来主要有三类原因。嗯,咱们一个一个说。
2.2.1 协议栈限制
这是最常见的问题。很多低功耗蓝牙芯片的协议栈对MTU有硬性限制。比如:
| 芯片/协议栈 | 最大MTU限制 | 备注 |
|---|---|---|
| 某国产芯片A | 128 | 超过128直接不响应 |
| 某国际大厂B | 247 | 默认配置,可修改 |
| 某低功耗方案C | 64 | 硬件限制,无法修改 |
我曾经在一个项目里,Client端请求MTU为512,Server端芯片的协议栈最大只支持128。结果Server直接忽略了MTU Request,没有回复任何Response。Client等超时后,以为连接断了,直接断连。查了两天才找到原因。
避坑指南:联调前,双方先确认各自协议栈支持的MTU范围。不要想当然地认为“蓝牙规范支持512,我的芯片就一定支持”。
2.2.2 对端不支持MTU交换
有些老旧的蓝牙设备,或者一些简化实现的从机,根本就不支持MTU交换。它们收到MTU Request后,要么不回复,要么回复一个错误码。
怎么判断?抓包看。如果Client发了MTU Request,Server回复了一个Error Response,错误码是0x04(Not Supported),那就是对端不支持。
我的建议:如果对端不支持MTU交换,那就只能用默认的23字节MTU。这时候你的应用层要做好分包和重组。别想着硬上,没用的。
2.2.3 时序问题
这个比较隐蔽。有些协议栈在连接刚建立时,还在处理内部状态机。如果你在连接建立后立即发送MTU Request,可能被协议栈丢弃。
我记得有一次,Client在连接建立后5ms就发了MTU Request,Server端芯片的协议栈还没准备好,直接忽略了。后来我们在Client端加了一个200ms的延时,问题就解决了。
2.3 抓包分析方法
MTU协商失败,抓包是最直接的定位手段。我一般用Ellisys或者TI的Packet Sniffer。下面说说怎么看。
2.3.1 抓包关键字段
在抓包工具里,找到ATT层的包。MTU交换相关的包有两个:
- MTU Request:Opcode为
0x02,后面跟着Client Rx MTU值 - MTU Response:Opcode为
0x03,后面跟着Server Rx MTU值
如果只看到Request,没看到Response,那就是Server没回复。如果看到Response,但值不对,那就是协商结果不是你期望的。
2.3.2 典型失败抓包示例
我画了一张流程图,帮你理解抓包时看到的场景:
2.3.3 抓包分析步骤
拿到抓包文件后,我一般按这个顺序排查:
- 过滤ATT层:只看ATT协议相关的包,过滤掉LL层和L2CAP层的控制包
- 找MTU Request:看Client有没有发。如果没发,那就是Client端代码没调用MTU交换接口
- 找MTU Response:如果Request发了,看Server有没有回。没回的话,大概率是Server协议栈不支持或者有bug
- 看协商值:如果Response回了,看Server Rx MTU的值。如果远小于预期,可能是Server端配置问题
- 检查时序:看Request和Response之间的时间差。如果Response在30秒后才回,那可能是Server处理太慢
一个小技巧:抓包时,把Client和Server的log也一起打开。有时候抓包看不出来的问题,log里会有明确的错误码。比如“MTU exchange not supported”这种log,一看就明白了。
2.4 总结一下
MTU协商失败,说白了就是两端没谈拢。要么是对方不支持,要么是协议栈有限制,要么是时机不对。抓包是最直接的定位手段,配合log一起看,基本能快速定位问题。
嗯,这一节就到这里。记住,联调前先确认双方支持的MTU范围,能省掉很多不必要的排查时间。