蓝牙是一种低成本、短距离的无线通信技术。对于那些希望创建个人局域网(PANs)的人们来说,蓝牙技术已经越来越流行了。每个个人局域网都在独立设备的周围被动态地创建,并且为蜂窝式电话和PDA等设备提供了自动连接和即时共享数据的能力。
    为了在Java平台上开发支持蓝牙技术的软件,JCP定义了JSR82标准--Java蓝牙无线技术APIs(JABWT)。
    在这篇文章中,我将介绍一些关于蓝牙技术的背景,概述一下支持蓝牙技术的MIDlet应用程序的典型要素,然后介绍给你核心的Java蓝牙APIs。最后我们展示一些代码来演示如何使用这些APIs。
    实际上JSR82定义了两个独立的可选包:核心蓝牙API和对象交换(OBEX)API。这篇文章将对这两个中更为普遍的部分--核心蓝牙包javax.bluetooth进行详细地阐述,而OBEX API(对象交换),我们留到以后去讨论。

背景
    篮牙技术由蓝牙兴趣小组发展,其包括:
        .无线电技术
        .协议栈
        .互操作性profiles
    蓝牙无线电技术基于在工业、科学以及医学(ISM)上公用的2.45GHz开放频段,这一频段无需授权并全球通用。当蓝牙设备互相连接时,他们将组成一个微微网(piconet),即以一个主设备和最大7个从设备的形式动态创建网络。蓝牙也支持piconet网之间的连接:当一个piconet中的主设备成为另一个piconet的从设备时,piconet与piconet间将形成桥接。
    蓝牙协议栈提供了一组的高层协议和API以完成发现服务和模拟串行I/O,还有一个关于包分割和重组的低层协议以及多路技术协议和质量服务。蓝牙互操作性profiles--不要与J2ME profiles搞混--它是用来描述跨平台互操作性和一致性需求的。蓝牙互操作性profiles包括三方面内容:通用访问profile(GAP)定义了设备管理功能性;服务发现应用profiles定义了服务发现方面的内容,串口profiles定义了互操作设备和模拟串口电缆的能力。你可以通过蓝牙规范(Bluetooth specification)学习这些和其它的profiles。
    蓝牙栈包含一个软件栈来映射一个固件栈(firmware),由图1所示:

图片1:蓝牙协议栈
    JSR82揭示了蓝牙软件栈给Java平台的开发者。其中引起我们兴趣的是服务发现协议(SDP),用来模拟串口的串口profile RFCOMM, 向上层协议提供诸如分割和重组等导向性连接的数据转换操作的逻辑链路控制及适配profile(L2CAP),以及多路技术协议。注意JABWT不支持无连接L2CAP。
    JABWT也包括对象交换API。OBEX也是高层API,它用来交换对象数据,诸如电子商业卡和日历标签之间以vCard和vCalendar的格式进行数据传输。在蓝牙上,对象交换通过RFCOMM发生。OBEX在最开始时是由红外(IrDA)引入的,并且它可以在IrDA协议、TCP/IP或者是其他协议的顶层实现。

典型的蓝牙应用程序实例
    一个开启蓝牙功能的应用可以作为一个服务端或是一个客户端-- 一个服务的提供者或是消费者,或者它可以作为一个真正的点对点终端同时表现出服务和客户的行为。图2所示一个蓝牙规范用例:

图2:一个典型的具有蓝牙功能的实际用例
    对这些用例的简要介绍:
        .初始化--所有具备蓝牙功能的应用程序必须先要初始化蓝牙栈。
        .客户端-- 一个客户对远端服务进行消费。首先它要发现所有附近的设备,然后对于每一个发现的设备搜索它感兴趣的服务。
        .服务器端-- 一个为客户端提供服务的服务器。它在服务发现数据库(SDDB)中对客户端进行注册,对他们进行有效广播。然后等待引入的连接,在他们进入时接受他们并为他们提供服务。最后,当不再需要服务时,应用程序会在服务发现数据库(SDDB)中将他们移除。
 
    图三:用例中参与活动的图表:

图 3: 蓝牙应用程序活动图

蓝牙应用程序中的元素
    图4显示了在MIDlet中一个典型蓝牙功能应用程序中的一些元素:

图4: 具有蓝牙功能的 MIDlet (高端组织)
    中间的是核心应用程序My Bluetooth MIDlet,它扩展自javax.microedition.midlet.MIDlet。没有显示出来的还有MIDlet中实现的javax.microedition.lcdui.CommandListener以监听从用户接口中输入的命令。应用程序使用的剩余的类和接口都包含在了蓝牙规范中,像设备发现和服务,连接和服务消费,还有广播和提供服务。
    使用诸如MVC等设计模式是很好的实践。MVC把应用程序分解成用户接口(视图),应用程序行为和导航(控制器),以及数据(模型),当然在我们的案例中还要加上蓝牙API的支撑类和接口。像将分离的客户端、服务端行为构建成独立的类以便以后可以重用这些组件,也是很好的设计。

Java蓝牙API核心概述
    JSR82需求的"最小公分母"是 受限连接设备配置(CLDC),可靠连接设备配置(CDC)是CLDC的超集,所以JABWT可以同时在CLDC和CDC上实现,简要地说,你可以在使用任何J2ME profile的上使用JABWT。
在javax.bluetooth中我们可以发现,Java蓝牙API可以被分解为三个部分,在下面我们将讨论到它们:发现、设备管理和通信。
 
蓝牙发现API
    客户端程序使用蓝牙发现API以搜索在其附近的设备和服务。服务代理类(DiscoveryAgent)同时支持设备与服务的发现。当设备和服务被发现时,想得到通知的客户端应用程序必须实现并注册DiscoveryListener接口,这个接口定义了设备发现通知和服务发现通知的回调。
    发现代理(DiscoveryAgent)与蓝牙客户端应用程序之间是典型的一对一的关系:

图 5: DiscoveryAgent类和DiscoveryListener接口

设备发现API
    你使用DiscoveryAgent类的"设备发现"方法来开始和取消设备发现:
        .retrieveDevices()重新获得已经发现或者附近的已知设备
        .startInquiry() 启动发现附近设备,也叫inquiry
        .cancelInquiry()取消当前进行的任何请求
    蓝牙发现代理在请求阶段的不同时候会分别调用DiscoveryListener(发现监听器)不同的回调方法:
        .deviceDiscovered() 指出是否有设备被发现。
        .inquiryCompleted() 指出是否请求已经成功、触发一个错误或已被取消。
    在图6中的状态图表阐明了设备发现的状态改变结束于相应的回调方法的返回。

图 6: 设备发现状态表

设备发现以调用startInquiry()函数开始。在请求进行时,蓝牙发现代理会在适当的时候调用回调方法DeviceDiscovered()和inquiryCompleted()。

服务发现API
    你可以使用发现代理的服务发现方法来开始或取消服务发现:
        . selectService()启动服务发现搜索。(原文有误,根据API手册应为尝试定位一个服务)
        . searchServices()启动服务发现搜索。
        . cancelServiceSearch()取消在正在进行中的任何的服务发现搜索操作。
    蓝牙发现代理在服务发现阶段的不同时候会分别调用DiscoveryListener的服务发现回调方法:
        . servicesDiscovered() 表示是否服务已被发现。
        . serviceSearchCompleted()表示服务发现是否已经完成。
    图7阐明了服务发现的状态改变结束于DiscoveryListener的回调方法的返回。

图 7: 服务发现状态图表

服务发现开始于对searchServices()的调用。当服务搜索进行时,蓝牙发现代理会在适当的时候回调servicesDiscovered()和 serviceSearchCompleted()方法。
    除了DiscoveryAgent和 DiscoveryListener了,你在服务发现过程中还要使用到的类有UUID,ServiceRecord以及DataElement等。

UUID类
    在蓝牙中,每个服务和服务属性都唯一地由"全球唯一标识符" (UUID)来校验。正如它的名字所暗示的,每一个这样的标识符都要在时空上保证唯一。UUID类可表现为短整形(16或32位)和长整形(128位)UUID。他提供了分别利用String和16位或32位数值来创建类的构造函数,提供了一个可以比较两个UUID(如果两个都是128位)的方法,还有一个可以转换一个UUID为一个字符串的方法。UUID实例是不可改变的(immutable),只有被UUID标示的服务可以被发现。
    在Linux下你用一个命令uuidgen -t可以生成一个UUID值;在Windows下则执行命令uuidgen 。UUID看起来就像如下的这个形式:2d266186-01fb-47c2-8d9f-10b8ec891363。当使用生成的UUID去创建一个UUID对象,你可以去掉连字符。

SDDB和ServiceRecord接口
    在服务发现的中心是服务发现数据库(SDDB)和服务发现协议(SDP)。SDDB由蓝牙实现负责维护的数据库。它包含了服务记录(service records),后者代表了对客户端有效的服务。SDP对于基于JABWT应用程序来说是透明的;可以这么说,SDP是用于服务发现的。为重新获取服务纪录,一个本地设备SDP客户端会向一个远端设备上SDP服务器发出请求。

图 8: SDDB

每一笔服务记录都会由一个ServiceRecord的实例来表现。这个记录包含了描述服务细节的属性。这个类提供了几种有用的方法:
    .getAttributeIDs() 和 getAttributeValue()方法返回服务记录的属性。
    .getConnectionURL()方法获取链接的URL地址给服务器主机来收集服务记录。
    .getHostDevice() 方法获取提供服务的远端设备。
    .populateRecord() 和 setAttributeValue()方法用来设置设备记录的属性。
    .setDeviceServiceClasses()方法设置服务的类。
图9显示了蓝牙本地设备和远端设备,以及SDDB还有服务记录之间的关系:

图 9: 使用远端设备,SDDB和服务记录进行服务发现

为使服务端可以被客户端来使用,服务应用程序要通过如下方法建立一个服务记录,首先要创建一个连接通知器(connection notifier),然后由调用连接通知器的acceptAndWait()方法来向SDDB中插入记录。服务端程序能够在适当的时候获得记录和更新。客户端应用程序向远端SDDB请求可以使用的服务,会发现服务记录。(待续)

数据元素类
    一个服务可以有许多的属性,一些是强制性的,其他的是可选的。一个服务属性由一个数据元素对象来表现,这个数据元素对象提供了设置并取得属性值的方法。
    强制性属性是在注册一个服务之后被自动设定的。这些属性包括:ServiceRecordHandle,ServiceClassIDList, ServiceRecordState, ServiceID, 还有 ProtocolDescriptorList。
    如果你想要的话,还可以设置可选属性。可选属性有很多,但是有三个值得关注:ServiceName,ServiceDescription, 和 ProviderName。
    想得到更多的关于这些属性的信息,请参看JABWT的文档或蓝牙规范。
设备管理API
    有3个主要的类来支持设备管理:
    .LocalDevice
    .RemoteDevice
    .DeviceClass
本地设备类
LocalDevice类标识了本地蓝牙设备。蓝牙应用程序和LocalDevice之间的关系是典型的一对一关系:
图 10:本地设备类
本地设备提供了方法来返回关于本地设备的信息,并且能够进入Bluetooth manager:
    .getBluetoothAddress()返回蓝牙设备地址。
    .getDeviceClass()返回设备类。
    .getFriendlyName()返回设备友好名称,蓝牙设备名通常是用户在蓝牙控制中心为其设置的我们将会在后面看到。
    .getRecord()返回一个指定蓝牙连接的服务记录。
    .updateRecord()方法用来为指定的ServiceRecord更新SDDB服务记录。
    .getDiscoverable()返回设备的可发现状态。
    .setDiscoverable()设置设备的可发现状态。
    .getDiscoveryAgent()返回一个参考给发现代理。
    .getProperty()返回一个设备的蓝牙属性
通过调用getProperty()方法你可以得到的属性包括:
    .bluetooth.api.version,蓝牙API版本
    .bluetooth.sd.attr.retrievable.max,一次性能够被获得的服务记录属性的最大值
    .bluetooth.connected.devices.max,支持的连接设备的最大值
    .bluetooth.sd.trans.max,同时发生的服务发现处理的最大值
    .bluetooth.l2cap.receiveMTU.max,L2CAP最大发射单元
你可以在Javadoc文档中或是规范中学习更多的有关蓝牙属性的内容。
远端设备类
    一个RemoteDevice的实例代表了一个远端蓝牙设备。在一个蓝牙客户端应用程序可以进行服务,消费之前,它必须发送一个设备请求来发现远端设备。典型的蓝牙应用程序和远端设备之间的关系是一对多:
图 11: 远端设备类
远端设备(RemoteDevice)提供的方法中,有些很类似于本地设备(LocalDevice)里提供的方法:
    .getBluetoothAddress()返回蓝牙地址。
    .getFriendlyName()返回蓝牙设备名。
    .getRemoteDevice()返回相应的被指定蓝牙连接的远端设备。
    .authenticate()尝试识别验证远端设备。
    .authorize()为指定的蓝牙连接去尝试批准远端设备访问本地设备。
    .encrypt()尝试为指定的蓝牙连接开启或关闭加密。
    .isAuthenticated()测试是否远端设备可以被验证。
    .isAuthorized()测试是否远端设备已经被蓝牙控制中心授权访问本地设备以进行蓝牙连接。
    .isEncrypted()测试是否本地设备和远端设备之间的通信被加密。
    .isTrustedDevice()测试是否远端设备被蓝牙控制中心指定为可信任的。
DeviceClass类
    一个DeviceClass对象代表一个设备的设备类(CoD),例如一个打印机或者一部电话。CoD包括一个主类,一个辅的类,和服务类型或服务类。DeviceClass提供了如下方法:
    .getMajorDeviceClass()方法获取设备的主类。
    .getMinorDeviceClass()方法获取设备的辅类。
    .getServiceClasses()获取设备的服务类。
当一个设备被发现,同时他的类也会被发现;当发现代理调用deviceDiscovered()时,其中一个参数就是DeviceClass。你可以通过它的getDeviceClass()方法找到本地设备的CoD。
蓝牙通信
    JABWT连接是基于逻辑链路及适配层协议的。L2CAP是一个低级协议用来管理数据包,直到达到64k。L2CAP中的处理细节像消息分割和重组(SAR),多路连接。另外,串口Profile(SPP)提供RFCOMM,一个通过L2CAP层的串行模拟协议。
    L2CAP和RFCOMM连接都是基于通用连接框架(GCF)的,直接通向接口和类的层次去创建连接和执行IO命令。JABWT依靠L2CAP和RFCOMM协议扩展了通用连接框架(GCF)以分别支持通过L2CAPConnection 和StreamConnection类型连接。就在L2CAPConnection被JSR 82介绍的同时,StreamConnection在原始的javax.microedition.io的GCF中被定义了,它是依靠CLDC发展来的。注意,JABWT中L2CAPConnection仅支持面向连接的L2CAP连接。图12显示了以基于GCF形式的各接口通过蓝牙网络进行通信的过程:
图 12: 通用连接框架和蓝牙连接类型
层次定义了L2CAP和Stream的连接和连接通知器。一个连接定义了一个连接终端,当一个连接通知器执行了服务行为时,它会等待并接受L2CAP连接处理。
    处理L2CAP连接比处理流连接更复杂。使用L2CAP时,开发者们必须处理好最大消息的大小(即最大传输单位,或叫做MTU)、打断和重组等。这些复杂的事项在开发者使用流连接的时候被隐藏了,以使他们处理蓝牙连通时获得更好的效率。
    如同所有的GCF连接类型,你可以通过调用GCF连接工厂方法javax.microedition.io.Connector创建蓝牙连接。传递给Connector()方法的连接URL决定了要创建的连接类型:
一个L2CAPConnection连接的URL格式:
btspp://hostname:[CN | UUID];parameters
一个RFCOMMStreamConnection连接的URL格式:
btspp://hostname:[CN | UUID];parameters

细节介绍:
    .btl2cap 是为L2CAPConnection设计的URL配置方案。
    .btspp是为RFCOMM StreamConnection的URL配置方案。
    .hostname 既可是localhost用于架设一个服务器连接,也可是一个用于创建客户端连接的蓝牙地址。
    .PSM是协议/服务多路复用值,在一个客户端连接服务器端时使用。在概念上是模拟一个TCP/IP端口。
    .CN是信道数值,在一个客户端连接服务器端时使用,也是模拟TCP/IP端口。
    .UUID是UUID(通用唯一标识符)值,在一个服务器上建立服务时使用。
    .parameters(参数)包括描述服务名称的名字和有于安全的参数:验证、授权和加密。
服务器连接和客户端连接
    在连接的URL中,主机名称告诉连接工厂是否它应该创建一个客户端异或服务器端。如果使用单词localhost作为主机名将定义一个服务器连接。客户端想要连接到一个指定的的服务可以通过调用ServiceRecord.getConnectionURL()来找到该服务连接的URL。
异常
    javax.bluetooth核心API定义了三个异常类:
    .当一个蓝牙L2CAP、RFCOMM或是OBEX-over-RFCOMM连接不能被成功建立会抛出BluetoothConnectionException异常。
    .一个试图在错误状态下进行蓝牙操作时,会抛出BluetoothStateException异常。
    .当在本地服务发现数据库(SDDB)中,添加或改变服务记录失败时,会抛出ServiceRegistrationException异常。
蓝牙安全
    一个安全的蓝牙连接应该是经过验证、可选的获得授权和被加密过的。这样,蓝牙连接在建立之初或以后就可以保证其安全性了。
注意:不是所有的蓝牙实现都提供了安全连接的。
为了在建立一个蓝牙连接时使其安全,就要给javax.microedition.io.Connector在连接URL字符串上提供适当的安全参数:

btspp://hostname:[CN | UUID];authenticate=true;authorize=true;encrypt=true

Where:
    .authenticate验证一个连接设备的身份。
    .authorize授权一个连接中的设备(已被识别)是否被允许进入。
    .encrypt指定连接需被加密。
你已经看到了想要连接到一个服务的客户端可以通过调用ServiceRecord.getConnectionURL()方法以获得服务连接的URL。该方法中的一个参数requiredSecurity,指定了返回的这个连接URL是否应该包含可选的authenticate和encrypt等安全参数。关于requiredSecurity的有效值为:
.ServiceRecord.NOAUTHENTICATE_NOENCRYPT意为authenticate=false; encrypt=false。
.ServiceRecord.AUTHENTICATE_NOENCRYPT意为authenticate=true; encrypt=false。
.ServiceRecord.AUTHENTICATE_ENCRYPT意为authenticate=true; encrypt=true。
例如:

...
ServiceRecord sr = ...;
...
String connURL = sr.getConnectionURL(ServiceRecord.AUTHENTICATE_ENCRYPT, false);
...
如果不在建立一个连接的时候就使用这种方法保证安全性,你也可以在以后确保其安全性,这就要使用一组已知的远端设备的安全方法:authenticate(),authorize()和 encrypt()。如果你这样做了请注意,验证必须在授权和加密之前进行。
蓝牙控制中心
    蓝牙控制中心(BCC)是设备上的一个管理软件,它负责在作为授权中心改变本地蓝牙的设置,包括:打开或关闭蓝牙无线电,设置友好名称以便在设备发现过程中进行广播,开启或屏蔽设备的发现模式,设置PIN码,设置缺省安全属性等等。BCC看上去表现如何全看实现的具体情况。
在Sun Wireless Toolkit中对蓝牙的支持
    J2ME Wireless Toolkit 2.2支持JABWT。toolkit的Preferences Utility(使用偏好)提供了新的Bluetooth/OBEX标签以进行蓝牙参数设置。在此栏下OBEX设置和三个蓝牙子标签,它们分别是:Internal Properties(内部属性)标签允许你设置设备搜索的超时时间,System Properties(系统属性)标签允许你定义一些调用LocalDevice.getProperty()方法便可得到蓝牙属性。BCC Properties

使用Java蓝牙无线通讯技术API相关推荐

  1. 使用Java蓝牙无线通讯技术API概述

    蓝牙是一种低成本.短距离的无线通信技术.对于那些希望创建个人局域网(pans)的人们来说,蓝牙技术已经越来越流行了.每个个人局域网都在独立设备的周围被动态地创建,并且为蜂窝式电话和pda等设备提供了自 ...

  2. Java远程通讯技术及原理分析

    在分布式服务框架中,一个最基础的问题就是远程服务是怎么通讯的,在Java领域中有很多可实现远程通讯的技术,例如:RMI.MINA.ESB.Burlap.Hessian.SOAP.EJB和JMS等,这些 ...

  3. Java 远程通讯技术及原理分析

    转自:https://www.cnblogs.com/Luouy/p/7399918.html 消息模式 归根结底,企业应用系统就是对数据的处理,而对于一个拥有多个子系统的企业应用系统而言,它的基础支 ...

  4. java 及时通讯弹幕技术 视频播放 websocket SSM 集成代码生成器 源码

    获取[下载地址] QQ: 313596790 官网 http://www.fhadmin.org/ A 代码编辑器,在线模版编辑,仿开发工具编辑器,pdf在线预览,文件转换编码 B 集成代码生成器 [ ...

  5. Java学习---RMI 技术分析[Hessian]

    一.什么是Hessian Hessian 是一个基于 binary-RPC 实现的远程通讯 library.使用二进制传输数据.Hessian通常通过Web应用来提供服务,通过接口暴露.Servlet ...

  6. 【原创】轻量级移动端即时通讯技术 MobileIMSDK 发布了

    申明:MobileIMSDK目前为个人原创开源工程,投入了大量的时间和精力,希望对需要的人有所帮助.如需与作者交流,见文章底部个人签名处,互相学习.Q群:215891622,欢迎共同志趣者学习和交流. ...

  7. NFC无线近场通讯技术

    NFC技术 1 简介 1.1技术背景 无线近场通讯技术(Near Field Communication,NFC),最早是Sony和Philip这两家公司共同开发的一种非接触式识别和互联技术,现在已经 ...

  8. Web实时通讯技术简介

    一.概述 1.Web端即时通讯技术 即时通讯技术简单的说就是实现这样一种功能:服务器端可以即时地将数据的更新或变化反应到客户端,例如消息即时推送等功能都是通过这种技术实现的.但是在Web中,由于浏览器 ...

  9. 网络技术概念与Java网络编程技术——最通俗的理解(转载)

    网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者可能觉得网络编 ...

最新文章

  1. 两个表的更新、表的复制
  2. 大一计算机论文_大一计算机实验报告
  3. UVA11375火柴(递推+大数)
  4. mysql索引分析_MySQL索引分析和优化
  5. Jquery实现简单图片切换
  6. 高通宣布与华为达成新专利授权协议,华为砸下18亿美元
  7. nlogn求最长不上升子序列
  8. 你绝对想不到,会Linux的程序员,到底有多吃香!
  9. win10易升_史上最稳定的win10版本,四大更新内容强势来袭,你敢升级吗?
  10. PHP 实现发送短信验证码(CI框架)
  11. 10分钟搭建你的云端微信机器人️️️
  12. 我是如何学习安卓开发的
  13. 软件机器人实现一键报税,即使没有开发接口,纳税申报也照样方便、快捷
  14. 年收入80亿、三年扩张四倍:1700人的Playrix已成休闲游戏新巨头
  15. 通达信玄黄趋势波段指标源码
  16. java给教师排课模块,java选排课系统
  17. netty实现简单时事通讯_使用 RSocket 进行反应式数据传输
  18. Unity2016 Unity3D开发VR游戏的经验
  19. 部署Exchange Server 2003+SP2补丁
  20. React中标签字符串强制转html解析的方法

热门文章

  1. 使用freemarker生成word文档(包含遍历多条数据、图片)
  2. 阿里研究院院长高红冰:如何测量数字经济的小美与大好
  3. 2D DenseUnet-based脑胶质瘤分割BraTs+论文翻译+代码实现
  4. 小车自动往返工作原理_小车自动往返.ppt
  5. 2013传智播客视频--.ppt,.pptx,.doc,.docx.目录
  6. ICT的圣杯(二):数字生活的另类想象
  7. 2022 电赛陕西省赛
  8. 实时的YcoCg-DXT压缩
  9. (附源码)基于Python的“书怡”在线书店系统的设计与实现 毕业设计082332
  10. 从Web2.0到Web3.0