一个让人抓狂的"连不上"现场
去年帮一个做资产追踪的团队排查问题。他们的设备装在物流托盘上,平时休眠,定时醒来广播一包数据,网关收到后回连读一次历史记录。实验室里一切正常,拉到现场跑了三天,发现大概三成的托盘数据永远收不上来。
现场表现很怪:网关日志里能看到这些设备的广播包,信号强度也不差,说明设备在正常发。但发起连接后,要么超时断开,要么连上了立刻掉,反复重试几次后设备就回到休眠,等下一个周期再重复同样的剧本。
他们一开始怀疑是天线、干扰、电源,换了一轮硬件没变化。后来把抓包工具挂上去,对比了"能连上的设备"和"连不上的设备"的广播内容,问题才浮出水面:两类设备的广播包里,有几个跟连接相关的字段不一样,而发起方用的是同一套固定参数去连所有人。
这就是典型的"发起连接参数与广播参数不匹配"。它不报错,不崩溃,只是默默让你一部分设备永远连不上,而且比例还可能随环境变化,非常折磨人。
先搞清楚这两组参数各自是什么
广播参数,是设备在广播包里"自报家门"时携带的信息。除了设备名、服务UUID这些业务字段,还有几个跟"能不能被连、怎么连"直接相关的:
- 是否允许被连接(可连接广播 vs 不可连接广播)
- 广播间隔
- 从设备延迟(slave latency)的期望值
- 连接超时的期望值
- 有些协议栈还会把"期望的连接间隔范围"放进广播数据或扫描响应里
发起连接参数,是主动方(手机、网关、主设备)在发起连接那一刻自己决定的:
- 扫描窗口/扫描间隔(决定它多久能"听到"一次广播)
- 发起连接时的连接间隔
- 连接超时
- 从设备延迟
关键点在于:发起方单方面决定了连接建立后的初始参数,但它未必尊重广播方声明的期望值。两边如果差得太离谱,连接要么建不起来,要么建起来很快断。
坑一:扫描窗口太窄,漏掉了慢广播
最隐蔽的一种不匹配,是发起方的扫描节奏和广播方的广播间隔对不上。
广播是周期性的,设备每隔一个广播间隔发一次。发起方如果只在很短的窗口里开机扫描,就可能连续几次都刚好错过。实验室里设备少、干扰小,偶尔错过还能补上;现场设备一多、广播信道一挤,错过概率急剧上升。
现象特征:不是完全连不上,而是"时好时坏",重试几次能成功,但成功率低得没法接受。很多人会误判成信号问题,其实是时间上的错位。
排查思路很直接:把发起方的扫描窗口/间隔,和广播方的广播间隔都打出来,算一下在一个扫描周期内,理论上能覆盖到几次广播事件。如果覆盖次数小于2,就是设计上的隐患。工程上一般要求扫描窗口至少能覆盖到广播间隔的两到三倍,留出余量。
扫描周期 = 扫描间隔 单周期内可听到广播的次数 ≈ 扫描窗口 / 广播间隔 这个值建议 >= 2,现场环境差时建议 >= 3坑二:连接间隔谈不拢,连上就掉
连接建立后,双方要协商一个连接间隔。发起方给的是一个初始值,广播方(从设备)可以在广播里声明自己期望的范围。如果发起方给的值远小于从设备能承受的最小值,或者远大于它声明的最大值,就会出现:
- 从设备直接拒绝这次连接请求
- 连接建立,但从设备因为来不及响应而频繁丢包
- 连接超时计数器很快溢出,触发断开
现场表现就是前面那个故事里的"连上了立刻掉"。抓包能看到连接建立的过程,然后很快出现断开事件,断开原因码往往指向"连接超时"或"参数不可接受"。
这里有个公开资料很少讲的细节:很多从设备的协议栈在收到不合理的连接参数时,不会礼貌地拒绝,而是先接受再立刻断开。所以你看到的是"连上又掉",而不是"连不上"。这个行为差异会误导排查方向——你会以为是链路不稳定,其实是参数从一开始就不被接受。
判断方法:把发起方的连接间隔、从设备广播里声明的期望范围、以及从设备实际能支持的范围,三个值列出来对比。只要发起方的值落在从设备支持范围之外,基本可以锁定。
坑三:从设备延迟和超时配合不当
从设备延迟(slave latency)允许从设备跳过若干个连接事件不应答,用来省电。它必须和连接超时配合:连接超时 > (1 + 从设备延迟) × 连接间隔 × 系数。如果发起方给的连接超时太短,而从设备又声明了一个较大的延迟,从设备按自己的节奏跳过事件,发起方那边超时计数器先溢出,连接就断了。
这个坑的阴险之处在于:它只在从设备真的进入省电节奏后才暴露。刚连上时从设备可能还积极应答,跑一会儿开始偷懒,连接就断。所以现象是"连上后能撑几秒到几十秒,然后断",而不是立刻断。
现场排查时,重点看断开的时间点是否规律。如果总是维持差不多长的时间后断开,且这个时间和"连接超时"字段对得上,基本就是这个问题。
坑四:可连接标志被忽略
还有一种低级但常见的:广播包里声明的是不可连接广播(比如只广播数据的信标),发起方却硬要去连。这种情况下发起方根本收不到连接响应,扫描器会一直重试直到超时。
现象是"能看到设备,就是连不上,连超时后放弃"。用抓包工具看广播包的类型字段就能确认。这个不算参数"数值"不匹配,而是"能力"不匹配,但现场表现和参数不匹配一模一样,所以放在一起讲。
现场怎么快速定位
给你一套我常用的判断顺序,按这个走基本不会绕弯:
第一步,抓广播包,列出每个设备的:广播类型(可连接/不可连接)、广播间隔、声明的连接参数期望范围。
第二步,抓发起方的配置:扫描窗口/间隔、发起连接时的连接间隔、连接超时、从设备延迟。
第三步,做三组对比:
- 扫描覆盖次数是否够(窗口/间隔 vs 广播间隔)
- 发起连接间隔是否落在从设备声明范围内
- 超时是否满足延迟约束
第四步,如果数值上都对得上还连不上,再怀疑广播类型和能力不匹配。
这里有个经验:不要只测一台设备。参数不匹配的坑,往往是"大部分设备能连,少数连不上",因为不同批次的从设备固件可能声明了不同的期望范围。只测一台很容易漏掉。
权衡:发起方该不该迁就广播方
理论上,发起方应该尊重广播方声明的期望参数。但工程上没那么简单。
发起方如果是手机,操作系统往往不让你随便设连接参数,它有自己的策略,你只能接受。这时候反过来的做法是:让从设备在广播里声明一个足够宽的范围,宽到能包容发起方可能给出的各种值。这是很多量产设备的实际做法——不追求最优省电,追求最大兼容。
发起方如果是自研网关,那就灵活得多。可以在发起连接前先解析广播里的期望参数,动态调整自己的发起参数。代价是逻辑复杂一点,但能显著提升连接成功率。
取舍的核心是:谁更容易改,就让谁去兼容。手机端改不动就设备端放宽,设备端资源紧张就网关端做适配。没有标准答案,取决于你的产品形态。
一个容易被忽略的隐形陷阱
从设备延迟这个字段,有些协议栈在广播里根本不声明,或者声明为0。发起方如果默认按自己的省电策略给一个较大的延迟,而从设备实际不支持,就会出现前面说的超时断开。
更麻烦的是,这个字段的行为在不同协议栈实现里不一致:有的忽略发起方的值、坚持用自己的,有的完全服从发起方。所以同样的参数,换一批从设备模块,表现可能完全不同。
工程上的稳妥做法:发起方给保守值。延迟给0或很小,超时给足够大,连接间隔给一个中间值。先保证能稳定连上,再在连接建立后通过参数更新流程去协商更省电的配置。把"建立连接"和"优化功耗"分成两步,比一次性赌对参数可靠得多。
最后一句实在话
这类问题的恶心之处在于它不给你明确的错误提示。你看到的是"连不上"“连上就掉”“时好时坏”,这些现象和射频问题、电源问题、干扰问题的表现高度重叠,很容易把人带到错误的排查方向上。
养成一个习惯:任何连接类故障,先把两边的参数抓出来对比,再去看射频和硬件。参数对比是几分钟的事,能帮你排除掉一大半的伪硬件问题。