我编写了一个应用程序,它在Linux上以非阻塞模式使用蓝牙LE L2CAP连接来读取/写入ATT数据包(使用socket(PF_BLUETOOTH, SOCK_SEQPACKET|SOCK_CLOEXEC, BTPROTO_L2CAP)
)。通常,当设备关闭或超出范围时,read()
会给出errno = ETIMEDOUT。
然而,当蓝牙LE设备似乎仍在工作时,read()
给出的errno = ETIMEDOUT比应该更频繁。超时的原因是什么?超时是否可配置?
我的Linux配置是3.13.0-24-generic;蓝牙核心版本2.17。
答案 0 :(得分:3)
已建立的LE L2CAP套接字上的ETIMEDOUT错误实际上是在连续几次丢失数据包之后来自蓝牙适配器。多少取决于连接参数。一旦主设备启动与从设备的连接,主设备每连接间隔(7.5ms-4s)对从设备进行ping操作,如果设备听到ping,则从设备将响应。如果任何一个设备在监控超时(100ms-32s)后无法从其他设备收到回叫,它将关闭连接。第三个参数 Slave Latency (0-499)允许从站通过不响应某些ping来节省电池电量。另请参阅What are connection parameters?
操作系统在启动连接时设置默认连接参数。从机可能会推荐一组更合适的连接参数,以平衡电池寿命,延迟和对障碍物/干扰的弹性,操作系统有机会批准这些参数(请参阅Apple’s Bluetooth Design Guidelines了解Apple的连接参数范围操作系统将接受)。但是如果奴隶没有建议一套新的参数,那么它就受操作系统默认值的支配,这些默认值在操作系统之间变化很大!
在查看Wireshark中的hcidump btsnoop文件时,我的特定设备(蓝牙笔)似乎从未建议不同的间隔和超时。因此,其可靠性将取决于操作系统默认值。
以下是实验确定的默认间隔和超时。
带有内部蓝牙适配器(currently defined in hci_core.c)的Linux 3.13:
OS允许的间隔:50-70ms
蓝牙适配器选择的连接间隔:67.5ms
监督超时:420ms(断开前 6 丢失数据包)
iOS 4的iPhone 4S:
操作系统允许的间隔时间:未知
蓝牙适配器选择的连接间隔:30ms
从机延迟:0个包
监督超时:720ms(断开前 23 丢失数据包)
Android 5.0.1 Lollipop on Nexus 4
OS允许的间隔:30-50ms
蓝牙适配器选择的连接间隔:48.75ms
从机延迟:0个包
监督超时:2000ms(断开前 41 丢失数据包)
这解释了为什么我在Livescribe笔上的连接在Linux上看起来不太可靠。内核默认是在仅丢失6个数据包后丢弃连接,并且笔从不推荐更好的参数。
在Linux 3.17及更高版本上,可以通过写入/ sys / kernel / debug / bluetooth / hci0 / supervision_timeout来调整监督超时。
测试方法:Linux上的痕迹是使用hcidump(在Android中的开发者选项中)获得的,并在Wireshark中分析了HCI LE创建连接命令。 OSX和iPhone的迹线是使用带有TI数据包嗅探软件的TI CC2540获得的。