0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

蓝牙软件协议栈与手机文件传输软件的实现过程

电子设计 作者:电子设计 2018-11-09 09:05 次阅读

蓝牙(Bluetooth)是由东芝、爱立信、IBM、Intel和诺基亚等公司等于1998 年5 月共同提出的近距离无线数据通信技术标准。它能够在10 米的半径范围内实现单点对多点的无线数据和声音传输,其数据传输带宽可达到1Mbps.本文利用蓝牙技术开发一个用于手机文件数据传输的软件,具有即建即连、使用灵活、安全高效等特点,避免传统网络文件传输软件存在的问题。

1 蓝牙通信的关键技术

蓝牙无线电技术基于在工业、科学以及医学(ISM)上公用的2.45GHz 开放频段,这一频段无需授权并全球通用。当蓝牙设备互相连接时,他们将组成一个微微网(piconet),即以一个主设备和最大7 个从设备的形式动态创建网络。其私有化和个性化特征表现得尤为突出。

1.1 蓝牙协议栈

蓝牙协议栈提供了一组的高层协议和API 以完成发现服务和模拟串行I/O,还有一个关于包分割和重组的低层协议以及多路技术协议和质量服务。蓝牙协议栈分为硬件和软件两部分,蓝牙硬件协议栈由设备硬件提供,蓝牙软件协议栈则由软件实现。

蓝牙软件协议栈是程序开发中的关键部分,其层次从下至上依次是: 宿主控制器接口(HostController Interface,HCI) 是蓝牙软件协议栈的最底层,直接和宿主控制器接口固件(Host ControllerInterface Firmware)交互。逻辑链路控制和适配协议(Logical Link Control and Adaptation Protocol,L2CAP) 该层负责处理包分割重组,为上层协议提供了有保证的服务。服务发现协议(ServiceDiscovery Protocol,SDP)包含用于发现服务是否有效等操作。RFCOMM 位于L2CAP 之上,提供了模拟标准串口通信的能力。对象交换协议(Object Exchange Protocol,OBEX)用于实际程序中的对象数据交换。

蓝牙软件协议栈与手机文件传输软件的实现过程

图1 蓝牙协议栈

1.2 J2ME 对蓝牙的支持

早在JSR82 规范中就定义了javax.bluetooth 和javax.obex 两个包,其中javax.bluetooth 定义了与蓝牙通信相关的API , 而javax.obex(Object ExchangeProtocol)是建立在串口通信之上,实现以对象为单位的通信。在javax.bluetooth 中,Java 蓝牙API 可以被分解为三个部分:发现服务、设备管理和蓝牙通信,其主要类及接口有:本地蓝牙管理器LocalDevice、远程蓝牙设备RemoteDevice、搜索代理DiscoveryAgent、搜索侦听DiscoveryListener、描述蓝牙服务的特征属性ServiceRecord 及蓝牙服务属性的类型DataElement.

1.3 J2ME 平台下蓝牙通信流程

蓝牙软件协议栈与手机文件传输软件的实现过程

图2 蓝牙通信流程图

蓝牙通信也是基于通用连接框架,与常见的C/S架构类似,只是客户端不知服务端的存在,需要通过无线搜索去发现。搜索到远程设备后,还需要进行服务搜索去发现对方提供了哪些服务。

其中,蓝牙通信是基于通用连接框架,对不同客户端而言,需要通过搜索来获得与服务端的连接信息

蓝牙服务端使用连接通知者对象,用于等待远程设备的连接,类似于阻塞式socket 服务端,它将一直等待直到接收到客户端的连接请求。对于蓝牙客户端的搜索服务分为设备搜索和服务搜索,后者需要基于指定的远程设备才能进行。客户端和服务器端在获得蓝牙协议连接后,通过连接创建输入/输出流来进行通信。

2 手机文件传输软件的实现

2.1 蓝牙服务端的实现

2.1.1 获得本地设备管理器

获得本地设备管理器会导致系统提示是否需要启动蓝牙服务,该步骤是蓝牙设备通信最基本的初始化。

通过LocalDevice 类的getLocalDevice 方法即可获取本地设备管理器。

try {

localDevice = LocalDevice.getLocalDevice();

} catch (BluetoothStateException init) {

init.printStackTrace();

}

2.1.2 生成连接字符串

蓝牙通信协议的连接字符串有两种:一种用于串口通信;一种用于蓝牙链路通信(L2CAPConnection)。

其中串口通信的连接字符串格式为:

btspp://hostnAME:[CN|UUID];parameters.完整的蓝牙通信链接字符串的构造代码如下:

StringBuffer url = new StringBuffer("btspp://");

url.append("localhost")。append(':');

url.append(BTConfigure.FILES_SERVER_UUID.toString() ); //服务UUID

url.append(";name=FileServer"); //服务名称

url.append(";authorize=false"); //安全参数

2.1.3 通过连接字符串获得连接通知者(Notifier)

连接通知者类似阻塞式套接字的侦听过程。该对象只有在接收到远程设备请求时才会返回与该远程设备的连接,否则一直等待下去。

StreamConnectionNotifier notifier = null;

try { notifier = (StreamConnectionNotifier)

Connector.open(url.toString()); //获取流连接通知者

… … }

2.1.4 设置本地设备的服务记录属性

服务器向外界"暴露"本设备可提供的服务信息,客户端才可能获取到这些服务,并向服务端提出请求。

以下代码描述了服务端如何设置本地设备的服务记录。

//获取服务记录(用于添加和编辑服务记录)

record = localDevice.getRecord(notifier);

//设置服务记录属性(文件名)

DataElement fileName = new

DataElement(DataElement.STRING, FILE_NAME);

record.setAttributeValue(BTConfigure.FILES_NAMES_ATTR_ID, fileName);

2.1.5 通过Notifier 循环阻塞等待远程设备的连接

当有远程设备进行连接后,通过连接通知者获得连接对象。当接收到远程客户端设备的连接请求,首先获取到该客户端设备的地址信息,再启动服务线程进行连接的处理。这样对每一个客户端连接启用一个处理线程,可以避免多个客户端排队访问服务端的情形。

while(true) {

StreamConnection conn = null;

try { //等待接受客户端的连接

conn = notifier.acceptAndOpen();

} catch (IOException e)

{ e.printStackTrace(); continue; }

RemoteDevice remoteDevice = RemoteDevice.getRemoteDevice(conn); //获取远程设备

//启动服务线程

new BTServerThread(mainPanel, conn)。start();

}

2.1.6 服务端和客户端的通信

蓝牙服务端通信线程是整个服务端程序的核心。

每接收到一个客户端的请求,都将创建一个独立的线程来进行处理。通过连接对象创建输入/输出流,实现服务端和客户端的通信。当某一客户端处理完毕,服务端将关闭与该客户端的连接。

public void run() {

String fileName=readFileName(); //获取请求

sendFile(fileName); //发送答复

uninit(); //关闭连接

}

//从客户端读取文件名

private String readFileName() {

String fileName = null;

try { InputStream is = conn.openInputStream();

int length = is.read();

byte [] buffer = new byte[length];

is.read(buffer, 0, length);

fileName = new String(buffer); is.close();

} catch (IOException e) {

e.printStackTrace(); }

return (fileName); }

//发送文件数据

private void sendFile(final String fileName) {

InputStream is = null; byte [] buffer = null;

try {

is = getClass()。getResourceAsStream("/" +fileName); buffer = new byte[is.available() ];

is.read(buffer); is.close();

OutputStream os = conn.openOutputStream();

os.write(buffer.length 》 8);

os.write(buffer.length & 0xFF);

os.write(buffer); os.flush(); os.close();

} catch (IOException e) { e.printStackTrace(); }

}

//释放连接流

private void uninit() {

try { conn.close(); } catch (IOException e)

{ e.printStackTrace(); }

}

2.2 蓝牙客户端的实现

2.2.1 获得本地设备管理器

获得本地设备管理器,设置本地设备管理器的搜索模式,获取搜索代理实例,开始搜索远程设备。

public void run() { //设备搜索线程核心

try {

LocalDevice localDevice = LocalDevice. getLocal

Device(); //获取本地设备实例

localDevice.setDiscoverable(DiscoveryAgent.GIAC);

//得到搜索代理

discoveryAgent = localDevice.getDiscoveryAgent();

startDiscover(); //开始探索

} catch (BluetoothStateException init) {

init.printStackTrace(); } }

public void startDiscover() { //开始搜索

discoveryDevices.removeAllElements();

try {

discoveryAgent.startInquiry(DiscoveryAgent.GIAC, this); } catch (BluetoothStateException e)

{ e.printStackTrace(); } }

2.2.2 记录设备搜索结果

在搜索侦听的设备搜索事件中记录设备搜索结果。设备搜索事件是通过实现搜索侦听(DiscoveryListener)的接口来完成回调处理。

(DiscoveryListener)的接口来完成回调处理。

//搜索到设备

public void deviceDiscovered(RemoteDevice remoteDevice, DeviceClass deviceClass) //添加远程设备

{ discoveryDevices.addElement(remoteDevice); }

//设备搜索结束

public void inquiryCompleted(int discType) {

switch(discType) {

case //查询正常结束

DiscoveryListener.INQUIRY_COMPLETED:{

mainPanel.setDevices(discoveryDevices);

break; }

case //查询被取消

DiscoveryListener.INQUIRY_TERMINATED:

break;

case //查询错误

DiscoveryListener.INQUIRY_ERROR: {

mainPanel.showMsg("Inquiry error!!");

break; } } }

2.2.3 记录服务搜索结果

对指定的远程设备搜索其服务,在搜索侦听的服务搜索事件中记录服务搜索结果。服务搜索事件的处理也是通过实现搜索侦听接口来完成回调的。

// 服务搜索线程执行代码

public void run() { … …

try {

LocalDevice localDevice =LocalDevice.getLocalDevice(); //获取本地设备实例

localDevice.setDiscoverable(DiscoveryAgent.GIAC);

//得到搜索代理

discoveryAgent = localDevice.getDiscoveryAgent();

//开始搜索服务

discoveryAgent.searchServices(attrSet, uuidSet,remoteDevice, this);

} catch (BluetoothStateException init){

init.printStackTrace();

} }

// 搜索到服务

public void servicesDiscovered(int transID,

ServiceRecord[] servRecord) { //添加探索到的服务

for(int i = 0; i < servRecord.length; ++i)

serviceRecords.addElement(servRecord[i]);

}

2.2.4 建立与远程设备的连接

通过服务记录来获取连接字符串,并建立与远程设备的连接。客户端通过搜索到的服务记录来获取可供连接的URL,并与服务端进行连接。

// 客户端通信线程核心

public void run() {

//通过服务记录来获取建立连接的URL

String url = serviceRecord.getConnectionURL(

ServiceRecord.NOAUTHENTICATE_NOENCRYPT,false); … …

StreamConnection conn = null;

try { // 通过URL 建立连接

conn = (StreamConnection)Connector.open(url);

} catch (IOException open)

{ open.printStackTrace(); } }

2.2.5 实现服务端和客户端的通信

由连接对象获取输入/输出流,实现服务端和客户端的通信。请求处理完毕,关闭与该远程设备的连接。

客户端发起与服务端进行通信并从服务器获取图片。

// 发送文件名称请求并下载文件

sendFileName(conn, fileName);

downloadFile(conn, fileName);

try { conn.close(); }

catch (IOException close)

{ close.printStackTrace(); }

// 发送文件名请求

private void sendFileName(StreamConnection conn,

final String fileName) {

try { OutputStream out = conn.openOutputStream();

out.write(fileName.length() );

out.write(fileName.getBytes() );

out.flush(); out.close();

} catch (IOException write)

{ write.printStackTrace(); } }

// 下载文件

public void downloadFile(StreamConnection conn,final String fileName) {

byte [] buffer = null;

try { InputStream is = conn.openInputStream();

//头两个字节为数据长度

int length = (is.read() 《 8); length |= is.read();

buffer = new byte[length]; length = 0;

while (length != buffer.length) {

int n = is.read(buffer, length, buffer.length - length);

if (n == -1) throw new IOException("Can't

readdata");

length += n; }

is.close();

} catch (IOException read)

{ read.printStackTrace(); }

try { Image img = Image.createImage(buffer, 0,buffer.length);

mainPanel.appendImage(img);

} catch (Exception image) {

image.printStackTrace();

} }

3 手机文件传输软件的运行与测试

对软件打包后,利用手机安装管理程序将MIDlet应用程序从计算机下载到支持蓝牙技术的手机上,然后执行文件传输程序,在此可选择执行客户端或服务器端应用,如图3 所示。用户选择BT Server 开启服务器端程序,允许对蓝牙进行连接。在另外一手机上执行该程序,选择BTClient,进入文件传输的客户端模式,菜单中执行Search Devices 功能,进行本地蓝牙设备的搜索,结果如图4 所示。再执行Search Service功能,即搜索服务器中提供的服务,选中要下载的文件,执行Transport 进行文件传输,如图5 所示。

当下载的图像文件传输完毕,将其显示出来,如图6所示。

图3 BTDemo 主界面

图4 搜索蓝牙服务。

图5 获取Server 端资源。

图6 下载图像文件并显示。

4 结束语

支持JAVA 并具备蓝牙功能的手机,给软件业提供了新的机遇。本文开发一种以J2ME 为平台的蓝牙文件传输软件,可以进行有效的文件传输。为建立微微网中文件服务做了一定的尝试。在一定程度上拓展了手机的功能, 具有一定的应用价值。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 手机
    +关注

    关注

    34

    文章

    6721

    浏览量

    156009
  • 蓝牙
    +关注

    关注

    112

    文章

    5534

    浏览量

    166858
  • JAVA
    +关注

    关注

    19

    文章

    2921

    浏览量

    103387
收藏 人收藏

    评论

    相关推荐

    如何高效实现文件传输

    服务器提供文件传输功能,需要将磁盘上的文件读取出来,通过网络协议发送到客户端。如果需要你自己编码实现这个文件传输功能,你会怎么
    发表于 08-01 16:16 384次阅读
    如何高效<b class='flag-5'>实现</b><b class='flag-5'>文件传输</b>

    文件传输解决方案

    文件传输是一个通用术语,适用于通过计算机网络传输数据的行为,私有或公共。托管文件传输旨在促进文件传输,它是一种软件或服务,用于通过网络提供安
    发表于 07-18 07:34

    浅析Linux的ftp文件传输协议

    FTP 是 File Transfer Protocol (文件传输协议)的英文简称,而中文简称为“文传协议”。
    发表于 07-18 08:19

    蓝牙协议软件框架解析

    通俗易懂讲蓝牙协议软件框架
    发表于 01-04 07:06

    协议是什么 协议又是什么

    协议协议的具体实现形式, 通俗的理解就是用代码实现的函数库, 以便于开发人员调用。协议
    发表于 08-05 07:00

    蓝牙协议iAP和AAP区别

    (0x4de17a00-52cb-11e6-bdf4-0800200c9a66)需要在蓝牙协议配置文件中设置:AAP_ENABLE=1三,APP和iAP的区别:1.不需要授权芯片,可
    发表于 04-11 09:26

    不同协议间的手机软件移植

    研究手机软件在不同协议之间的可移植性,根据AT命令特性,提出一个有效的协议适配层实现框架,在
    发表于 04-14 09:24 14次下载

    蓝牙协议实现模式分析

    蓝牙技术是未耒无线通信的一个重要的研究方向。本文主要介绍了蓝牙技术的体系结构及其特点,并结合东芝公司生产的蓝牙协议产品BluetoothT
    发表于 08-21 09:50 62次下载

    实现CFDP协议延时NAK模式文件传输

    CFDP协议,其数据丢失与错误检测重传机制可以有效解决该问题。本文结合航天工程经验搭建空间数据管理系统,采用软硬件协同机制在空间数据传输链路中设计实现了CFDP协议延时NAK模式
    发表于 11-05 11:33 2次下载
    <b class='flag-5'>实现</b>CFDP<b class='flag-5'>协议</b>延时NAK模式<b class='flag-5'>文件传输</b>

    FeiQ局域网文件传输软件应用程序免费下载

    本文档的主要内容详细介绍的是FeiQ局域网文件传输软件应用程序免费下载。
    发表于 10-25 08:00 9次下载
    FeiQ局域网<b class='flag-5'>文件传输</b><b class='flag-5'>软件</b>应用程序免费下载

    基于UDP的简单文件传输协议TFTP设计

    前面我们已经实现了UDP的回环客户端和回环服务器的简单应用,接下来我们实现一个基于UDP的简单文件传输协议TFTP。
    的头像 发表于 12-14 15:06 1952次阅读
    基于UDP的简单<b class='flag-5'>文件传输</b><b class='flag-5'>协议</b>TFTP设计

    一般会如何实现文件传输?零拷贝如何提升文件传输性能?

    服务器提供文件传输功能,需要将磁盘上的文件读取出来,通过网络协议发送到客户端。
    的头像 发表于 07-26 14:43 767次阅读
    一般会如何<b class='flag-5'>实现</b><b class='flag-5'>文件传输</b>?零拷贝如何提升<b class='flag-5'>文件传输</b>性能?

    中文应用笔记《利用 MPLAB® Harmony v3 TCP/IP 协议在SAM E54 MCU上实现文件传输协议

    利用 MPLAB Harmony v3 TCP/IP 协议 在SAM E54 MCU上 实现文件传输协议 简介
    的头像 发表于 09-26 17:30 3826次阅读
    中文应用笔记《利用 MPLAB® Harmony v3 TCP/IP <b class='flag-5'>协议</b><b class='flag-5'>栈</b>在SAM E54 MCU上<b class='flag-5'>实现</b><b class='flag-5'>文件传输</b><b class='flag-5'>协议</b>》

    如何实现文件传输

    你会如何实现文件传输? 服务器提供文件传输功能,需要将磁盘上的文件读取出来,通过网络协议发送到客户端。如果需要你自己编码
    的头像 发表于 11-13 15:32 624次阅读
    如何<b class='flag-5'>实现</b><b class='flag-5'>文件传输</b>

    利用 MPLAB® Harmony v3 TCP/IP协议在SAM E54 MCU 上实现文件传输协议

    电子发烧友网站提供《利用 MPLAB® Harmony v3 TCP/IP协议在SAM E54 MCU 上实现文件传输协议.pdf》资料免
    发表于 12-18 11:03 0次下载
    利用 MPLAB® Harmony v3 TCP/IP<b class='flag-5'>协议</b><b class='flag-5'>栈</b>在SAM E54 MCU 上<b class='flag-5'>实现</b><b class='flag-5'>文件传输</b><b class='flag-5'>协议</b>