ios 是否有蓝牙mtu设置方法 ios asihttprequesttmtu

博客访问: 2042607
博文数量: 409
博客积分: 10227
博客等级: 上将
技术积分: 8561
注册时间:
认证徽章:
非淡泊无以明志,非宁静无以致远
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: Android平台
1. 问题引言:
想在gatt client上(一般是手机上)传输长一点的数据给gatt server(一般是一个Bluetooth smart设备,即只有BLE功能的设备),但通过
writeCharacteristic(BluetoothGattCharacteristic)&
来写的时候发现最多只能写入20个byte的数据。
这篇文章会回答下面几个问题:
1)为什么会是20?
2)如何突破20?
3)如何更优雅的来实现?
2. 为什么为限制成20个字节?
core spec里面定义了ATT的默认MTU为23个bytes, 除去ATT的opcode一个字节以及ATT的handle 2个字节之后,剩下的20个字节便是留给GATT的了。
考虑到有些Bluetooth
smart设备功能弱小,不敢太奢侈的使用内存空间,因此core spec规定每一个设备都必须支持MTU为23。
在两个设备连接初期,大家都像新交的朋友一样,不知对方底细,因此严格的按照套路来走,即最多一次发20个字节,是最保险的。
由于ATT的最大长度为512byte,
因此一般认为MTU的最大长度为512个byte就够了,再大也没什么意义,你不可能发一个超过512的ATT的数据。
所以ATT的MTU的最大长度可视为512个bytes。
3. 如何突破20?
很简单嘛,改变传输的ATT的MTU就行了,大家经过友好的协商,得到双方都想要的结果,是最好的。在Android上(API 21),改变ATT MTU的接口为:
public boolean requestMtu (int mtu)& &&
Added in API level 21&
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
onMtuChanged(BluetoothGatt, int, int) callback will indicate whether this operation
was successful.&
& Requires
BLUETOOTH permission.&
true, if the new MTU value has been
requested successfully&
大声的说出来你想要一下子传多少,调用上面的接口就可以了,然后在下面的函数中看最终结果(当然了,如果你的peripheral申请改变MTU并且成功的话,那这个回调也会被调用):
@Override&
public void onMtuChanged(BluetoothGatt gatt,
int mtu, int status) {&
super.onMtuChanged(gatt, mtu, status);&
(status == BluetoothGatt.GATT_SUCCESS) {&
this.supportedMTU =//local var to record MTU size&
之后你就可以快乐的发送supported& MTU-3的长度的数据了。
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
4. 如何优雅的来实现?
万一对方设备不同意你的请求怎么办?
对于app来说,一般是知道自己要最大发送多少数据的,例如一次要发100个bytes,那么就首先试试申请一下103,失败的话,则申请一下53,即二分法,剩下的只能自己分段拆着发了。
一般来讲,app的开发者和对端设备的开发者都是同一伙儿人,这是好事,他们可以根据自己设备的硬件情况,来商量MTU应该是多少。
阅读(24) | 评论(0) | 转发(0) |
下一篇:没有了
相关热门文章
给主人留下些什么吧!~~
请登录后评论。IOS BLE4.0蓝牙和外设连接和收发数据的流程
苹果在IOS 6系统之后开始支持BLE 4.0,iPhone4s,iPod 5,iPad 3等之后的机型开始内嵌BLE4.0硬件,因此在开发前请先确认你的开发环境符合上述要求,并且苹果在BLE4.0之后,对外部的连接设备已经不在需要MFI认证了,当然你的外设肯定得要有蓝牙4.0模块了
开发BLE4.0的App,你需要在你的项目里面导入框架:
CoreBluetooth.framework
在需要使用到蓝牙的文件里面你需要导入头文件:
#import &CoreBluetooth/CoreBluetooth.h&#import&CoreBluetooth/CBService.h&
并且你需要在你的蓝牙类里面实现两个协议,CBCentralManagerDelegate ,CBPeripheralDelegate
现在我们需要有两个实例对象CBCentralManager和CBPeripheral,第一个是蓝牙中心管理器,主要用来搜索外设,连接外设以及处理外设断开的情况;第二个主要用于在蓝牙中心管理器成功连接外设之后的一系列动作,如:读取外设的服务号CBService,特征值号CBCharacteristic以及对这些特征值号进行读写操作等,下面我们来看一下IOS这边和外设联机的一个大概流程:
1):IOS这边蓝牙中心管理器开始扫描广播包(扫描的时长可以自己写一个定时器控制,并且可以设定扫描的具体条件)
2):外设开始广播(当然外设的广播时长也是可以设定的,这是硬件那边的事了,我不太懂)
3):IOS发现有广播包,就请求连接外设(这是底层自动实现,我们不需要写代码),之后外设会接收到连接请求,如果外设接收这个连接请求,就会给IOS那边发送一个连接请求的确认包,当IOS这边收到这个包后,两边设备就完成了连接(当然,由于连接底层已经写好,比较复杂,我讲的比较肤浅,只是一个大概步骤而已)
4):连接成功之后IOS这边就可以读取外设的相关信息了,比如服务号CBService,特征值号CBCharacteristic,还有外设的一些硬件信息,电池电量,信号强度RSSI什么的
5):当然在正常连接的过程中总会出现点意外,如果两个设备突然断掉了连接,一般我们还是希望它们能够再次连接的,这里就得要看硬件和IOS程序里对于短线的处理代码了
6):当然,外设和IOS端也可以主动发起断开连接的请求
下面我们看看IOS端具体的代码流程和基本的含义,你只需要跟着我的顺序走就可以了,以下顺序符合IOS BLE4.0联机的流程:
&在你的蓝牙类的初始化里面,先实例化一下中心设备管理器
_centralMan=[[CBCentralManageralloc]initWithDelegate:selfqueue:nil];
代码很简单吧,只需要一行就可以了,主要是要设置委托的对象,至于是否要加入某个队列,就看你的需求了,还记得我们蓝牙类里面继承了CBCentralManagerDelegate ,CBPeripheralDelegate两个协议吧,你可以跟进去看一下里面的协议方法,我就不多说了,先讲第一个需要实现的协议方法
-&& (void)centralManagerDidUpdateState:(CBCentralManager *)central
这个方法主要是来检查IOS设备的蓝牙硬件的状态的,比如说你的设备不支持蓝牙4.0,或者说你的设备的蓝牙没有开启,没有被授权什么的,一般是在你确定了你的IOS设备的蓝牙处于打开的情况下,你才应该执行扫描的动作,我记得我之前没有检查蓝牙的状态就直接扫描了,虽然项目可以运行,但是控制台给出了一大堆的警告什么的,看着很烦人,那么我们执行扫描的动作之后,[_centralManscanForPeripheralsWithServices:Niloptions:Nil];如果扫描到外设了,就会自动回调下面的协议方法了
-&& (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
这个方法里面的信息量可是比较大啊,看那个CBPeripheral,你在这个方法里面你就已经可以获取它的名称了可以使用peripheral.name来获取名称,当然,这里还可以获取设备的一个广播名称 NSString *CBName=[advertisementData valueForKeyPath:CBAdvertisementDataLocalNameKey]; 这两个名称一般是不一样的,除非你们硬件那边把人家写一样了,当然还有其他的很多信息,具体看代码吧;在这个回调里我们可以获取外设的广播包信息,当然我们就可以根据广播包的信息符合不符合你们的自定义的协议,符合就可以发起连接请求了,这样可以避免连接上其它一些自己不希望连接上的外设;当然你应该也看到了这里还有一个RSSI的值,这里是广播包附带过来的,根据这个值我们可以大概估计出广播设备里我们IOS设备有多远,如果信号太弱距离过远,我们是不是就不考虑连接这个外设了;这里我们假设广播包数据符合条件,我们发起了连接请求[_centralManconnectPeripheral:_peripheraloptions:Nil];那么如果连接成功,就会回调下面的协议方法了:
-&& (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
如果你能回调到上面这个方法,说明你已经成功连接外设了,具体你可以打个断点试试,既然连接已经成功,我们就该考虑是不是要停止中心管理设备的扫描动作了,要不然在你和已经连接好的外设进行数据沟通时,如果又有一个外设进行广播且符合你的连接条件,那么你的IOS设备就会也去连接这个设备(因为IOS BLE4.0是支持一对多连接的),导致数据的混乱。所以我们在这个方法里面停止扫描动作:[_centralManstopScan];& 现在是时候让我们的第二个实例对像出场了& CBPeripheral,这里需要注意的是,记得要设置CBPeripheral的委托对象 _peripheral.delegate =self;为了以后使用方便,我们还是一次性读出外设的所有服务UUID:[_peripheraldiscoverServices:nil];这样一旦我们读取到外设的相关服务UUID就会回调下面的方法:
-&& (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
接着在这个方法里面我们还可以接着往里面剥,读取某个CBService&里面的特征值UUID:[peripheraldiscoverCharacteristics:nilforService:s];同上,如果我们成功读物某个特征值UUID,就会回调下面的方法:
-&& (void)peripheral:(CBPeripheral *)peripheraldidDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
能进入到这个方法,说明你已经读取到某个特征值UUID了,到达这一步,我们基本上也完成对外设的层层剥离了,接下来就是一些对某个特征值的读写操作了,当然我们首先要找到我们需要写数据的特征值UUID了,这里我们可以简单地通过循环来找出外设含有的某个特征值UUID:
for(int i=0; i & service.characteristics.count; i++) {
&&&&&&&CBCharacteristic *c = [service.characteristicsobjectAtIndex:i];
&&&&&&&if ([[c
UUID] isEqual:[CBUUIDUUIDWithString:@&FFF1&]])
&{ //你的动作}
在这里我们需要强调一下,由于特征值UUID是外设设定的,并且特征值UUID的属性properties有很多种,比如Read,WriteWithoutResponse,Write,Notify等等,因此你需要根据你们之间的协议还确定对某个特征值UUID怎么处理了,当然你也可以自己读出来这个特征值UUID的属性:c.properties,这里我们假设一个特征值UUID :“FFF1”的属性为WriteWithoutResponse,我们往里面写一个数据
Byte dataArr[2];
dataArr[0]=0xaa; dataArr[1]=0xbb;
NSData * myData = [NSDatadataWithBytes:dataArr length:2];
[_peripheral
writeValue:myData forCharacteristic:c
type:CBCharacteristicWriteWithResponse];
这样我们就完成了一次向外设写数据,但是如果外设的特征值UUID是Read,怎么办呢?比如说获取外设的电池电量信息(注:这个属于标准服务里面自带),服务UUID:“180F”,特征值UUID:“2A19”,我们可以这样写:
[_peripheral
readValueForCharacteristic:cbc];
cbc就是指特征值为“2A19”的特征值对象,当然还有属性为Notify的,方法和这个类似:[peripheralsetNotifyValue:YES&forCharacteristic:c];
那么我们设置读这个特征值对象的值了,怎么接收它发过来的值呢,其实如果外设有特征值对象的值更新了,会自动回调下面的方法:
-&& (void)peripheral:(CBPeripheral *)peripheraldidUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
在这个回调函数里面我们就可以根据characteristic的值来判断是哪个特征值UUID发送过来的值了,那个peripheral主要是用来判断是哪个外设发送的值,主要用于蓝牙一对多的情况,如果是一对一的,基本没用。那么我们再说一下怎么输出接收到的值,就以接收电池电量来说吧,看代码:
if ([[characteristic
UUID] isEqual:[CBUUIDUUIDWithString:@&2A19&]]){
&&&&&&&&&&&const
unsigned char *hexBytesLight = [characteristic.valuebytes];
&&&&&&&&&&&NSString * battery = [NSStringstringWithFormat:@&%02x&, hexBytesLight[0]];
&&&&&&&&&&&NSLog(@&batteryInfo:%@&,battery);
& 其实,外设向IOS这边发数据,都会自动回调上面的那个方法,因此你接收外设发送过来的数据,也只能在这个方法里面,通过不同的特征值判断是哪个UUID发送过来的,解析出数据再执行相应的动作就可以了,好了到这里我们应该很清楚IOS和外设是怎么进行数据沟通的了,如果还想深入就靠你自己了,当然我们最后再说一点,如果连接上的两个设备突然断开了,程序里面会自动回调下面的方法:
-&& (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
在这个方法里面,我们可以做一些补救措施,比如回连,我们就可以在这个方法里写上:
[_centralMan
connectPeripheral:_peripheral
options:nil];
从这个方法里,我们还可以输出连接断开的原因:我们这样写:error.code,跟进去看会发现错误的原因有很多种,比如说CBErrorConnectionTimeout,CBErrorOperationCancelled,CBErrorPeripheralDisconnected,你可以根据错误的原因来进行不同的动作,好了,其实还有很多的回调方法,大家可以去看苹果官方的文档,这里只列出了一些常用的而已,水平有限,有不到之处,还请指证!如果大家还有什么疑问可以加我 QQ:;额,最好还是发邮件到QQ邮箱吧!
外设的特性和服务是怎么来的。。。。。。。。
本分类共有文章1篇,更多信息详见
& 2012 - 2016 &
&All Rights Reserved. &
/*爱悠闲图+*/
var cpro_id = "u1888441";
/*爱悠闲底部960*75*/
var cpro_id = "u1888128";蓝牙使用流程图
Created with Rapha?l 2.1.0CBCentralManagerCBCentralManagerCBPeripheralCBPeripheralServiceServiceCharacteristicsCharacteristics搜索设备设备被管理器发现链接该设备设备连接成功一个外设中有一个或者多个服务检索该设备的服务返回所有的服务一个服务中存在一个或者多个特征检索服务下面对应的特征返回服务下面的特征根据返回的特征,就可以进行对应的读写操作对对应的特征设置监听事件,当监听的特征的内容发生改变的时候会接受到对应的改变值。
1、初始化CBCentralManager。
在初始化的时候需要传入两个参数:
第一个参数设置Delegate一般我们设置成self;
第二个需要传入一个队列,出入的不是主队列的话,那我们接收的时候也要在传入的队列里面才能接收到对应的值,所以一般第二个参数可以直接出入nil或者dispatch_get_main_queue()
2、实现代理方法
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
在该代理方法里面主要监听设备当前的蓝牙状态,根据蓝牙的状态来判断是否进行下一步的操作,状态主要返回如下内容:
CBCentralManagerStateUnknown = 0,
CBCentralManagerStateResetting,
CBCentralManagerStateUnsupported,
CBCentralManagerStateUnauthorized,
CBCentralManagerStatePoweredOff,
CBCentralManagerStatePoweredOn,
3、搜索周围的蓝牙设备调用
- (void)scanForPeripheralsWithServices:(nullable NSArray&CBUUID *& *)serviceUUIDs options:(nullable NSDictionary&NSString *, id& *)options
调用该方法的中心就不断的搜索周围的蓝牙设备,需要传入两个参数:
第一个参数是对应设备的UUID,如果出入nil就搜索周围的所有设备,如果出入了指定的UUID就只搜索出入的设备;
第二个参数是一个搜索的配置参数,该参数的具体配置,自己了解还不是很清楚,平时一般出入nil就可以了
4、在调用搜索周围设备的方法之后需要同时实现以下的代理方法
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
该代理方法里面四个参数主要的意思是:
第一个参数是当前的中心
第二个参数是对应的设备
第三个参数是对应设备蓝牙广播出来的信息
第四个参数是设备的蓝牙信号强度
其中我们主要使用到的是第二个参数,也就是发现的设备
5、得到了对应设备之后就要开始连接设备,连接设备我们调用
- (void)connectPeripheral:(CBPeripheral *)peripheral options:(nullable NSDictionary&NSString *, id& *)
在该方法中我们很明显的看出第一个参数是需要出入一个设备,那么我们就将刚刚发现的设备出入一个进去,第二个参数是需要出入一个字典属性,我这里一般出入的是@{ CBCentralManagerScanOptionAllowDuplicatesKey:@YES }其他属性我没有具体使用,有时间大家一起研究研究。
6、连接设备的时候同时也要实现以下两个代理方法
-(void)centralManager:(nonnull CBCentralManager *)central didDisconnectPeripheral:(nonnull CBPeripheral *)peripheral error:(nullable NSError *)error
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
在这两个代理方法里面,第一个方法是连接发生错误的时候调用的;第二个方法是两节成功之后会调用的,当调用成功之后会返回连接成功对应的中心和设备,这个时候我们要设置设备的代理因为检索设备的服务和服务下面对应的特征的时候都是通过代理的方式实现的
self.ConnectionDevice =
self.ConnectionDevice.delegate = self;
7、通过连接成功的设备调用以下方法发现该设备下面的服务
- (void)discoverServices:(nullable NSArray&CBUUID *& *)serviceUUIDs;
该方法可以传入一个服务的UUID如果出入了对应的UUID之后就之后搜索对应UUID的服务。
8、调用发现服务方法的同时还需要实现对应的代理方法
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(nullable NSError *)
第一个参数是对应的设备,该设备下面有一个peripheral.services属性,通过该属性能够得到该设备下面的所有服务,
第二个参数就是对应的错误信息,当发生错误的时候我们需要做对应的处理
9、得到对应服务之后通过设备调用以下方法发现服务下面对应的特征
- (void)discoverCharacteristics:(nullable NSArray&CBUUID *& *)characteristicUUIDs forService:(CBService *)
第一个参数指定对应特征的UUID,如果传入则只搜索对应UUID的特征
第二个参数传入需要搜索特征的服务
10、调用发现特征方法的时候还需要实现
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(nullable NSError *)
这个代理方法会得到一个CBService在这个下面有一个service.characteristics这个属性里面有该服务下面所有的特征,我们就可以获取到特征了。
到此我们就已经连接了对应的设备,并拿到了对应设备下面的服务和特征了,为我们后面的蓝牙读写操作做好了基础了。
1、写入操作调用以下方法实现
- (void)writeValue:(NSData *)data forCharacteristic:(CBCharacteristic *)characteristic type:(CBCharacteristicWriteType)type;
第一个参数是需要写入的数据
第二个参数是对应写入的特征
第三个参数是对应写入的类型一般是CBCharacteristicWriteWithResponse和CBCharacteristicWriteWithoutResponse这两个类型
2、设置通知监听,调用以下方法实现
- (void)setNotifyValue:(BOOL)enabled forCharacteristic:(CBCharacteristic *)
第一个参数一般情况设置成YES
第二个参数是需要监听的对应特征
3、读取对应特征下面的值,调用
- (void)readValueForCharacteristic:(CBCharacteristic *)
该方法只需要传入需要读取的特征就OK了
4、在设置通知和读取值的时候记得一定要实现以下代理方法
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)
该代理方法在收到通知或者读取到值的时候都会调用,通过characteristic.value我们就得到了想要的值了。
蓝牙的手机端基本操作就差不多完成了,还有很多的地方补助,以后还要像大家学习学习.
最后给出一个自己写的
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1248次
排名:千里之外ios - BLE MTU higher but speed is the same - Stack Overflow
to customize your list.
Announcing Stack Overflow Documentation
We started with Q&A. Technical documentation is next, and we need your help.
Whether you're a beginner or an experienced developer, you can contribute.
I'm playing around with CoreBluetooth in iOS 7, and have successfully got two devices sending quite a large amount of data between each other (one is the central, one is the peripheral).
Between an iPhone 5 and 4S I had an MTU of 20 bytes, and between an iPhone 5s and iPhone 5 I had an MTU of 132 bytes. The size is much larger, so I assumed fewer individual messages would be sent and therefore the overall time of the transfer would decrease.
Unfortunately the time remains pretty much the same in both scenarios (around 15 seconds). Was my original assumption incorrect or is there something I may be doing wrong?
L2CAP has MTU of 20 bytes. If you want to send data of more than 20 bytes, it is sent in multiple packets. Most likely the 132 bytes are being sent in 7 packets at the same rate as 7 20-byte packets. So the throughput is the same.
Your Answer
Sign up or
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Post as a guest
By posting your answer, you agree to the
Not the answer you're looking for?
Browse other questions tagged
Stack Overflow works best with JavaScript enabled}

我要回帖

更多关于 requestmtu 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信