【背景】
Android中,用蓝牙发送数据,结果出现,超过990的字节的大批量的数据,就会被截断。
【解决过程】
1.google去搜:
Bluetooth 990 bytes
找到:
有人遇到,但是无解:
streaming – What is the Maximum packat size to send data over bluetooth in Android? – Stack Overflow
2.android – RFCOMM receiving data with 1 L2CAP packet missing – Stack Overflow
提到了“My android mobile bluetooth supporting maximum RFCOMM payload is 990 bytes”
不过好像其遇到的问题不一样:
发送了1K=2014=990+34,结果990丢失了,而不是截断的事情了。
3.Bluetooth data being split on Android device – Stack Overflow
说是:
RFCOMM中,就像串口,是没有Package包的概念的,只有字节流;
然后有时候多个小的数据包,又会被放在一起传输->一次性接收到的,是多个小的数据包。
而分段的大小,即一次性最大传输多少个,此处的990,是取决于每个蓝牙芯片内部的参数设置的。
->感觉说的也不一定对。。。
4.java – Android – Pass object via bluetooth – Stack Overflow
也有人遇到类似问题。
5.看到:
Setting up Bluetooth — Clay and Galileo
Intel® Galileo Boards and Kits — Bluetooth Setup
中关于蓝牙配置时,有个:
# hciconfig hci0: Type: BR/EDRBus: USB BD Address: B4:B6:76:8D:AB:07ACL MTU: 310:10SCO MTU: 64:8 UP RUNNING RX bytes:990 acl:0 sco:0 events:44 errors:0 TX bytes:738 acl:0 sco:0 commands:44 errors:0
其中的
RX bytes:990
感觉像是说:
一次性最多接受990个字节
如果是的话,那么:
TX bytes:738
或许就意味着:
一次性最多发送738个字节
6.再去搜:
Bluetooth RFCOMM max payload
找到:
List of Bluetooth protocols – Wikipedia, the free encyclopedia
都提到了:
L2CAP’s functions include:
- Multiplexing data between different higher layer protocols.
- Segmentation and reassembly of packets.
- Providing one-way transmission management of multicast data to a group of other Bluetooth devices.
- Quality of service (QoS) management for higher layer protocols.
L2CAP is used to communicate over the host ACL link. Its connection is established after the ACL link has been set up.
In basic mode, L2CAP provides packets with a payload configurable up to 64 kB, with 672 bytes as the default MTU, and 48 bytes as the minimum mandatory supported MTU.
”
根据:
Segmentation and reassembly of packets
感觉应该是L2CAP层负责数据包的,分段,拆分,和合并的。
7.根据:
http://authors.phptr.com/bluetooth/bray/pdf/cr_ch10.pdf
的
“10.5.4 Data
The data field is only present in UIH frames. There must be an integral number of bytes in the data up to 32767. The size limit is set by the Maximum Transmission Unit (MTU) on
L2CAP packets, so if a system has a smaller L2CAP MTU, the size of RFCOMM data will also be restricted.”
好像是:
RFCOMM中最大的payload是32767字节(而不是上面说的64KB=65536)
另外也在:
SPP Maximum Payload – Bluetooth® CC256x Forum – Wireless Connectivity – TI E2E Community
中看到RFCOMM协议的细节构成:
+----------+----------+--------------------+----------+--------------------+---------+ | Address | Control | Length Indicator | Credits | Data/Information | FCS | +----------+----------+--------------------+----------+--------------------+---------+ 1 Octet 1 Octet 1 or 2 Octets 1 Octet 1 Octet
%l2control -a 00:02:72:00:d4:1a read_channel_list L2CAP channels: Remote BD_ADDR SCID/ DCID PSM IMTU/ OMTU State 00:07:e0:00:0b:ca 66/ 64 3 132/ 672 OPEN
好像是:
IMTU==Input MTU 是132字节?
OMTU==Output MTU 是672字节?
9.根据:
Higher Layer Losses | How Fast is Bluetooth? | InformIT
“For example, if we assume that a regular stream of 20-byte packets is sent via RFCOMM, L2CAP, and HCI, this is what will happen:
RFCOMM adds a byte of address information, a byte of control information, a byte of length indicator information, and a byte of Frame Check Sequence (FCS) information. With these extra 4 bytes, L2CAP receives a 24-byte packet. RFCOMM escapes some characters, so the data rate could be even worse, depending on the data patterns sent.
L2CAP adds 2 bytes of length information and 2 bytes of channel ID onto the packet. So, having received 24 bytes from RFCOMM, L2CAP passes 28 bytes on to HCI.”
应该是:
HCI
== 4字节(2字节长度+2字节channel ID) + L2CAP
== 4字节(2字节长度+2字节channel ID) +(4字节(1字节地址信息+1字节控制信息+1字节长度指示信息+1字节FCS) + RFCOMM)
简单说就是:
HCI
= L2CAP + 4字节
=(RCFOMM+4字节)+ 4字节
10.
参考:
先明白蓝牙协议的层次关系:
RFCOMM
L2CAP
HCI
11.SPP Maximum Payload – Bluetooth® CC256x Forum – Wireless Connectivity – TI E2E Community
说是:
L2CAP的MTU最大是128字节
当配置L2CAP通道的时候,就会通知双方的MTU是多少。
MTU表示的含义是,可以通过L2CAP通道去接收的最大的SDU(Service Data Unit)的字节数是多少
BlueMSP430 EtherMind SPP SDK用的RFCOMM的MTU是128字节
意味着:
针对此RFCOMM协议,其底层的L2CAP中Payload是128字节
换句话说:
此处的128不包含L2CAP的头信息
->L2CAP
==payload+header/tail
=128+4
而用到了RFCOMM的协议(比如SPP),其中最大的数据包packet长度,是由
在建立RFCOMM连接的参数协商Parameter Negotiation阶段
去确定的帧大小Frame Size决定的。
L2CAP MTU的值是不对称的:
两个方向可以是不一样的:发送和接收的MTU可以不一样
而帧大小是统一的
当计算帧大小时,两个方向,发送和接收,的L2CAP MTU的最小值则要考虑进去
比如:
BlueMSP430 SPP SDK 连接到PC(比如默认用的是微软的蓝牙协议栈)
往往MTU都是大于128字节的->因为PC端有足够的资源和内存,可以处理更大批量的数据包
所以此时BlueMSP430 SPP的最小MTU是128字节
去掉6字节的头尾,还剩128-6=122字节
12.后来去折腾,寻找其他hciconfig的用法时,也看到其他地方的hciconfig输出中RX的值是其他的值,比如:
Android blueZ HCI(一):hciconfig实现及常用方法 – CLK – 博客频道 – CSDN.NET
(1)
RX是3944
TX是2311
(2)
root@android:/ # hciconfig -a hciconfig -a hci0: Type: BR/EDR Bus: UART//蓝牙的接口类型,这个是UART的,还有USB、PCI………… BD Address: 00:16:53:96:22:53 ACL MTU: 1021:8 SCO MTU: 120:10//蓝牙地址 UP RUNNING PSCAN//命令状态 RX bytes:2846 acl:0 sco:0 events:67 errors:0 TX bytes:2034 acl:0 sco:0 commands:80 errors:0 Features: 0xff 0xff 0x8d 0xfe 0x9b 0xbf 0x79 0x83 Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3//支持数据包 Link policy: RSWITCH HOLD SNIFF PARK Link mode: SLAVE ACCEPT//连接的类型,是主设备、从设备 Name: 'sp8825c1'//蓝牙名称 Class: 0x5a020c//蓝牙的类型 Service Classes: Networking, Capturing, Object Transfer, Telephony//支持的类型 Device Class: Phone, Smart phone HCI Version: 2.1 (0x4) Revision: 0x1250//HCI版本 LMP Version: 2.1 (0x4) Subversion: 0x1250//LMP版本 Manufacturer: Ericsson Technology Licensing (0)//作者
RX是2846
TX是2034
(3)
linux下使用蓝牙设备 bluetooth hciconfig hcitool
RX是1459
TX是764
(4)
hci0: Type: BR/EDR Bus: USB BD Address: E4:D5:3D:F2:7B:66 ACL MTU: 1021:8 SCO MTU: 64:1 UP RUNNING PSCAN RX bytes:1105 acl:0 sco:0 events:38 errors:0 TX bytes:2088 acl:0 sco:0 commands:38 errors:0
RX是1105
TX是2088
(5)
Resources/HowTo/SamsungBTInOrigen – Linaro Wiki
root@linaro-alip:~# hciconfig -a hci0: Type: BR/EDR Bus: UART BD Address: A0:0B:BA:FF:FF:FF ACL MTU: 310:10 SCO MTU: 64:8 UP RUNNING PSCAN RX bytes:1306 acl:0 sco:0 events:31 errors:0 TX bytes:1118 acl:0 sco:0 commands:30 errors:0 Features: 0xff 0xff 0x8f 0xfe 0x9b 0xff 0x59 0x87 Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3 Link policy: RSWITCH HOLD SNIFF PARK Link mode: SLAVE ACCEPT Name: 'linaro-alip-0' Class: 0x4a0100 Service Classes: Networking, Capturing, Telephony Device Class: Computer, Uncategorized HCI Version: 3.0 (0x5) Revision: 0x1aa1 LMP Version: 3.0 (0x5) Subversion: 0x1aa1 Manufacturer: Cambridge Silicon Radio (10)
RX是1306
TX是1118
13.然后问题转化为:
关于Android端的(和PC端,后期再说)蓝牙的MTU值,或者说payload值的,具体是多少
去google搜:
android bluetooth MTU
参考:
Bluetooth MTU – stevenliyong 的专栏 – 博客频道 – CSDN.NET
应该说是:
Android端,蓝牙的MTU的值,一般来说,默认估计也是672之类的值
而PC端,MTU值一般很大(因为内存足够用)比如Ubuntu,常见的是990
而MTU的值的大小,影响了实际的蓝牙传输速度,MTU越高,速度越快,但是同时对于内存占用相对越多些。
比如那人的例子:
PC端:
开发板(等价于Android手机)端:
MTU==672->20KB(1MB/50s)
MTU==60000->蓝牙速度:75KB(1MB/13s)
注:
手机端的蓝牙的L2CAP底层的内存占用就高了些(具体多少,暂未知)。
14.不过另外这里:
external-bluetooth-bluedroid/gatt_api.h at master · tieto/external-bluetooth-bluedroid · GitHub
关于bluedroid中的GATT,也有个MTU
/* MAX GATT MTU size */ #ifndef GATT_MAX_MTU_SIZE #define GATT_MAX_MTU_SIZE 517 #endif
15.这里:
bluetooth lowenergy – Android BLE MTU size, has anyone sniffed it? – Stack Overflow
提到了:
client和server可以通过:
Exchange MTU Request and Response PDUs
去改变默认的MTU值,然后之后的通讯就以两者最小的MTU为基准,进行通信。
【总结】
首先,从蓝牙的协议关系来说是:
HCI=L2CAP+4字节=RFCOMM+4字节+4字节=RFCOMM+8字节
简写为:
HCI=L2CAP+4=RFCOMM+8
而我们常用的协议本身内部传输的有效数据叫做payload,好像有的地方也叫MTU(Maximum Transmission Unit),然后有的地方也被叫做frame帧:
不过,一般来说,其关系是:
MTU=Frame=Header/Tail + Payload
如图:
协议 | Payload或MTU范围 | Payload或MTU默认值 |
RFCOMM | 0-32KB | 默认为672字节 其他的比如接收RX990/发送TX738 |
L2CAP | 0-64KB | |
HCI | 310/10 |
不过其实还是没有研究的透彻,有空再说。
转载请注明:在路上 » 【基本解决】蓝牙数据传输数据单次超过990字节时被截断分段多次传输