
手机发送一次动作设备开始执行结果还没回到手机连接断了。按钮恢复可点用户再点一下。第二次点击究竟是在查询上次结果还是在创建一个新动作如果协议没有区分界面里的“重试”就可能变成设备上的“再执行一次”。下面用虚构的移动指令讨论这个问题实际动作测试应在仿真或无负载环境中进行。图超维方程技术团队绘制。BLE 链路确认与业务动作完成需要分开处理。写响应不是执行结果Bluetooth ATT 定义了写请求和写响应也定义了没有对应写响应的写命令。但设备把某个属性值解释为“移动一次”以后动作多久完成、怎样报告失败是应用协议要补充的内容。手机收到写响应只能按协议解释这个响应不能直接把执行机构显示为“已到位”。反过来手机没收到业务结果也不能证明动作没有发生。这里真正需要区分的是请求是否被接受、动作是否开始、动作是否完成、手机是否已经获知结果。四者可能在不同时间成立。一次动作一个编号重试沿用旧编号下面是一个说明性的业务消息不是 Bluetooth 标准数据格式{controller:demo-controller-A,request_id:demo-move-017,operation:move_relative,arguments:{axis:x,steps:1}}同一次动作因通信失败重发时保持request_id不变。只有用户确实要求另一轮动作才生成新编号。控制端重新连接不应自动把所有未确认请求变成新请求。设备侧用控制端作用域与请求编号定位记录再比较规范化后的业务参数。同一个编号配上不同参数应返回冲突而不是覆盖旧记录。参数摘要可辅助比较但不能替代原始业务校验和访问授权。设备已有的记录收到同一请求后的处理没有记录校验参数、权限和当前状态再决定是否接受已接受或执行中返回现有进度不再次启动动作已完成返回保存的结果注明这是上次动作的结果参数不同拒绝冲突不擅自解释成新动作记录已过期且无法核实返回结果不确定要求重新核对设备状态“查询不到”不是“从未执行过”。记录可能已过期也可能在掉电时丢失。设备没有证据时应把不确定性传给上层。两个重复请求同时到达怎么办如果程序先查询编号、再启动动作、最后写记录两条并发请求可能同时查到“没有”然后都执行。单线程主循环或任务队列也不能凭名称就保证没有这种交错需要查看实际执行路径。常见做法是将“占用编号并记录已接受”放到受控的原子边界内后续重复请求只读取同一条记录。这个边界怎样实现取决于设备运行环境可能是串行处理、临界区或具有一致性保证的存储操作。不要把一段内存字典伪代码当成跨任务、跨掉电都可靠的实现。资源也有限。去重记录应有容量、保留时间和清理规则。清理后收到迟到请求协议要能回答“记录已不在保留窗口”而不是默默执行一次。掉电会留下最难解释的窗口考虑这样的顺序接受记录已经写入动作完成完成结果还没落盘就断电。重启后只看到“执行中”该不该再做一次对不可逆动作简单重做并不安全。可能需要读取位置或状态传感器、人工核对或者让动作本身具有可恢复的检查点。软件日志与物理世界不天然构成一个事务因此仅加一个请求编号不能宣称实现了跨掉电的“恰好一次”。能表达目标状态的业务可以优先考虑目标式命令例如“亮度设为 40%”而不是“增加 10%”。但这只改善业务语义不会自动解决所有副作用、授权和硬件恢复问题。把失败窗口写成测试步骤比正常收发更有价值的是下面几组测试所有次数统计都要看实际动作不能只数手机上的成功日志动作接受后断连再用原编号重发确认没有多启动一次。动作完成后丢弃结果再查询和重发确认返回原结果。同编号改参数确认设备拒绝冲突。两个相同请求并发到达检查接受路径是否只建立一个执行实例。在接受记录、实际动作和结果保存的交界处安排受控故障检查重启后的核对方式。记录过期后重发旧请求确认系统不会把“不知道”显示成“从未执行”。最后检查手机文案。超时后先显示“结果尚未确认正在查询设备”比立即恢复一个含义不清的重试按钮更符合真实状态。参考资料Bluetooth Core SpecificationAttribute Protocol。本文的编号、状态和去重表是应用层设计建议不是 ATT 自动提供的保证。作者超维方程技术团队。