作者:
caigao@hotmail.com2004-7
J2ME应用程序已经
我在应用开发过程中,常常用到J2ME的网络应用,但限于J2ME无线设备的能力,我们不得不在可用性和性能之间作出选择,因此,我做了以下的试验,并由此总结出一点结论,以方便后来者不必再走弯路。
我的应用主要功能是测试J2ME设备的网络连接性能,因此,其他方面的测试概不涉及。
我们知道,J2ME的通用连接框架为我们提供了http/socket/数据报/本地文件/线外等连接方式,但由于具体设备实现不同而导致程序开发方面的不便。举例来说,J2ME 的 MIDP 1.0版本中没有规定socket是必须的,但到了MIDP 2.0 socket才成为必须实现的协议。因此,现阶段大多数流行的设备都没有socket连接,这给我们编程带来了不利因素。在我们的测试程序中,SOCKET测试采用了StreamConnection类来建立连接,而走的是socket协议。分析一下程序即可知。
本文涉及了多种协议情况下的数据上传与下载,中文上传下载处理及网络传输计时、数据加密解密等方面的内容。为了做到通用,我在该程序的实现中没有用到特定设备的类。
本文给出的测试数据中第一个是建立连接所使用的时间,其余9项是连接建立后的数据传送时间。最后一项是前面9项数据的平均值。
测试结果数据比较:
机型,所用时间(秒),连接次数
- SUN WTK 模拟器
HTTP 1.391 0.188 0.625 0.141 0.141 0.391 0.313 0.204 0.375 0.484 0.318
SOCK 0.500 0.531 0.157 0.531 0.360 0.172 0.313 0.641 0.437 0.266 0.378
- Nokia6610
HTTP 4.258 1.682 1.612 1.373 2.681 1.820 1.264 1.512 1.919 1.808 1.741
SOCK 未通过
- Nokia 7650
HTTP 7.812 2.790 2.641 2.500 2.630 3.922 2.438 2.672 2.219 2.594 2.712
SOCK 1.719 1.312 1.609 3.359 3.360 1.375 1.781 3.313 1.250 1.329 2.076
- Nokia 6600
HTTP 3.937 1.984 2.172 1.641 1.500 1.531 2.125 1.906 1.843 2.156 1.873
SOCK 3.188 1.281 1.406 1.266 1.833 1.688 1.719 1.688 1.625 1.703 1.579
- 索爱P802
HTTP 7.484 1.484 1.500 1.859 1.485 1.500 1.938 1.781 1.938 1.701 1.687
SOCK 1.360 1.328 1.281 1.625 1.406 1.592 1.140 1.281 1.312 1.297 1.362
从以上数据分析,我认为:
1、 每一款机器每一种连接方式在同一时刻的网络连接速度波动都较大,即每一次连接都可能有导致网络连接滞后的不确定因素;
2、 无论哪一种连接方式,无线设备的网络连接速度比PC连接要慢;
3、 当前网络连接的时间超过了
游戏者可接受的延迟,不适合做实时或即时性操作;
4、 随着中国移动EDGE的上线,或者联通公司的CDMA1X普及,实时性手机应用将会得到发展,但仍需要进一步测试;
5、 在无线应用网络连接术语中有呼叫建立延迟(Call Setup latency)和通话信号传输延迟(Intra-call latency)两种,从以上数据可以看出,第一种延迟要比后一种延迟要明显一些,即第一次连接时用户需要等待更多的时间;
以下是本文的代码片断:
-
- public class Game extends MIDlet implements CommandListener {
- private Display display;
- private Form fmHTTP;
- private Form fmHTTP2;
- private Form fmStream;
- private Form fmSocket;
- private Command cmdTest = new Command("测试", Command.BACK, 0);
- private Command cmdStream = new Command("STREAM", Command.ITEM, 1);
- private Command cmdSocket = new Command("SOCKET", Command.ITEM, 2);
- private Command cmdHTTP = new Command("HTTP", Command.ITEM, 3);
- private TestThread testThread;
- public Game() {
- display = Display.getDisplay(this);
-
- fmHTTP = new Form("1.HTTP测试");
- fmHTTP.addCommand(cmdStream);
- fmHTTP.addCommand(cmdSocket);
- fmHTTP.addCommand(cmdHTTP2);
- fmHTTP.addCommand(cmdExit);
- fmHTTP.setCommandListener(this);
- fmHTTP.append("HTTP协议网络测试工具用于检测手机是否具备HTTP网络连接能力。第一行数据是由服务器产生的,经过UTF编码和DES加密传输到手机上的。");
-
- fmStream = new Form("3.STREAM测试");
- fmStream.addCommand(cmdHTTP);
- fmStream.addCommand(cmdHTTP2);
- fmStream.addCommand(cmdSocket);
- fmStream.setCommandListener(this);
- fmStream.append("STREAM网络连接是走的socket端口,对应的服务器端口是10000。");
- testThread = new TestThread(getAppProperty("Server").toLowerCase().trim());
- }
-
-
- class TestThread implements Runnable {
- private String server;
- private String message;
- private Form curForm;
- private int responseCode;
- private InputStream is2;
- private HttpConnection conHttp;
-
-
- private String keyOptimize;
- private HttpConnection conOptimize;
-
- public TestThread(String server) {
- this.server = server;
- }
-
- public void start(Form curForm) {
- this.curForm = curForm;
- Thread t = new Thread(this);
- t.start();
- }
-
- public void run() {
- message = "";
- long start,timeused;
- int formid = Integer.parseInt(curForm.getTitle().substring(0,1));
- start = System.currentTimeMillis(); //网络用时测试起点
- if (formid==1) { //1.HTTP测试
- try {
- String key = genPassword(); //产生8位的随机字符串密码,用于返回给服务器进行DES加密
- conHttp = (HttpConnection) Connector.open("http://" + server + ":8080/ns/hellodes?r=" + key);
- responseCode = conHttp.getResponseCode();
- if (responseCode==HttpConnection.HTTP_OK){
- InputStream is = conHttp.openInputStream();
- int len = (int) conHttp.getLength();
- byte[] bytestr = new byte[len];
- is.read(bytestr); //直接从输入流中读取字节,
- cipher = new DesCipher(key.getBytes());
- for (int i = 0; i < bytestr.length / 8; i++) {
- cipher.decrypt(bytestr, i * 8, bytestr, i * 8); //解密;
- }
- message = gbDecode(new String(bytestr)); //解码
- is.close();
- is = null;
- }else{
- message = "服务器无法连接!" + responseCode;
- }
- } catch (Exception e) {
- message = e.getMessage();
- }
- } else if (formid==3) { //3.STREAM测试
- try {
- conStream = (StreamConnection) Connector.open("socket://" + server + ":10000", Connector.READ_WRITE);
- InputStream is = conStream.openInputStream();
- byte[] outs = new byte[20];
- int len = 0, ch;
- while ((ch = is.read()) != -1) {
- outs[len] = (byte) ch;
- len++;
- }
- byte[] bytestr = new byte[len];
- System.arraycopy(outs, 0, bytestr, 0, len);
- message = gbDecode(new String(bytestr));
- is.close();
- is = null;
- } catch (Exception e) {
- message = e.getMessage();
- }
- } else if (formid==4) { //SOCKET测试
- /*
- try {
- sck = (SocketConnection)Connector.open("socket://"+server+":10009",Connector.READ_WRITE);
- sck.setSocketOption(SocketConnection.LINGER,5);
- dis = sck.openDataInputStream();
- message = dis.readUTF();
- dis.close();
- sck.close();
- dis = null;
- sck = null;
- } catch (Exception e) {
- message = e.getMessage();
- }
- */
- message = "SOCKET连接只能在MIDP2.0中使用";
- }
- timeused = System.currentTimeMillis() - start;
- curForm.append(message+"");
- message = "网络用时 " + timeused / 1000 + "." + timeused % 1000 + "";
- curForm.append(new StringItem(null,message)); //HTTP连接结果为1.6-1.9秒之间
- }
- private String alpha =
- "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- private String genPassword() {
- StringBuffer tmpstr = new StringBuffer(8);
- int iRandNum;
- Random rnd = new Random();
- for (int i = 0; i < 8; i++) {
- iRandNum = Math.abs(rnd.nextInt()) % 62;
- tmpstr.append(alpha.substring(iRandNum, iRandNum + 1));
- }
- return tmpstr.toString();
- }
-
- private String gbDecode(final String dataStr) {
- int start = 0;
- int end = 0;
- final StringBuffer buffer = new StringBuffer();
- while (start > -1) {
- end = dataStr.indexOf("\\u", start + 2);
- String charStr = "";
- if (end == -1) {
- charStr = dataStr.substring(start + 2, dataStr.length());
- } else {
- charStr = dataStr.substring(start + 2, end);
- }
- char letter = (char) Integer.parseInt(charStr, 16); // 16进制parse整形字符串。
- buffer.append(new Character(letter).toString());
- start = end;
- }
- return buffer.toString();
- }
- }