级别: 初级
Bruce Hopkins (bhopkins@gestalt-llc.com), 技术架构师, Gestalt LLC
2005 年 12 月 15 日
熟悉用来控制蓝牙设备的 Java™ 语言库,并学习如何用 JSR-82 API 和 Object Exchange 在客户机和服务器之间传输文件。
<!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--end RESERVED FOR FUTURE USE INCLUDE FILES-->
蓝牙协议栈允许采用多种方法,包括 RFCOMM 和 Object Exchange(OBEX),在设备之间发送和接收文件。如果想发送和接收流数据(而且想采用传统的串口应用程序,并给它加上蓝牙支持),那么 RFCOMM 更好。反过来,如果想发送对象数据以及关于负载的上下文和元数据,则 OBEX 最好。在这篇文章中,将熟悉用来控制蓝牙设备的 Java 语言库,并学习如何使用 JSR-82 API 和 OBEX 在客户机和服务器之间传输文件。
蓝牙是多家移动设备制造商选择的无线协议,拥有多项吸引人的特性,最重要的是它在数据传输上的低能耗。截止 2004 年 6 月,每周交付的支持蓝牙的设备超过五百万台,这项技术在消费电子市场上拥有强大的渗透率。
蓝牙协议回顾
目前市场上设备中运行的蓝牙协议有三个版本 —— 分别是版本 1.1、1.2 AFH 和 2.0+EDR。这没给开发人员带来任何问题,因为新版本的协议与以前的版本兼容。表 1 显示了目前可用的蓝牙版本的一些相似性与区别。
表 1. 蓝牙协议版本
版本
原始数据速率
通信范围(英尺)
说明
Bluetooth 1.1 |
1 Mbps |
30-300 |
市场上部署得最广泛的蓝牙版本。 |
Bluetooth 1.2 AFH |
1 Mbps |
30-300 |
包含高级频率跳跃技术,可以与 WiFi 网络更好地并存。 |
Bluetooth 2.0+EDR |
3 Mbps |
30-300 |
包含增强数据速率技术,可以用更高的速度传输数据。 |
现在,让我们回顾一下控制蓝牙设备的固件/软件:栈。
蓝牙协议栈
蓝牙栈的目的是什么呢?栈是控制蓝牙设备的软件(和固件)。图 1 显示了协议栈的细节。
图 1. 蓝牙协议栈
- 栈的最底层是 HCI,即主机控制器接口(Host Controller Interface)。这一层顾名思义就是主机(计算机)和控制器(蓝牙设备)之间的接口。可以看到,其他所有的层都要经过 HCI。
- HCI 上面的一层是 L2CAP,即逻辑链接控制器适配协议(Logical Link Controller Adaptation Protocol)。这一层充当其他所有层的数据多路复用器。
- 接下来一层是 BNEP,即蓝牙网络封装协议(Bluetooth Network Encapsulation Protocol)。使用 BNEP,可以在蓝牙上运行其他网络协议,例如 IP、TCP 和 UDP。
- RFCOMM 称作虚拟串口协议(virtual serial port protocol),因为它允许蓝牙设备模拟串口的功能。
- OBEX 协议层是在 RFCOMM 层上面实现的,如果想把数据以对象(例如文件)的形式传输,那么 OBEX 很有用。
- SDP 是服务发现协议(Service Discovery Protocol)层,用于在远程蓝牙设备上寻找服务。
- 最后两层是 AVCTP 和 AVDTP,用于蓝牙上音频和视频的控制 和 发布。AVCTP 和 AVDTP 是蓝牙协议中增加的相对较新的层;如果想控制媒体播放器的功能或者想以立体声播放音频流,则要使用它们。
发送文件:RFCOMM 还是 OBEX?
我们先来看看栈中用来发送数据的两个简单协议 RFCOMM 和 OBEX,并比较使用它们传送文件的优势和不足。
可以采用 RFCOMM 或 OBEX 在蓝牙设备之间发送和接收文件。但是,如果想发送和接收流数据,则 RFCOMM 是更好的选择,就像使用传统的串口一样。在现实世界中,如果想使用传统的串口应用程序,并让它能使用蓝牙,就应当使用 RFCOMM。如果要在蓝牙设备之间发送简单的文本字符串(例如在聊天应用程序中),那么使用 OBEX 可能没有太大优势。在这种情况下,应当使用 RFCOMM 或 L2CAP。
另一方面,如果想发送对象数据(例如文件),则 OBEX 最合适。使用 OBEX 不仅可以发送数据,而且还能发送关于负载的上下文或元数据。例如,在使用 OBEX 发送文件时,还能够发送关于文件的其他有用信息,例如文件名称、文件类型、文件尺寸或者其他任何对文件进行描述的内容。
那么,既然已经决定了使用蓝牙时通过 OBEX 发送对象数据文件,那么我们来看看使用 Java 语言对蓝牙设备进行控制的官方库。
探索 JSR-82 API
JSR-82 是用于蓝牙无线技术的官方 Java API。可使用这个 API 创建可执行以下功能的应用程序:
- 判断和检测自己的蓝牙设备的属性
- 发现设备通信范围内的蓝牙设备
- 在远程蓝牙设备上搜索服务
- 创建可以与远程蓝牙服务器通信的蓝牙客户机应用程序
- 创建能够为蓝牙客户机的请求提供服务的蓝牙服务器应用程序
JSR-82 包含两个包,即 javax.bluetooth 和 javax.obex 。您自己的蓝牙设备由 javax.bluetooth.LocalDevice 类表示,所有的远程蓝牙设备由 javax.bluetooth.RemoteDevice 类表示。
javax.bluetooth.DiscoveryAgent 类是个有帮助的类,它让您可以发现附近的远程蓝牙设备,并为区域内的每个蓝牙设备返回一个 javax.bluetooth.RemoteDevice 。也可以使用 javax.bluetooth.DiscoveryAgent 在已经发现的远程设备上搜索服务。
如果想在发生发现事件的时候得到通知,则需要实现 javax.bluetooth.DiscoveryListener 接口的方法 。这一切听都来都很简单,是不是?但是,当想要创建 OBEX 应用程序的时候,会变得复杂一些。
OBEX 的语义
也许您不知道,OBEX 并不是蓝牙本身的协议,实际是由无线数据协会创建的。因为 OBEX 是已采纳的 协议,所以 Java 蓝牙 API 的作者决定为 OBEX 应用程序单独创建一个包;这样,就可以使用 Java 创建出能够在任何传输机制(例如红外或 TCP/IP)而不仅仅是在蓝牙上工作的 OBEX 应用程序。
在使用蓝牙 API 创建 OBEX 应用程序时,将使用 javax.obex 包中的一些类和接口。正如我在前面提到过的,蓝牙协议栈中的 OBEX 层实际是面向蓝牙设备间的文件传输而优化的,所以就像传统的 FTP 一样,OBEX 应用程序拥有像 GET 和 PUT 这样的操作。
到底什么是 OBEX 操作?
OBEX 操作
当客户机和服务器在一个 OBEX 会话内通信时,它们的交互叫做操作。对于每个从客户机发出的操作,服务器给出一个响应,指明操作的状态。要真正了解 OBEX 客户机和服务器的操作和响应的工作方式,请参见图 2:
图 2. OBEX 操作和响应代码
如果从电话向打印机发送文件,就像图 2 中表示的那样,需要什么呢?首先,在创建 OBEX 会话之前,先要建立一个传输的连接(蓝牙、红外、TCP/IP 等等)。因为这篇文章是关于蓝牙的,所以毫不奇怪我要使用的底层传输机制是蓝牙。
在传输连接已经建立之后,蓝牙客户机需要发出 CONNECT 操作。如果蓝牙服务器(在这个示例中,是打印机)想接受新客户机来使用它的服务(例如打印服务),那么它就用表示成功的响应代码 160 对客户机进行响应。如果打印机不想接受新客户机,那么它可能用响应代码 211 来响应,这个代码代表 “OBEX SERVICE UNAVAILABLE”。
现在假设打印机接受了 CONNECT 操作,那么现在就在客户机和服务器之间创建了一个 OBEX 会话。现在有了 OBEX 会话,就能够向 OBEX 服务器发送请求(请注意,请求和操作是同义的)。当然,GET 和 PUT 操作是自解释的。但是,SETPATH 操作主要是在 OBEX 服务器具有文件系统时才使用。OBEX 客户机发送 SETPATH 请求以指导 OBEX 客户机改变工作目录(类似于 cd 命令)。SETPATH 操作后面通常跟着一个 GET 或 PUT 操作。要终止 OBEX 会话,客户机需要发送 DISCONNECT 操作。如果成功,OBEX 服务器会用成功响应代码 160 进行响应。
现在对于 OBEX 的语义有了良好的理解,让我们看看在 JSR-82 API 中,Java 语言、蓝牙和 OBEX 是如何放在一起的。我先从服务器代码开始,因为客户机代码更复杂。
创建 OBEX 服务器应用程序
我的服务器应用程序叫做 FileServer.java ,而且因为 “重要事情优先”,所以我们先来看清单 1 中的 import 语句和类声明。
清单 1. import 语句和类声明
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.microedition.io.*;
import java.io.*;
import javax.bluetooth.*;
import javax.obex.*;
public class FileServer extends ServerRequestHandler
implements ActionListener{
|
如果想创建 OBEX 服务器,就需要扩展 javax.obex.ServerRequestHandler 类。因为这个示例是 J2SE 应用程序,所以我还想实现 ActionListener 接口,这样就能响应按钮点击。当用户点击启动服务器的按钮时,就会调用 actionPerformed() 方法(如清单 2 所示)。
清单 2. FilesServer.actionPerformed()
public void actionPerformed(ActionEvent e) {
startButton.setEnabled(false);
try {
UUID uuid = new UUID("8841", true);
String url = "btgoep://localhost:" + uuid
+ ";name=FTP;authenticate=false;master=false;encrypt=false";
SessionNotifier sn = (SessionNotifier)Connector.open(url);
updateStatus("[server:] Now waiting for a client to connect");
sn.acceptAndOpen(this);
updateStatus("[server:] A client is now connected");
} catch (Exception ex){
}
}
|
机器上的每台蓝牙设备都需要惟一的标识符,所以我决定将这个服务的 UUID (统一惟一标识符)定为 8841 (可以是任意四位数字)。在创建客户机应用程序时需要记住这个 UUID。
因为正在创建 JSR-82 服务器应用程序,所以需要调用 Connector.open() 并传递进 String ,其中包含服务的 URL。因为这是一个 OBEX 应用程序,所以采用的协议是 btgoep 。而且,也可以看到服务被命名为 “FTP”(也可以取其他的名称)。
FileServer.java 是一个 OBEX 服务器应用程序,这意味着 OBEX 客户机将发送 OBEX 操作,例如 CONNECT 、GET 、PUT 等等。所以,类需要恰当地处理客户机将要发送的每个操作(或者我想要处理的操作)。所以,在 FileServer.java 中,我包含了 onPut() 、onConnect() 和 onDisconnect() 方法的实现。我可能还创建了 onGet() 的实现,但是因为只想从客户机向服务器发送简单文件,所以实现 onGet() 并不是必需的,而只需要实现 onPut() 方法。
清单 3 演示了 onConnect() 和 onDisconnect() 的实现。可以看到,onConnect() 要求一个 int 返回值,但是 onDisconnect() 不返回内容,因为不需要。
清单 3. FilesServer.onConnect() 和 FilesServer.onDisconnect()
public int onConnect(HeaderSet request, HeaderSet reply) {
updateStatus("[server:] The client has created an OBEX session");
return ResponseCodes.OBEX_HTTP_OK;
}
public void onDisconnect (HeaderSet req, HeaderSet resp) {
updateStatus("[server:] The client has disconnected the OBEX session");
}
|
现在来看允许 FileServer.java 在客户机发送 PUT 请求时从客户机接收文件的代码段。onPut() 的代码如清单 4 所示。
清单 4. FilesServer.onPut()
public int onPut (Operation op) {
try {
java.io.InputStream is = op.openInputStream();
updateStatus("Got data bytes " + is.available() + " name "
+ op.getReceivedHeaders().getHeader(HeaderSet.NAME) +
" type " + op.getType());
File f =
new File((String)op.getReceivedHeaders().getHeader(HeaderSet.NAME));
FileOutputStream fos = new FileOutputStream (f);
byte b[] = new byte[1000];
int len;
while (is.available() > 0 && (len = is.read(b)) > 0) {
fos.write (b, 0, len);
}
fos.close();
updateStatus("[server:] Wrote data to " + f.getAbsolutePath());
} catch (Exception e) {
e.printStackTrace();
}
return ResponseCodes.OBEX_HTTP_OK;
}
|
正如我前面说的,清单 4 的代码显示了 OBEX 服务器如何从远程蓝牙设备接收文件。您可能会注意到可以得到传输的文件的名称,在这个示例中,在实例化 File 对象时使用到了文件名称。
结束语
在这篇文章中,我介绍了开始创建使用 OBEX 协议的 Java 蓝牙应用程序的许多基础知识。您学习了对于数据传输什么时候选择 OBEX 比 RFCOMM 更合适。阅读完这篇文章时,您应当很好地掌握了 OBEX 应用程序需要的语义的知识。
在这个系列的第 2 部分中,我将介绍如何创建能够与这里创建的服务器应用程序正确通信的客户机应用程序。当您很好地理解了客户机代码之后,我将对客户机代码稍做修改,创建一个蓝牙音乐商店。
参考资料
学习
获得产品和技术
关于作者
|
|
|
Bruce Hopkins 是 Bluetooth for Java (Apress)的作者,也是 JB-22 开发包的创建者。他毕业于底特律的 Wayne 州立大学,拥有电子和计算机工程学士学位。他目前是 Gestalt LLC 的技术架构师,专攻分布式计算、Web 服务和无线技术。您可以通过他的电子邮件 bhopkins@gestalt-llc.com 与他联系。
|
|
相关推荐
JSR-82支持蓝牙的基本服务,如对象传输服务(OBEX)和文件传输服务,使得应用程序可以方便地发送和接收文件。 以下是一些关键的JSR-82概念: 1. **LocalDevice**: 表示本地蓝牙设备,可以通过`LocalDevice....
标题中的“简单的蓝牙通讯代码...总结来说,这个主题涉及到使用J2ME平台和蓝牙API(JSR-82)来创建能够进行设备间通信的应用程序,特别是通过OBEX协议交换数据。开发者可以通过分析bexDemo示例,学习如何实现这一功能。
JSR-82是Java Community Process发布的一个标准,它定义了Java语言中的蓝牙API,使得开发者能够利用这些接口在支持蓝牙的设备上进行编程。JSR-82包括了蓝牙设备的发现、连接、数据传输以及服务搜索等功能。 4. **...
在Java中,蓝牙API主要由Java Micro Edition (Java ME) 的JSR-82规范定义,同时也被部分Java Standard Edition (Java SE) 的实现所支持。本文将深入探讨Java蓝牙API的基本概念、核心组件以及如何进行蓝牙功能的调用...
2. **蓝牙Java API (JSR-82)**:引入了OBEX支持,提高了蓝牙功能的完整性和可用性。 3. **无线消息API (JSR-120)的增强**:改善了消息传递机制,提高了消息发送和接收的效率。 4. **Java MIDP的可缩放UI效果**:与...
8.2 JSR-82:Java API for Bluetooth,允许开发者集成蓝牙功能。 8.3 JSR-179:Location API,提供对GPS和其他位置服务的访问。 **九、J2ME应用发布与分发** 9.1 JAD文件:描述MIDlet Suite的元数据,包括版本、...
开发者可以通过分析和运行“BCExchanger”代码,了解并学习如何在J2ME环境中实现蓝牙OBEX通信,从而在手机和电脑之间进行文件传输或其他数据交互。这种技术在早期移动设备中尤其有用,因为它们通常不支持其他高速...
一旦找到目标设备和服务,客户端便能建立连接,创建输入/输出流进行文件传输。服务端则需监听连接请求,等待客户端的连接。 对于手机文件传输软件的具体实现,服务端的构建是核心。首先,我们需要获取LocalDevice...
8. **File Transfer Profile (FTP)**: 文件传输配置文件,支持文件的上传和下载。 9. **Basic Imaging Profile (BIP)**: 基本成像配置文件,支持图像数据的传输。 10. **Basic Printing Profile (BPP)**: 基本打印...
javax.bluetooth是核心包,包含了与蓝牙设备交互的基础接口和类,而javax.obex则专注于对象交换协议,用于蓝牙设备间的文件传输和其他数据交换。 JSR 82规范是Java Bluetooth API的基础,它定义了蓝牙控制中心(BCC)...
蓝牙技术的应用非常广泛,例如蓝牙耳机、文件传输、数据通信等。 #### 二、JSR082及BlackBerry蓝牙支持 BlackBerry操作系统支持两种蓝牙通信方式:一是JSR082(Java Specification Request 082),二是BlackBerry...
蓝牙技术基于一种协议,可以进行多种应用,比如支持文件传输和对象推送。对象交换协议(OBEX)是一种面向应用的会话层协议,用于设备间对象交换。它运行在蓝牙协议之上,支持包括文件和图像在内的多种数据类型的交换...
6. **文件传输与对象推送**:探讨如何通过蓝牙进行文件传输和对象推送,如使用OBEX(Object Exchange)协议来发送和接收文件。 7. **蓝牙低功耗(Bluetooth Low Energy, BLE)**:随着蓝牙技术的发展,BLE成为低功耗...