开发MIDP联网应用程序
扫描二维码
随时随地手机看文章
♦引言
在上讲中,我们介绍了如何利用RecordStore把数据保存在终端内。本讲,我们将阐述MIDPJAVA网络的相关功能。由于N800终端只能使用HTTP通信,所以我们将以HTTP为主要范例进行讲解。到目前为止,只能制作终端内的单机型应用程序,如果利用网络,连接网络服务器,那么就能够制作出多种应用程序。
1.利用网络
1.1.GenericConnectionFrameWork
J2ME应该能支持各种手机终端。由于终端不同其网络功能及文件I/O功能也迥然不同,网络和文件I/O关联的图书馆所需的条件也不同。
为了解决上述问题,JSME的CLDC采用了GenericConnectionframework。GenericConnectionframework拥有不同终端所需的省空间网络功能以及文件I/O功能。广泛应用J2SE的java.io和java.net包里的网络、文件I/O功能,并准备7个interface。这样,为能支持各种手机终端的通信功能,只限定interface,在每个手机终端上都能自由安装。不支持手机终端连接的实际安装不能进行。各种interface的说明如表1所示、层次结构如图1所示。
点击图片看大图
表1
图1
1.2.ConnectionInterface
Connectioninterface在GenericConnectionframework中是连接interface的基础interface。其他的连接interface是从Connectioninterface派生而来的。
1.3.Connector类
使用Connector类的static方法open(StringconnectString)入网。
Connectioncon=Connector.open("http://www.nec-mfriend.com/");
ex.1
例如、如ex.1所示,在open方法的自变量中输入“http://www.nec-mfiend.com/”,就可以实现与www.nec-mfriend.com服务器进行http通信。
而GenericConnectionframework的全部链接都是利用Connector类的open方法完成的。也就是说,即使链接类型不同,也能以同样的方法完成。J2ME由于这样的设计而拥有丰富的扩展性,对于上述新的装置它也配备了简单的支持系统。
按照下述形式指定Open方法的自变量。
{protocol}:[{target}][{params}]
在Protocol部分可以指定如下所示的Protocol。
表2
*N800不支持socket通信、数据电报通信,而N820支持socket通信。
在Target部分指定服务器的用户名、端口号和文件名等。若有必要的添加信息则在Params部分指定。
Open方法也可以指定其他的自变量。
staticConnectionopen(StringconnectString,intmode)
从connectString中制作Connection、打开链接,若要使用mode链接则需指定accessmode。在accessmode中,可以指定Connector.READ,Connector.READ_WRITE和Connector.WRITE,若不指定,则为Connector.READ_WRITE。在Protocol中不能指定accessmode时,则放弃IllegalArgumentException。
下表是其他Connector类的static方法。
1.4.HTTP通信
现在,我们对N800所支持的HTTP通信进行阐述。利用HTTP通信可以连接WEB服务器。例如,可以把手机终端难以处理的复杂问题交给WEB服务器处理,得出结果。HTTP通信采用MIDP方法作为标准,但是,采用MIDP作为基本方法的终端却不能进行HTTP通信,或者有很大的限制,这一点请注意。
为能在N800中使用HTTP通信需遵从以下规定。
•要实现MIDlet通信必须在JAD(ADF)文件中设定MIDlet-UseNetwork(参考3.JAD(ADF)文件)为YES。.
•最大发送量为10kbyte。
大于10kbyte时,超出部分被清除,小于10kbyte的数据才是有效的。
•最大接收量为100kbyte。
大于100kbyte时,超出部分被清除,小于100kbyte的数据才是有效的。
•连接处URL
从http://开始,包含http://,最多为512byte。不分大/小写。
HTTP通信由request和response两部分组成。从客户发出的request信息传到服务器,服务器接收request,返还response信息。
HTTP通信主要有下述三种request方式。
接下来,让我们试着用多种request与服务器进行通信。
1.5.利用GET
利用GET可以读取服务器上的文件。在使用GET之前,如下所示需在已完成的HttpConnection方法的setRequestMethod方法中,指定HttpConnection的static变数GET。
HttpConnectioncon=(HttpConnection)Connector.open("http://www.nec-mfriend.com/");
con.setRequestMethod(HttpConnection.GET);
ex.2
如下所示可以利用DataInputStream获取response。
Stringres="";
DataInputStreamin=con.openDataInputStream();
intinput;
while((input=in.read())!=-1){
res=res+(char)input;
}
in.close();
ex.3
以下实际是与服务器通信,获取html文件的sample。为简单介绍sample的操作,得把通信结果,即获取的html文件内容,输入控制台。因此,此sample是以在模拟器上面操作为前提的。
importjava.io.DataInputStream;
importjava.io.IOException;[!--empirenews.page--]
importjavax.microedition.io.Connector;
importjavax.microedition.io.HttpConnection;
importjavax.microedition.midlet.MIDlet;
importjavax.microedition.midlet.MIDletStateChangeException;
/**
*利用GET发送request的sample
*从控制台输出response
*/
publicclassGETTestextendsMIDlet{
/**
*访问服务器
*/
protectedvoidstartApp()throwsMIDletStateChangeException{
try{
HttpConnectioncon=(HttpConnection)Connector.open("http://www.nec-mfriend.com/en/");
//指定GET
con.setRequestMethod(HttpConnection.GET);
DataInputStreamin=con.openDataInputStream();
intinput;
while((input=in.read())!=-1){
System.out.print((char)input);
}
in.close();
//关闭链接
con.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
protectedvoidpauseApp(){
}
protectedvoiddestroyApp(booleanarg0)throwsMIDletStateChangeException{
}
}
ex.4
实际操作后的结果。
1.6.利用HEAD
接下来介绍如何利用HEAD方法获取文件的header。多数情况下,在HTTPheader中,包含了文件种类、尺寸大小、文字编码、回复日期、request文件的最后修改时间、以及兑现期限的截止日期等。一般来讲,使用HEAD方法检查其是否对兑现内容进行了新信息的替换。
为使用HEAD,如下所示要在作成的HttpConnection的setRequestMethod方法中,指定HttpConnection的static变量HEAD。
HttpConnectioncon=(HttpConnection)Connector.open("http://www.nec-mfriend.com/en/");
con.setRequestMethod(HttpConnection.HEAD);
获取HEAD信息的方法。
表3
下面是利用getHeaderField方法和getHeaderFieldKey方法,获取全部header信息的sample。这个sample与刚才所介绍的一样,是以在模拟器上进行操作为前提而作成的,它只用于说明,实际操作还没有进行测定。由此获取的全部header信息内容将输入控制台。
importjava.io.IOException;
importjavax.microedition.io.Connector;
importjavax.microedition.io.HttpConnection;
importjavax.microedition.midlet.MIDlet;
importjavax.microedition.midlet.MIDletStateChangeException;
/**
*利用HEAD发送request的sample
*从控制台输出response
*/
publicclassHEADTestextendsMIDlet{
/**
*显示header信息
*/
protectedvoidstartApp()throwsMIDletStateChangeException{
try{
HttpConnectioncon=
(HttpConnection)Connector.open("http://www.nec-mfriend.com/en/");
//指定HEAD
con.setRequestMethod(HttpConnection.HEAD);
//取得关键的HTTPheader信息——成对的值
inti=0;
Stringmessage="";
Stringkey="";
Stringvalue="";
while((value=con.getHeaderField(i))!=null){
key=con.getHeaderFieldKey(i++);
message=message+key+":"+value+"n";
}
System.out.println(message);
//关闭链接
con.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
protectedvoidpauseApp(){
}
protectedvoiddestroyApp(booleanarg0)throwsMIDletStateChangeException{
}
}
ex.5
实际操作后的结果如下所示。
图3
1.7.利用POST
为能利用POST发送request,要使用InputStream和OutputStream。用OutputStream向服务器发送数据,而InputStream则接收来自服务器的response。
用下述方法指定POST。
HttpConnectioncon=(HttpConnection)Connector.open("http://www.yahoo.com");
con.setRequestMethod(HttpConnection.POST);
ex.6
如下所示使用OutputStream在requeat信息中输入数据,使输入数据为(message=helloworld),而变量con是指定了POST的HttpConnection。
Stringmessage=乭message=helloworld乭;
DataOutputStreamdos=con.openDataOutputStream();
byte[]request=message.getBytes();
for(inti=0;i
dos.writeByte(request[i]);
}
dos.flush();
ex.7
下面实际是利用POST与服务器进行通信的sample。在这里,WEB服务器将转发利用POST发送的信息值,并接收最终结果response。接收的response内容将被输入控制台,请用模拟器进行确认。
importjava.io.DataInputStream;
importjava.io.DataOutputStream;
importjava.io.IOException;
importjavax.microedition.io.Connector;
importjavax.microedition.io.HttpConnection;
importjavax.microedition.midlet.MIDlet;
importjavax.microedition.midlet.MIDletStateChangeException;
/**
*利用POST发送request的sample[!--empirenews.page--]
*从控制台输出response
*/
publicclassPOSTTestextendsMIDlet{
/**
*利用POST送信息
*/
protectedvoidstartApp()throwsMIDletStateChangeException{
try{
HttpConnectioncon=(HttpConnection)Connector.open("http://localhost:8080/nec_server/servlet/ReverseServlet");
//指定POST
con.setRequestMethod(HttpConnection.POST);
//在request中输入数据
Stringmessage="message=helloworld";
DataOutputStreamdos=con.openDataOutputStream();
byte[]messageByte=message.getBytes();
for(inti=0;i
dos.writeByte(messageByte[i]);
}
dos.flush();
dos.close();
//接收response
DataInputStreamin=con.openDataInputStream();
intinput;
while((input=in.read())!=-1){
System.out.print((char)input);
}
in.close();
//关闭链接
con.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
protectedvoidpauseApp(){
}
protectedvoiddestroyApp(booleanarg0)throwsMIDletStateChangeException{
}
}
ex.8
接下来介绍本次使用的SERVLETsample,作为服务器实际安装的例子。因为本讲座是MIDP讲座,所以关于SERVLET的详细说明就不再赘述,网上有许多这方面的信息,请大家参考Sun—http://java.sun.com/products/servlet/等网站。
importjava.io.IOException;
importjava.io.PrintWriter;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
/**
*把接收的文字列进行转发的SERVLET
*/
publicclassReverseServletextendsHttpServlet{
/**
*处理postrequest
*/
protectedvoiddoPost(HttpServletRequestreq,HttpServletResponseres)
throwsServletException,IOException{
//接收参数
Stringmessage=req.getParameter("message");
//转发文字
Stringreverse="";
for(inti=message.length();i>0;i--){
reverse=reverse+message.charAt(i-1);
}
//写response
PrintWriterout=res.getWriter();
out.write("
n");
out.write("
n");
out.write("
n");
out.write("n");
out.write("
n");
out.write("messageis"+message+"
n");
out.write("ReverseMessageis"+reverse+"n");
out.write("
n");
out.write("");
out.close();
}
}
ex.9
实际操作如下所示:
2
2.制作应用程序
现在,我们介绍如何实际制作利用HTTP通信的应用程序。这次增添了以前所作的泡泡龙游戏(BlockApplication)的内容,并把游戏结束的时间作成高低分一览表,由服务器管理。为了使程序更简单,还省略了与声音相关的操作。以下是内容改变前的sourcecode:
给这个程序添加
•计算结束时间功能。 •向服务器发送时间表功能。 •从服务器接收最高分功能。 通过游戏或游戏结束时,显示出最高分。 为了计算Http通信和时间表,给实际变量添加以下变量: //相关经过时间 privateintsecond=0; privatelongstartMs; //http通信类 privatefinalStringSERVER_URL= "http://localhost:8080/nec_server/servlet/BlockScoreServlet";//服务器的UPL privateString[]highscore=null;//最高分 ex.10 2.1.计算结束时间 为了计算结束时间,要记录游戏开始时的系统时间(startMs),以这个时间为准计算经过时间,如下画面所示: /***************************************** *计时器相关处理 *****************************************/ /** *计算经过时间 */ publicintgetSecond(){ return(int)((System.currentTimeMillis()-startMs)/1000); } ex.11 2.2.向服务器发送时间表,接收最高分 如上所述,游戏结束时显示最高分。但是,游戏结束时向服务器发送时间表,而通过游戏时不发送时间表,只显示最高分。[!--empirenews.page--] 为在通过游戏时显示最高分,要与服务器进行通信,由此获得最高分。这里,可以用我们介绍的HttpConnection,利用GET取得最高分。可以在游戏结束时使用以下方法。 /** *与服务器进行通信,获取最高分。 */ publicString[]getHighScore(){ String[]str=newString[5]; HttpConnectioncon=null; DataInputStreamin=null; try{ con=(HttpConnection)Connector.open(SERVER_URL); //接收response in=con.openDataInputStream(); intinput; inti=0; Strings=""; while((input=in.read())!=-1){ if((char)input==‘n‘){ str[i]=s; i++; s=""; continue; } s=s+(char)input; } }catch(IOExceptione){ e.printStackTrace(); }finally{ if(con!=null){ try{ con.close(); }catch(IOExceptione1){ e1.printStackTrace(); } } if(in!=null){ try{ in.close(); }catch(IOExceptione1){ e1.printStackTrace(); } } } returnstr; } ex.12 下面是进行游戏时的操作。结束游戏时向服务器发送结束时间,即利用POST如下所示发送结束时间。然后,接收来自服务器的response最高分。可以在游戏结束时使用以下方法。 /** *向服务器发送时间表,取得最高分 */ publicString[]sendScore(){ String[]str=newString[5]; HttpConnectioncon=null; DataOutputStreamout=null; DataInputStreamin=null; try{ con=(HttpConnection)Connector.open(SERVER_URL); con.setRequestMethod(HttpConnection.POST); out=con.openDataOutputStream(); //向服务器发送时间表 Stringmessage="score="+second; byte[]messageByte=message.getBytes(); for(inti=0;i out.writeByte(messageByte[i]); } out.close(); //接收response in=con.openDataInputStream(); intinput; inti=0; Strings=""; while((input=in.read())!=-1){ if((char)input==‘n‘){ str[i]=s; i++; s=""; continue; } s=s+(char)input; } }catch(IOExceptione){ e.printStackTrace(); }finally{ if(con!=null){ try{ con.close(); }catch(IOExceptione1){ e1.printStackTrace(); } } if(out!=null){ try{ out.close(); }catch(IOExceptione1){ e1.printStackTrace(); } } if(in!=null){ try{ in.close(); }catch(IOExceptione1){ e1.printStackTrace(); } } } returnstr; } ex.13 2.3.显示最高分 通过游戏和游戏结束时,都显示最高分。用以下方法显示最高分: /** *显示最高分 */ publicvoidpaintHighScore(Graphicsg){ for(inti=0;i if(highscore[i]==null)break; g.drawString( highscore[i], 10, 10+i*15, Graphics.LEFT|Graphics.TOP); } } ex.14 2.4.运行 完成的sourcecode如下: •BlockApplication.java •BlockCanvas.java 另外,服务器使用的SERVLET的sourcecode式如下: •nec_server.zip 运行后的结果如下: 3.总结 本讲中,介绍了可以利用HTTP通信进行网络编程。利用本讲介绍的东西,能够制作简单的chat程序以及联网作战游戏等应用程序。请大家也试着制作一些新的独特的应用程序吧。