什么是蓝牙service和characteristic?如何理解蓝牙profile? ATT和GATT二者如何区分?什么是attribute? attribute和characteristic的区别是什么?蓝牙的互联互通为何可以作的这么成功?数据库
本文除了阐述上述问题 ,并重点阐述蓝牙协议栈中的ATT层和GATT层。浏览器
低功耗蓝牙协议栈构架结构:安全
如图所示,ATT和GATT是蓝牙协议栈最重要的两层,也是蓝牙应用开发者打交道最多的两层,用户开发应用程序或者说service/profile的时候,调用的都是GATT API,而GATT又调用ATT API。在讲解ATT 和 GATT以前 。咱们先看一下蓝牙核心规范中一个重要概念:Client/Server (客户端/服务端)架构。服务器
BLE client/server(c/s)架构架构
BLE采用了client/server (c/s)架构来进行数据交互,C/S架构是一种很是常见的架构,在咱们身边随处可见,好比咱们常用的浏览器和服务器也是一种C/S架构 ,这其中浏览器都是客户端client ,服务器是服务端server,server好比淘宝服务器,提供商品信息,广告,社交等服务,而浏览器就是客户端,好比微软的IE ,就能够用来请求这些服务,并使用server提供的服务。BLE与此类似,通常而言,设备提供服务,所以设备时server,手机使用设备提供的服务,所以手机就是client。好比蓝牙体温计,它能够提供 "体温" 数据服务,所以是一个server,而手机则能够请求 "体温" 数据以显示在手机上,所以手机是一个 client.框架
服务是以数据为载体的,因此说server提供服务其实就是提供各类有价值的数据。函数
图一: C/S架构spa
客户端要访问一个数据,就发送一个request/请求(其实就是一条命令或者PDU),服务端再把数据返回 给 客户端(一条response/响应命令或者PDU),这就是 C/S架构。翻译
ATT3d
讲解以前咱们先讲解attribute,那么什么是attribute? 其实就是一条条的数据。前面说过,每一个蓝牙设备就是来提供服务的,而服务就是众多数据的集合,这个集合能够称为数据库,数据库里面每个条目都是一个attribute。因此咱们把attribute翻译为数据条目。你们能够把蓝牙设备 想象称为一个表格,表格里面每一行就是一个attribute。attribute能够用下图来表示:
因为这个UUID众所周知,蓝牙 联盟将本身定义的attribute或者数据只用16bit UUID来表示,好比0x1234,其实他也是128bit,完整表示为:
Attribute type通常是由service和characteristic规格来定义,站在蓝牙协议栈角度来看,ATT层定义了一个通讯的基本框架,数据的基本结构,以及通讯的指令,而GATT层就是定义serveice和characteristic,GATT层用来赋予每一个数据一个具体的含义,让数据变得有及结构和意义。换句话说,没有GATT层 ,低功耗蓝牙也能够通讯起来,可是会产生兼容性问题以及通讯效率低。
一个应用全部的 attribute组成一个database,也称为attribute table,一个attribute table示例以下 所示:
上图:原始attribute数据库(这个表格不能算是 原始attribute,由于它已经把bin数据 转成字符了,你们能够 把相关字符都当作bin数据,就当作原始attribute表格)。
设备支持的服务不一样,attribute table就不一样。这里说明一下,当你添加,修改或者删除服务时,那么attribute table就会变,attribute table变了,它占用的RAM空间就会变。
ATT,全称attribute protocol(数据交互协议)。说到底,ATT是由 一群ATT命令组成,就是上文 所述的request(请求)和response(响应)命令。ATT也是蓝牙空口包中的最上层,也就是说,ATT就是你们对蓝牙数据包进行分析的最多的地方。
ATT命令,正式称谓ATT PDU (Protocol Data Unit,协议数据交互单元)包括4类:读,写,notify(通知)和 indicate(指示)。这些命令又能够分红两种:若是它须要response,那么会在相应命令后面加上request。相反,若是它只是须要ACK而不须要response,那么它 的后面就不会带request。这里要特别强调 一点,ATT全部命令都是 "必达" 的。也就是说每一个命令发出去之后,就会立马等ACK信息,若是收到ACK包,发送方认为命令完成;不然发送方一直重发该命令到致使BLE链接断开。换句话说,只要你的BLE链接没有断开,那么 你以前发送的数据包,无论他是用什么ATT PDU来发送的,它确定被对方收到了。
有时候常常会出现一种状况,你们有时候会遇见 " 丢包 ",其实不是在空中丢包或者被干扰了 ,而是咱们 的 发送代码写的有问题,致使包没有被安全的送达到协议栈射频 FIFO中,从而 出现所谓的 " 丢包 "。
既然每一个ATT命令都必达对方,那么还须要request类型的命令作什么?
若是一个命令带有request后缀,那么发起方就能够收到命令的response包,这个response包在应用层是有回调事件的,而前述的ACK包在应用层是没有回调事件的。换句话说,不带request的命令,虽然协议栈底层确保了该命令必达对方,但应用层其实并不知道(私有实现方法除外),当你须要实现一个通讯序列的时候,这种命令就显得不足了。而采用request/response方式的命令时,request命令发出去以后,必须等到相应的response命令回复才能进行下一步操做,好比发送下一个request命令,这样应用层能够严格按照规定逻辑执行一系列的操做,这个在不少应用场合是很是有用的。Request/response命令对还有一个反作用:大大下降通讯的有效速率(吞吐率),由于request/response命令必须在不一样的链接间隔中出现,也就是说,你在间隔1中发送了一个request命令,那么response包必须在间隔2或者稍后间隔中回复,而不能在间隔1中回复,这就致使一个数据包的发送须要跨两个链接间隔甚至更多。而不带request后缀的ATT命令就没有这个限制,ACK能够在同一个链接间隔中回复,这样一个链接间隔中能够同时发出多个数据包,这样将大大提升通讯速率。你们能够参考下图来理解request和非request命令的区别:
注:第1个链接间隔中的蓝色包为request命令,旁边的灰色包是该request的ACK;第2个链接间隔的绿色包是response包,而它的ACK是第3个链接间隔中的蓝色包
注:图中的绿色包就是非request命令,而紧随其后的灰色包就是它的ACK
不带request的命令只有2个:write command和notification,其他的命令都是带request:全部 read命令,全部write 命令,find命令以及indicate命令,完整的ATT命令(ATT PDU)列表以下所示:
GATT,Service(服务)和Characteristic(特征数据)
在讲解GATT以前,咱们先看一下什么是profile?
Profile是一个你们常常见到的英文单词,可是总感受领会不到这个词的内涵。Profile,英文本意就是 脸的侧面轮廓,这里你们注意必定要注意,脸的轮廓 不等于脸自己,可是profile自己是对脸的一种抽象,描述和定义,蓝牙规范其实也是使用profile这个引伸意义而已,换句话说 ,蓝牙的profile跟英文字典中的profile是同一个意思。要定义蓝牙,必需要有一个规范,这就是蓝牙核心规范v4.2/v5.0/v5.1……蓝牙规范很是复杂和庞大 ,大部分蓝牙设备只实现了蓝牙规范中不多一部分,那么没有实现的这些规范对这个蓝牙设备来讲 能不能称为 规范?固然不能!所谓规范或者规格 ,就是强制的,就必须实现。针对这种状况,profile能够很好的应对。咱们把蓝牙某部分规范称为profile,这个profile若是设备要实现它,那么它就是强制的,若是设备不用它,也没有关系,这就是profile。基于此,咱们能够把profile翻译成子规范或者条件规范或者剖面规范。“蓝牙规范包含不少子规范”,这句话用中文说问题不是很大,可是你把它翻译成英文,那就很难了!这就是 英文须要用profile的缘由(而不是spec), 以及为何profile在规范中出现的如此频繁。
GATT,全称generic attribute profile,对数据进行通常化/抽象化的子规范,说白了就是对数据进行逻辑化表达的规定。前面说过了,attribute就是一条一条的数据,那么这条数据表示什么?如何对其进行分类?这就是GATT要作的事情,GATT将数据赋予含义,并呈现必定的逻辑结构。
Service和characteristic就是GATT层定义的,前面说过,server端提供 服务,服务就是数据,而数据就是一条一条的attribute,而service和characteristic就是数据的逻辑呈现,后者说用户能看到的数据最终都转化为 service和characteristic。好比,一个数据 “37”。有多是说体温 “37度”,也可能说心率 “37次”或者湿度 “37%”,所以必须对数据进行分类和定义。
在蓝牙规格中,每个具体的蓝牙应用是由多个service组成,而每个service又是多个characteristic组成,这样咱们能够把上面的图一转化为图3.
图三:service和characteristic
那么service/characteristic和attribute之间究竟是一个怎样的关系?如前所述,service/charateristic是attribute的逻辑表现形式,而attribute是service/characteristic具体实现方式。尤为要注意的是,一条characteristic不是对应一条attribute具体实现方式。尤为注意的是,一条chararcteristic不是对应一条attribute,而是由多条attribute组成。虽然一个数据最有价值的部分是它的值(value )。=,可是 仅有value是不够的,好比27,究竟是表示27°温度仍是27%湿度;若是表示的是温度,那么它的单位是摄氏度仍是华氏度。同时每一个数据还有相应的读写属性以及权限属性,所以一个characteristic包含三种类型的数据条目(attribute):characteristic声明体条目(declaration attribute),characteristic 值条目(value characteristic)以及characteristic描述符条目(descriptor attribute) (一个characteristic能够有多个描述符条目),以下所示:
因为一个service能够包含多个characteristic,characteristic declaration就是每一个characteristic的分界符,解析时一旦遇到characteristic declaration,就能够认为接下来又是一个新的characteristic了,同时characteristic declaration还将包含value attribute的读写属性等。Charateristic value就是数据的值了,他也是一个单独的attribute,这个比较好理解就再也不说了。Charactristic descriptor就是数据的额外信息,好比 温度的单位是什么,数据是用小数表示仍是百分比表示等之类的数据描述信息。Descriptor属于可选条目,也就是说,一个characteristic能够不包含任何一条descriptor。这里着重提一种特殊的descriptor:CCCD。通常而言,都是client来访问server的characteristic,即经过ATT读或者写PDU访问相关数据。若是server想直接把本身的characteristic的值告诉client,就须要经过notiy或者indicate PDU,跟其余PDU相比,这两个PUD是由server本身决定何时开始传送,而不是被动接收client的命令请求。但client毕竟是客户,他得有自主权,因此引入了一个CCCD来帮助client控制server的行为。client能够经过禁止CCCD以容许notify或者 indicate命令,client能够经过禁止CCCD以容许notify或者indicate命令。从新总结一下。当CCCD使能的状况下,server能够随时notify或者indicate数据 给client;当禁止的时候,哪怕server有数据,它也不能notify或者indicate给client。这里强调一下。当characteristic具备notify或者indicate操做功能时,蓝牙规范要求必须为其添加CCCD attribute.
重复强调,无论是characteristic declaration,characteristic value仍是characteristic descriptor,实现的时候,都是一条数据条目,即attribute.
引入了GATT,咱们就能够把图2的 attribute table进行GATT化,获得下面有内涵,有层次,有定义的数据表格:
所谓开发蓝牙应用程序,其实就是开发service和characteristic。经过API,添加本身须要的characteristic和service,你本身的蓝牙设备就诞生了。只要characteristic和service是符合GATT规范的,你能够随意添加任何characteristic和service,并将他们组合成一个专门的蓝牙设备。因为这个蓝牙设备是按照规范来定义的,因此它能够与任何其余蓝牙设备,好比手机,互联互通,并完成所要求的的交互动做。这里的蓝牙设备,咱们还能够进一步细分为蓝牙profile设备和非profile蓝牙设备。前面也提过,profile就是一个子规范,蓝牙profile设备包含的全部实际service和characteristic都是按照profile规格来添加和定义的,好比说心率计profile,就是一个蓝牙联盟定义的蓝牙设备,蓝牙联盟有一份专门的spec来定义心率计profile,在这份spec中规定了心率计profile除了包含心率service,还包含电池service,设备信息service等。从这能够看出,心率profile和心率service是包含关系,前者包含后者。