苗振兴 (安徽工程大学计算机与信息学院,安徽 芜湖241000)
马幼鸣 (北京理工大学信息与电子学院,北京100081)
周鸣争 (安徽工程大学计算机与信息学院,安徽 芜湖241000)
智能手机除了基本的通话功能以外,还具备PDA的主要功能,包括办公、上网、学习、游戏等。智能手机之间的通信除了移动运营商提供的GPRS或3G方式以外,通常还有红外、蓝牙和WiFi方式,而这3种通信方式中目前最常用于手机之间直接互传文件的仍然是蓝牙。蓝牙技术 (Bluetooth,802.15标准)是一种短距离无线通信技术,其传输最大速率为1Mb/s,最远传输距离为10m。然而,智能手机硬件性能的提高和存储容量的提升日新月异,蓝牙的传输效率就难以满足用户日益增长的使用需求。无线局域网的WiFi技术[1](Wireless Fidelity,802.11b标准)也是一种用于短距离无线网络传输的标准,相对于蓝牙技术,WiFi有着更加强大的优势,主要表现在传输速度更快和传输距离更远。如今WiFi技术已经不仅用于电脑的联网方式,它同时也被集成于各种终端设备中,用于互联网的连接。如果能够实现用WiFi替代蓝牙的短距离文件传输功能,将会给用户带来焕然一新的体验,同时推动WiFi在终端设备中更加广泛的应用。
作为目前最受欢迎的智能手机操作系统,Android OS[2]是一个应用非常广泛的平台,除了智能手机之外,搭载该系统的设备还包括平板电脑、智能相机、智能电视机等,故在该平台下实现通过WiFi方式的文件传输系统更具有实际意义。
正如蓝牙传输的方案一样,该系统首先也要将2部设备之间建立起点对点的连接,连接方式为WiFi无线局域网[3]。Android智能手机上都配置有WiFi扫描连接的功能,只要在手机上建立无线AP,另一部手机就可以连接到这个WiFi网络与之组成一个无线局域网。目前已有部分手机支持无线AP的建立,系统没有集成该功能的手机同样可以通过安装第三方软件的方式实现。然后,在该局域网中就通过Socket进行通信,通信规则按照自定义的一套协议就可以实现文件的传输与管理等功能。系统分为服务端和客户端2个部分,分别运行于多台手机之上。服务端只有一个,客户端可以有多个,根据Android的多线程可以同时进行多个客户端的操作,客户端软件作为人机交互的主要操作界面,服务器会自动解析用户的指令并作出响应。最后将软件打包为安卓程序安装包 (Android package,Apk)的格式,以便安装使用。Apk是一种压缩格式,它包含由Java类编译后的二进制文件集合dex文件和程序使用的图片、音频、配置文件、界面布局文件、C/C++静态库等资源文件。
Android OS是Google公司最新推出的面向下一代以移动互联网业务为核心的智能终端开源平台,它本身是一套软件堆层 (Software Stack),堆层的具体构成框架如图1所示。其中,标准库包括Android封装好的核心类库以及Java语言API中的基本类库;Dalvik虚拟机是谷歌改进的Java虚拟机,是基于寄存器的而不是传统的基于栈的虚拟机,它同时改进了内存资源使用的优化以及支持多个虚拟机的特点,Android系统下的每一个程序在运行时都有一个Dalvik虚拟机的实例;应用程序框架层,封装了Android应用程序开发所需要用到的API,为开发者提供可重用的组件;应用层是Android系统的表面层,负责用户与手机之间的可视化交互,集成了Android OS堆层的具体构成框架Android的所有核心应用程序与开发者开发的应用程序。由图1可见,应用程序虽然表面是用Java语言写的,但当涉及到本地库或者内核层时,便会用到JNI技术调用本地程序,也就会编译成NDK应用程序。
Android软件开发平台的安装支持3种主流操作系统:Windows、Mac OS和Linux。笔者选择Linux系统,因为Linux下可以更方便使用编译工具,如NDK[4]。安装Android的开发平台,首先要在官网下载Android SDK,这个开发包中包含了各种必备的调试命令和应用程序的API;然后下载较新版本的Eclipse,并且给它安装Android的开发插件ADT;由于Eclipse用于编写和编译Java代码,故Linux系统必须安装好Java环境;然后在官网下载NDK工具;最后配置一下Linux的环境变量就完成了开发环境的搭建。
图1 Android OS堆层的具体构成框架
软件设计结构采用MVC模式来进行构建 (见图2)。模型是应用程序的主体部分,代表了业务数据和业务逻辑,当数据发生改变时,它负责通知视图部分。由于同一个模型可以被多个视图重用,所以提高了应用的可重用性。视图是用户看到并与之交互的界面,它向用户显示相关的数据,并能接收用户的输入数据,但是它并不进行任何实际的业务处理。视图能接受模型发出的数据更新事件,从而对用户界面进行同步更新,还可以向模型查询业务状态,但不能改变模型。控制器负责逻辑处理、控制实体数据在视图上展示、调用模型处理业务请求。
在Android程序开发过程中,控制部分采用Java语言编写,针对不同的数据模型和控制程序可以定义在不同的包中。另外,Android对数据的存储方式[5]有Shared Preference、Content Provider和SQLite等来屏蔽底层具体的存储细节,从而使应用系统具有良好的数据迁移性。视图层则可以通过定义XML文件的方式来设计用户界面。用户界面通常设计为触摸、按键和其他感应器共同操控的交互方式。由于每一个Xml布局文件都是单独编写的文件,故与数据模型和控制部分完全分离,提高 了程序的易读性和可重用性。
图2 客户端MVC结构图
Socket通信是采用客户机/服务器(Client/Server) 的 工 作 模 式[6], 利 用Socket网络通信接口来实现客户机和服务器的通信。Socket接口是TCP/IP网络的API,它在OSI(开放式系统互联参考模型)中主要集中在传输层和会话层。Socket通常也称为 “套接字”,用于描述IP地址和端口,是一个通信连接句柄,应用程序的通信是通过Socket向网络发出请求或者应答网络请求。Socket根据所采用的协议可以分为面向连接和面向非连接2种操作方法,采用TCP/IP协议的Socket操作方法是面向连接的可靠通信;采用UDP协议的Socket操作方法是面向非连接的不可靠通信。由于面向连接的可靠通信方式更能保证客户机与服务器的数据同步性与一致性,故系统采用的是面向连接的方式。Android中提供了Socket和Server Socket 2个类,并实现了所有的Socket客户端和服务器双向连接。面向连接的Socket网络通信的实现流程如图3所示。
图3 面向连接的Socket网络通信的实现流程
在Socket网络通信的过程中,服务器端建立的初始状态是阻塞等待接收客户端的数据流,接收完之后返回数据流到客户端,故这种通信的模型必须是由客户端首先发起请求数据,然后与服务器之间形成数据往返循环进行的交互形式。这种交互必须建立在一套完整的通信协议之下才能保证数据传输的健全性与高效性。Java语言中的Socket数据流被封装成为输出流 (OutputStream)和输入流 (InputStream),传输的基本单位是字节,因此,通信协议的定义与传输的数据都被编排成字节数组的格式。对于字符串类型(String),由于在传输的文件名称包含中文字符时,必须用16位长度的编码格式,故笔者采用的是UTF-16LE的编码格式,这种格式下字符串中的字符占用2个字节,在Java语言中通过String.getBytes(“utf-16le”)方法将字符串中的字符依次转换成对应的字节,从而返回字符串对应的字节数组;通过new String(byteArray,“utf-16le”)的方法将字节数组中的字节依次转换成对应的字符,从而返回一个完整的字符串。对于整型数据类型 (Integer),在Java语言中占4个字节的长度,通过4次移位相与的方法转换成一个4个字节数组;同样地,对于一个整型数据转换成的4字节数组,也可以通过4次移位相与的方法转换成一个整型数据。对于文件的数据类型,在Android中可以通过FileInputStream和FileOutputStream的方法来构造文件输入流和文件输出流,这种数据流也是以字节为单位,故可以直接与Socket网络数据流对接,无需转换或包装。
在用户的操作过程中,以客户端作为主要人机交互端,它包含查看服务器的文件列表、进入文件夹、下载、发送和删除文件或文件夹等操作。服务器则被动地响应客户端的请求操作,但无需用户手动操作,它会自动循环解析客户端的请求指令,然后回复相应的返回指令和数据。指令是一个由整型数字转换成的4字节数组,所有的指令所对应的数字代码都是唯一的。客户端的请求指令与服务器回复的指令所采用的格式是不同的。客户端发送的完整请求数据格式为:指令+数据长度+数据内容,其中数据长度也是一个整型数组转换成的4字节数组,它指示的是后面数据内容的长度,后面的数据内容可能是文件名称或者文件信息数据。服务端回复的完整数据格式为:回复指令+数据内容,其中回复指令为16字节的数组,它的格式为:指令+错误信息+结束符+数据长度,这4个部分都是4字节数组,错误信息指示服务器在作出回应过程中的错误类型 (没有错误回复0);结束符指示当前信息是第几条文件,当前文件路径返回1,结束返回0;数据长度指示后面的数据内容长度,可能是文件名称或者文件信息数据。
在Android编程中,对文件的操作仍然遵循Java语言中的方法。该系统对文件和文件夹的管理包括创建、删除、修改和传输,对文件夹的操作实际上是对其目录下的所有文件依次进行操作,其中操作最复杂的也是该系统最重要的部分便是文件的传输功能。由于在传输过程中,网络数据流和文件数据流都是以字节数组的形式包装的,而这些字节数组需要占用Dalvik虚拟机中大量的内存空间,当文件过大时,虚拟机就会因无法给对象分配足够的内存空间而导致内存溢出的错误。本设计对此问题采取了以下的解决方案:对文件的传输设定一个传输块,大小设定为5MB,若文件所占空间小于传输块,那么就可以一次读取或写入,不会引起内存溢出的问题;若文件所占空间大于传输块,则大文件按照传输块分成若干次分组发送或者接收,每组发送过后都要调用System.gc()方法来回收不用的内存空间。为了便于将一个文件分成多次读取或者写入内容,使用了RandomAccessFile类,这是一个支持断点续传的文件类,它建立在一个文件的基础上,创建的时候要申明读写权限,它可以直接读取或写入字节流,并可以设置标记,实现对文件的断点续传。
在文件的传输过程中,需要消耗大量的机器资源和时间,而Android系统对程序设置了一个响应时间,如果超出这个时间没有响应系统就会提醒用户关闭程序。由于人机交互界面视图工作在主线程,若在主线程处理大量的操作,就会出现界面无响应的现象,若使用子线程,必须用到Handler方法(Android中线程消息的管理者),才能间接访问到界面视图,增加了程序的复杂度。针对这种耗时长的操作Android系统设计了异步任务 (AsyncTask)的方法,异步任务的设计很好地解决了匿名线程存在的问题。对文件的传输操作都是放在异步任务中执行的,实现了友好的人机交互界面。
在Android应用程序开发中,应用程序对手机重要功能组件的访问有着严格的权限控制方法,对涉及到手机安全[7]的操作 (如使用电话和短信服务、访问网络或者内存等)以授权的方式控制。每一个Android工程目录下都有一个清单文件AndroidManifest.xml,清单可以定义应用程序及其组件的结构和元数据,包括软件安全模型中的访问权限控制。在清单中必须添加uses-permission标签来创建所需要的权限定义之后,程序才可以使用这些受保护的组件。在安装程序的时候,就会请求用户授权清单文件中设定的权限,当用户同意授权之后才可以安装运行程序。该系统所使用到的权限有:网络访问、WiFi状态访问、手机振动、内存卡访问以及唤醒锁的权限。权限解释:网络与WiFi权限用于访问无线局域网;手机振动用于提醒用户状态的改变;内存卡的访问是文件管理的前提;唤醒锁是为了防止系统进入休眠状态。
在Android平台下采用WiFi方式实现设备之间文件互传,大大提高了短距离通信的效率。不仅如此,该系统支持最低版本Android1.5平台,而目前市场上的Android设备所使用的系统版本基本在此版本之上,因此,该系统基本可以安装运行于所有的Android智能手机和平板电脑。智能终端上的WiFi应用日益广泛,相信不久的将来一定可以给广大的消费者带来更多便捷的服务。
[1]吴功宜 .计算机网络高级教程 [M].北京:清华大学出版社,2007:133-144.
[2]Google.Android official website [EB/OL].http://www.android.com/index.html,2012-09-05.
[3]张琨 .基于Android平台的WLAN解决方案 [D].济南:山东大学,2010.
[4]Google.Android NDK | Android Developers[DB/OL].http://developer.android.co m/tools/sdk/ndk/index.html,2012-09-05.
[5]Meier R.Android高级编程 [M].王鹏杰,霍建同 译 .北京:清华大学出版社,2010:187-209.
[6]蒋敏,单家芳,孔军 .基于socket的多平台通信研究 [J].计算机工程与应用,2005(36):135-141.
[7]Burns J.Developing secure mobile applications for android [DB/OL].http://www.isecpartner s.com/white-papers/,2012-09-05.