1

我编写了一个应用程序,它在 Linux 上以非阻塞模式使用蓝牙 LE L2CAP 连接来读取/写入 ATT 数据包(使用socket(PF_BLUETOOTH, SOCK_SEQPACKET|SOCK_CLOEXEC, BTPROTO_L2CAP))。通常,当设备关闭或超出范围时,read()给出 errno=ETIMEDOUT。

但是,read()当蓝牙 LE 设备似乎仍在工作时,给出的 errno=ETIMEDOUT 比它应该更频繁。超时的原因是什么?超时是否可配置?

我的 Linux 配置是 3.13.0-24-generic;蓝牙核心版本 2.17。

4

1 回答 1

6

已建立的 LE L2CAP 套接字上的 ETIMEDOUT 错误实际上来自蓝牙适配器在几个连续丢失的数据包之后。多少取决于连接参数。一旦 master 发起与 slave 的连接,master 每隔一个Connection Interval (7.5ms–4s) 就会对 slave 进行 ping 操作,slave 如果听到 ping 就会做出响应。如果任一设备在监督超时(100ms–32s)后未能收到另一台设备的回复,它将关闭连接。第三个参数,从属延迟(0-499),允许从属通过不响应某些 ping 来节省电池电量。另请参阅什么是连接参数?

操作系统在启动连接时会设置默认连接参数。从设备可能会推荐一组更合适的连接参数来平衡电池寿命、延迟和对障碍物/干扰的恢复能力,并且操作系统有机会批准这些参数(有关Apple操作系统的连接参数范围,请参阅Apple 的蓝牙设计指南会接受)。但是,如果从站不建议一组新的参数,那么它将受操作系统默认值的支配,从一个操作系统到另一个操作系统的默认值差别很大!

在查看 Wireshark 中的 hcidump btsnoop 文件时,我的特定设备(蓝牙笔)似乎从不建议不同的间隔和超时。因此,其可靠性将取决于操作系统的默认设置。

以下是通过实验确定的默认间隔和超时。

带有内部蓝牙适配器的 Linux 3.13(当前在 hci_core.c 中定义):
操作系统允许的间隔:50–70ms
蓝牙适配器选择的连接间隔:67.5ms
监督超时:420ms(断开连接前丢失6 个数据包)

装有 iOS 7 的 iPhone 4S:
操作系统允许的间隔:未知
蓝牙适配器选择的连接间隔:30 毫秒
从属延迟:0 个数据包
监督超时:720 毫秒(断开连接前丢失23 个数据包)

Nexus 4 上的 Android 5.0.1 Lollipop
操作系统允许的间隔:30–50
毫秒 蓝牙适配器选择的连接间隔:48.75 毫秒
从属延迟:0 个数据包
监督超时:2000 毫秒(断开连接前41 个丢失数据包)

带有外部适配器的 OSX 10.10.1(Apple 蓝牙软件版本:4.3.1f2 15015):
操作系统允许的间隔:未知
蓝牙适配器选择的连接间隔:15 毫秒
从属延迟:0 个数据包
监督超时:2000 毫秒(断开前丢失133个数据包)

这就解释了为什么我与 Livescribe 笔的连接在 Linux 上显得不那么可靠。内核默认是在丢失 6 个数据包后断开连接,并且笔从不推荐更好的参数。

在 Linux 3.17 及更高版本上,可以通过写入 /sys/kernel/debug/bluetooth/hci0/supervision_timeout 来调整监督超时。

测试方法:Linux 上的跟踪是使用 hcidump(在 Android 的开发人员选项中)获得的,并在 Wireshark 中针对 HCI LE 创建连接命令进行了分析。OSX 和 iPhone 的迹线是使用 TI CC2540 和 TI 的数据包嗅探器软件获得的。

于 2015-02-07T22:56:30.130 回答