通过 withoutResponse 发送时 CoreBluetooth 数据包丢失

CoreBluetooth data package lost when sending via withoutResponse

在 iOS 上,一些数据包通过 BLE 丢失。

在一个特征上,我们有 .withoutResponse 类型,我们当然会检查 canSendWriteWithoutResponsefunc peripheralIsReady(toSendWriteWithoutResponse peripheral: CBPeripheral)。 文档中也有说明。

On the other hand, if you specify the write type as CBCharacteristicWriteType.withoutResponse, Core Bluetooth attempts to write the value but doesn't guarantee success. If the write doesn't succeed in this case, you aren't notified and you don't receive an error indicating the cause of the failure.

有人知道我如何在不切换到 withResponse 的情况下解决这个问题吗?

BLE 是一种分布式协议。 总是 可能会丢失数据。确保没有丢失数据的唯一方法是收到一些通知,表明数据已正确接收(通常称为 ACK,表示确认)。实现此目的的标准 BLE 方法是响应。但是如果你不想使用标准的,你可以自由地实现你自己的 ACK 方案。

例如,您可以在中央订阅的外围设备中创建一个“确认”特征。当您发送写入时,您会等到收到来自该特征的通知。如果您在超时后没有看到通知,则写入可能已丢失。这个 re-implements 更高层的标准 write-with-response 系统。

我使用的几个 BLE 协议实际上是串行协议(我们写入一个特征,并从相同的特征读取响应)。我们经常将 ACK 直接实现到串行协议中(例如,返回 <msgid>OK),而不需要 BLE write-response.

另一种解决方案是写入特征,然后从特征中读取以查看它是否已更新,前提是特征以这种方式对称(很多不是)。我相当确定这里没有 write-caching 会咬你,因为 BLE 读写通常不对称,但你应该 double-check 在依赖它之前。 (请参阅 2019 年和 2017 年的核心蓝牙 WWDC 视频。)

与所有分布式系统一样,也永远不可能知道数据丢失了。有可能数据已经到达,而响应丢失了。这是分布式协议的本质,只需将其纳入系统即可。这就是为什么可以构建一个 至少 一次传递消息的系统(前提是传递是可能的),或者构建一个 传递消息的系统most 一次,但不可能构建一个将消息 exactly 一次传递的系统。

如果您无法控制外围设备,并且它不提供任何错误检测机制,那么在中央 (phone) 端您将无能为力。您必须与双方合作才能构建 fault-tolerant 分布式协议。