背景:为什么Android 蓝牙通讯数据包默认情况下最多20个字节?参考资料:Core_v4.2.pdf

MTU is not a negotiated value, it is an informational parameter that each device can specify independently. It indicates to the remote device that the local device can receive, in this channel, an MTU larger than the minimum required. All L2CAP implementations shall support a minimum MTU of 48 octets over the ACL- U logical link and 23 octets over the LE-U logical link; however, some protocols and profiles explicitly require support for a larger MTU. The minimum MTU for a channel is the larger of the L2CAP minimum 48 octet MTU and any MTU explicitly required by the protocols and profiles using that channel. (Note: the MTU is only affected by the profile directly using the channel. For example, if a service discovery transaction is initiated by a non service discovery profile, that profile does not affect the MTU of the L2CAP channel used for service discovery).

core spec里面定义了ATT的默认MTU为23个bytes, 除去ATT的opcode一个字节以及ATT的handle 2个字节之后,剩下的20个字节便是留给GATT的

关于自定义MTU

在BluetoothGatt源码中,有可自定义MTU的方法,但是由于国内各个OEM厂商百花齐放,实际在自定义MTU时,效果不一,要么无法设置,要么设置成功不生效,都是坑

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36public final class BluetoothGatt implements BluetoothProfile{

...

/**

* Request an MTU size used for a given connection.

*

*

When performing a write request operation (write without response),

* the data sent is truncated to the MTU size. This function may be used

* to request a larger MTU size to be able to send more data at once.

*

*

A {@link BluetoothGattCallback#onMtuChanged} callback will indicate

* whether this operation was successful.

*

*

Requires {@link android.Manifest.permission#BLUETOOTH} permission.

*

* @return true, if the new MTU value has been requested successfully

*/

public boolean requestMtu(int mtu){

if (DBG) Log.d(TAG, "configureMTU() - device: " + mDevice.getAddress()

+ " mtu: " + mtu);

if (mService == null || mClientIf == 0) return false;

try {

mService.configureMTU(mClientIf, mDevice.getAddress(), mtu);

} catch (RemoteException e) {

Log.e(TAG,"",e);

return false;

}

return true;

}

...

}

分析:

so:蓝牙通讯时,往往有些指令/数据会超过20个字节,此时需要分包处理。

无论怎么分,每包不能大于20个字节

考虑性能问题

考虑业务逻辑问题

示例:分包说白了就是一套通讯协议

假设:一包数据的格式 -> 协议头 + 总包号 + 当前包号 + 命令号 + 内容 + 协议尾

协议

内容

长度(byte)

类型

示例

协议头

s

1

字符

总包号

1

16进制

2

当前包号

1

16进制

1

命令号

2

16进制

T0

内容

14

字符

12345678901234

协议尾

e

1

字符

如果按照上述方式,那么每包数据内实际有效的内容只有14个字节。

现在向蓝牙设备发送一条指令(时区+时间):UTC+8 2019-04-24 16:50:26,

我们把这条指令命名为 T0。

用刚才的定义的协议进行分包:

第一包:s21T0 UTC+8 2019-04e

第二包:s22T0-24 16:50:26e

反之,蓝牙设备向手机发送数据也可以用同一套协议,

现在蓝牙设备向手机通知一条数据(电量|温度|湿度|时间|经度|纬度):95|27.5|49|2019-04-24 16:50:26|123.456789|123.456789,

我们把这条数据命名为 D0。

第一包:s41D095|27.5|49|201e

第一包:s42D09-04-24 16:50:e

第一包:s43D026|123.456789|e

第一包:s44D0123.456789e

手机在处理的时候,需要先判断当前指令的命令号

当然实际业务中通讯协议没有这么简单,可能把数据处理成16进制、2进制,或者通讯数据加密之类的。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐