PDA应用系统数据传输

PDA数据传输功能的分析、实现

级别:初级

WangYanCheng (ybygjy#gmail.com), 作者/编者, ushayden, Inc

2010年12月22日

文章内容描述了实现应用系统数据的传输的一种方法,主要内容包括:

委托回调机制的应用 、 简单示例代码

一、场景描述

1、PDA应用程序系统环境:

Window CE 5.0 .Net Framework 2.0 支持WIFY、GPRS、红外、蓝牙等模块

2、服务器端应用系统环境:JavaEE典型Web应用系统

3、应用场景:

业务级别应用,包括:业务数据上传、下载、同步。 系统级别应用,包括:系统升级机制、系统运行日志上传、同步

4、目标要求:

对PDA设备通过WIFY方式进行数据采集、汇总、分发等业务操作。 需要支持同步/异步数据传输方式。

二、策略以及分析、实现思路

1、JavaEE应用系统:增加PDA管理专用功能模块,提供基于HTTP协议的访问入口。

2、PDA应用系统:封装通信数据传输功能模块,负责实现数据与外部系统的交互。

PDA应用系统数据传输
PDA应用系统数据传输
PDA应用系统数据传输
PDA应用系统数据传输
回页首

3、顺序图:

PDA应用系统数据传输
PDA应用系统数据传输
PDA应用系统数据传输
PDA应用系统数据传输
PDA应用系统数据传输
回页首

三、技术知识点

  • 事件处理机制与观察者模式
  • 事件委托回调机制
  • 字节流基础操作

四、实现

JavaEE部分

代码片断:
/** * dataTrans * @param request 请求头 * @param response 响应头 */ private void upload4PDA(HttpServletRequest request, HttpServletResponse response) { InputStream ins = null; try { ins = request.getInputStream(); ReadableByteChannel rbc = Channels.newChannel(ins); WritableByteChannel wbc = Channels.newChannel(System.out); ByteBuffer buffer = ByteBuffer.allocate(1024); int i = -1; do { i = rbc.read(buffer); buffer.flip(); wbc.write(buffer); buffer.clear(); } while (i != -1); } catch (IOException ioe) { ioe.printStackTrace(); } Date currDate = Calendar.getInstance().getTime(); DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); ResponseUtils.getInstance().doResponse(response, df.format(currDate)); } /** * 下载 * @param response response */ private void download4PDA(HttpServletResponse response) { OutputStream ous = null; try { ous = response.getOutputStream(); File file = new File("F://tools//java//install//jdk-6u23-ea-src-b01-jrl-30_aug_2010.jar"); WritableByteChannel rbc = Channels.newChannel(ous); response.setContentLength((int) file.length()); FileChannel fc = new FileInputStream(file).getChannel(); ByteBuffer buffer = ByteBuffer.allocate(512); while (fc.read(buffer) != -1) { buffer.flip(); rbc.write(buffer); buffer.clear(); } } catch (IOException ioe) { ioe.printStackTrace(); } finally { if (ous != null) { try { ous.close(); } catch (IOException ioe) { ioe.printStackTrace(); } } } }

注意事项:

可以通过request.getParameter("argName")方式取得请求地址传递的参数。 在处理接收流数据时类似FileUpload文件上传插件会失效,原因是虽然流是经由HTTP协议传递的,但是默认数据内容并不会被加上分割标记boundary。 详细参见RFC1867F
PDA应用系统数据传输
PDA应用系统数据传输
PDA应用系统数据传输
PDA应用系统数据传输
回页首

PDA部分

因为数据传输应用模块必须基于设备底层通信支持模块,所以针对特定场景会有不同策略的实现。这里只是描述了HTTP请求方式的一种简单实现

代码片断:
class InnerDataSwitchImpl { private DataSwitchMgr dtiInst; private String filePath; public InnerDataSwitchImpl(DataSwitchMgr dtiInst, String filePath) { this.dtiInst = dtiInst; this.filePath = filePath == null ? "C://bar.emf" : filePath; } public void uploadData() { try { System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(dtiInst.serverUrl); request.Method = "POST"; //request.ContentType = "application/x-www-form-urlencoded"; request.ContentType = "multipart/form-data"; request.AllowAutoRedirect = true; request.MaximumAutomaticRedirections = 10; System.IO.FileInfo fileInfo = new System.IO.FileInfo(this.filePath); request.ContentLength = fileInfo.Length; System.IO.Stream stream = request.GetRequestStream(); innerSendData(stream, fileInfo); stream.Flush(); stream.Close(); stream = request.GetResponse().GetResponseStream(); String tmpStr = innerReceiveData(stream); dtiInst.OnDataTransferNotify(new DataSwitchArgs(tmpStr, true)); stream.Close(); } catch { dtiInst.OnDataTransferNotify(new DataSwitchArgs(true, false)); } } public void downloadData() { System.IO.Stream fileStream = null; System.IO.Stream stream = null; try { System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(dtiInst.serverUrl); request.MaximumAutomaticRedirections = 10; request.Credentials = System.Net.CredentialCache.DefaultCredentials; request.Timeout = (3 * 60) * 1000; System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse(); int contentLen = (int)response.ContentLength; int flag = 0, addUp = 0; byte[] buffer = new byte[512]; stream = response.GetResponseStream(); fileStream = System.IO.File.Create(this.filePath); while ((flag = stream.Read(buffer, 0, buffer.Length)) != 0) { fileStream.Write(buffer, 0, flag); addUp += flag; dtiInst.OnDataTransferNotify(new DataSwitchArgs(contentLen, addUp, true)); //因网络环境不同,所以这里要考虑延时策略.因为如果网络太好的情况,如:(localhost)呈现进度频率就非常高根本看不到。 do { flag++; } while (flag < 9999); flag = 0; } fileStream.Close(); dtiInst.OnDataTransferNotify(new DataSwitchArgs(0, 0, true)); } catch { dtiInst.OnDataTransferNotify(new DataSwitchArgs(true, false)); } finally { if (null != stream) { try { stream.Close(); } catch { } } if (null != fileStream) { try { fileStream.Close(); } catch { } } } } private void innerSendData(System.IO.Stream stream, System.IO.FileInfo fileInfo) { System.IO.FileStream readStream = fileInfo.OpenRead(); byte[] buffer = new byte[256];//限制内存占用 int flag = 0, finishCount = 0, totalCount = (int)fileInfo.Length; while ((flag = readStream.Read(buffer, 0, buffer.Length)) != 0) { stream.Write(buffer, 0, flag); finishCount += flag; dtiInst.OnDataTransferNotify(new DataSwitchArgs(totalCount, finishCount)); } readStream.Close(); } private String innerReceiveData(System.IO.Stream stream) { if (stream == null) { return String.Empty; } byte[] buffer = new byte[256]; int flag = 0; StringBuilder sbud = new StringBuilder(); Encoding encoder = UTF8Encoding.UTF8; while ((flag = stream.Read(buffer, 0, buffer.Length)) != 0) { sbud.Append(encoder.GetString(buffer, 0, flag)); } stream.Close(); return sbud.ToString(); } }
PDA应用系统数据传输
PDA应用系统数据传输
PDA应用系统数据传输
PDA应用系统数据传输
回页首

注意事项:

在单机测试的情况下,基本忽略数据传递延迟,要注意回调间隔。

测试截图

PDA应用系统数据传输
PDA应用系统数据传输
PDA应用系统数据传输
PDA应用系统数据传输
PDA应用系统数据传输
回页首

五、小结

通过使用委托机制可以容易的实现对某一资源状态的监听,委托机制的一个优点就是可以轻松实现异步方式。有时也会考虑到直接利用多线程机制完成类似功能,但那样程序复杂性、开发成本、相关投入都会提高。

1、实现源码下载

此文章是属于个人工作中对一些知识运用的总结,如有错误请直接指正,多多交流,谢谢。。