開發(fā)MIDP聯(lián)網(wǎng)應(yīng)用程序
掃描二維碼
隨時(shí)隨地手機(jī)看文章
♦引言
在上講中,我們介紹了如何利用RecordStore把數(shù)據(jù)保存在終端內(nèi)。本講,我們將闡述MIDPJAVA網(wǎng)絡(luò)的相關(guān)功能。由于N800終端只能使用HTTP通信,所以我們將以HTTP為主要范例進(jìn)行講解。到目前為止,只能制作終端內(nèi)的單機(jī)型應(yīng)用程序,如果利用網(wǎng)絡(luò),連接網(wǎng)絡(luò)服務(wù)器,那么就能夠制作出多種應(yīng)用程序。
1.利用網(wǎng)絡(luò)
1.1.GenericConnectionFrameWork
J2ME應(yīng)該能支持各種手機(jī)終端。由于終端不同其網(wǎng)絡(luò)功能及文件I/O功能也迥然不同,網(wǎng)絡(luò)和文件I/O關(guān)聯(lián)的圖書館所需的條件也不同。
為了解決上述問題,JSME的CLDC采用了GenericConnectionframework。GenericConnectionframework擁有不同終端所需的省空間網(wǎng)絡(luò)功能以及文件I/O功能。廣泛應(yīng)用J2SE的java.io和java.net包里的網(wǎng)絡(luò)、文件I/O功能,并準(zhǔn)備7個(gè)interface。這樣,為能支持各種手機(jī)終端的通信功能,只限定interface,在每個(gè)手機(jī)終端上都能自由安裝。不支持手機(jī)終端連接的實(shí)際安裝不能進(jìn)行。各種interface的說明如表1所示、層次結(jié)構(gòu)如圖1所示。
點(diǎn)擊圖片看大圖
表1
圖1
1.2.ConnectionInterface
Connectioninterface在GenericConnectionframework中是連接interface的基礎(chǔ)interface。其他的連接interface是從Connectioninterface派生而來的。
1.3.Connector類
使用Connector類的static方法open(StringconnectString)入網(wǎng)。
Connectioncon=Connector.open("http://www.nec-mfriend.com/");
ex.1
例如、如ex.1所示,在open方法的自變量中輸入“http://www.nec-mfiend.com/”,就可以實(shí)現(xiàn)與www.nec-mfriend.com服務(wù)器進(jìn)行http通信。
而GenericConnectionframework的全部鏈接都是利用Connector類的open方法完成的。也就是說,即使鏈接類型不同,也能以同樣的方法完成。J2ME由于這樣的設(shè)計(jì)而擁有豐富的擴(kuò)展性,對于上述新的裝置它也配備了簡單的支持系統(tǒng)。
按照下述形式指定Open方法的自變量。
{protocol}:[{target}][{params}]
在Protocol部分可以指定如下所示的Protocol。
表2
*N800不支持socket通信、數(shù)據(jù)電報(bào)通信,而N820支持socket通信。
在Target部分指定服務(wù)器的用戶名、端口號和文件名等。若有必要的添加信息則在Params部分指定。
Open方法也可以指定其他的自變量。
staticConnectionopen(StringconnectString,intmode)
從connectString中制作Connection、打開鏈接,若要使用mode鏈接則需指定accessmode。在accessmode中,可以指定Connector.READ,Connector.READ_WRITE和Connector.WRITE,若不指定,則為Connector.READ_WRITE。在Protocol中不能指定accessmode時(shí),則放棄IllegalArgumentException。
下表是其他Connector類的static方法。
1.4.HTTP通信
現(xiàn)在,我們對N800所支持的HTTP通信進(jìn)行闡述。利用HTTP通信可以連接WEB服務(wù)器。例如,可以把手機(jī)終端難以處理的復(fù)雜問題交給WEB服務(wù)器處理,得出結(jié)果。HTTP通信采用MIDP方法作為標(biāo)準(zhǔn),但是,采用MIDP作為基本方法的終端卻不能進(jìn)行HTTP通信,或者有很大的限制,這一點(diǎn)請注意。
為能在N800中使用HTTP通信需遵從以下規(guī)定。
•要實(shí)現(xiàn)MIDlet通信必須在JAD(ADF)文件中設(shè)定MIDlet-UseNetwork(參考3.JAD(ADF)文件)為YES。.
•最大發(fā)送量為10kbyte。
大于10kbyte時(shí),超出部分被清除,小于10kbyte的數(shù)據(jù)才是有效的。
•最大接收量為100kbyte。
大于100kbyte時(shí),超出部分被清除,小于100kbyte的數(shù)據(jù)才是有效的。
•連接處URL
從http://開始,包含http://,最多為512byte。不分大/小寫。
HTTP通信由request和response兩部分組成。從客戶發(fā)出的request信息傳到服務(wù)器,服務(wù)器接收request,返還response信息。
HTTP通信主要有下述三種request方式。
接下來,讓我們試著用多種request與服務(wù)器進(jìn)行通信。
1.5.利用GET
利用GET可以讀取服務(wù)器上的文件。在使用GET之前,如下所示需在已完成的HttpConnection方法的setRequestMethod方法中,指定HttpConnection的static變數(shù)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
以下實(shí)際是與服務(wù)器通信,獲取html文件的sample。為簡單介紹sample的操作,得把通信結(jié)果,即獲取的html文件內(nèi)容,輸入控制臺。因此,此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發(fā)送request的sample
*從控制臺輸出response
*/
publicclassGETTestextendsMIDlet{
/**
*訪問服務(wù)器
*/
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();
//關(guān)閉鏈接
con.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
protectedvoidpauseApp(){
}
protectedvoiddestroyApp(booleanarg0)throwsMIDletStateChangeException{
}
}
ex.4
實(shí)際操作后的結(jié)果。
1.6.利用HEAD
接下來介紹如何利用HEAD方法獲取文件的header。多數(shù)情況下,在HTTPheader中,包含了文件種類、尺寸大小、文字編碼、回復(fù)日期、request文件的最后修改時(shí)間、以及兌現(xiàn)期限的截止日期等。一般來講,使用HEAD方法檢查其是否對兌現(xiàn)內(nèi)容進(jìn)行了新信息的替換。
為使用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。這個(gè)sample與剛才所介紹的一樣,是以在模擬器上進(jìn)行操作為前提而作成的,它只用于說明,實(shí)際操作還沒有進(jìn)行測定。由此獲取的全部header信息內(nèi)容將輸入控制臺。
importjava.io.IOException;
importjavax.microedition.io.Connector;
importjavax.microedition.io.HttpConnection;
importjavax.microedition.midlet.MIDlet;
importjavax.microedition.midlet.MIDletStateChangeException;
/**
*利用HEAD發(fā)送request的sample
*從控制臺輸出response
*/
publicclassHEADTestextendsMIDlet{
/**
*顯示header信息
*/
protectedvoidstartApp()throwsMIDletStateChangeException{
try{
HttpConnectioncon=
(HttpConnection)Connector.open("http://www.nec-mfriend.com/en/");
//指定HEAD
con.setRequestMethod(HttpConnection.HEAD);
//取得關(guān)鍵的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);
//關(guān)閉鏈接
con.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
protectedvoidpauseApp(){
}
protectedvoiddestroyApp(booleanarg0)throwsMIDletStateChangeException{
}
}
ex.5
實(shí)際操作后的結(jié)果如下所示。
圖3
1.7.利用POST
為能利用POST發(fā)送request,要使用InputStream和OutputStream。用OutputStream向服務(wù)器發(fā)送數(shù)據(jù),而InputStream則接收來自服務(wù)器的response。
用下述方法指定POST。
HttpConnectioncon=(HttpConnection)Connector.open("http://www.yahoo.com");
con.setRequestMethod(HttpConnection.POST);
ex.6
如下所示使用OutputStream在requeat信息中輸入數(shù)據(jù),使輸入數(shù)據(jù)為(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
下面實(shí)際是利用POST與服務(wù)器進(jìn)行通信的sample。在這里,WEB服務(wù)器將轉(zhuǎn)發(fā)利用POST發(fā)送的信息值,并接收最終結(jié)果response。接收的response內(nèi)容將被輸入控制臺,請用模擬器進(jìn)行確認(rèn)。
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發(fā)送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中輸入數(shù)據(jù)
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();
//關(guān)閉鏈接
con.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
protectedvoidpauseApp(){
}
protectedvoiddestroyApp(booleanarg0)throwsMIDletStateChangeException{
}
}
ex.8
接下來介紹本次使用的SERVLETsample,作為服務(wù)器實(shí)際安裝的例子。因?yàn)楸局v座是MIDP講座,所以關(guān)于SERVLET的詳細(xì)說明就不再贅述,網(wǎng)上有許多這方面的信息,請大家參考Sun—http://java.sun.com/products/servlet/等網(wǎng)站。
importjava.io.IOException;
importjava.io.PrintWriter;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
/**
*把接收的文字列進(jìn)行轉(zhuǎn)發(fā)的SERVLET
*/
publicclassReverseServletextendsHttpServlet{
/**
*處理postrequest
*/
protectedvoiddoPost(HttpServletRequestreq,HttpServletResponseres)
throwsServletException,IOException{
//接收參數(shù)
Stringmessage=req.getParameter("message");
//轉(zhuǎn)發(fā)文字
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
實(shí)際操作如下所示:
2
2.制作應(yīng)用程序
現(xiàn)在,我們介紹如何實(shí)際制作利用HTTP通信的應(yīng)用程序。這次增添了以前所作的泡泡龍游戲(BlockApplication)的內(nèi)容,并把游戲結(jié)束的時(shí)間作成高低分一覽表,由服務(wù)器管理。為了使程序更簡單,還省略了與聲音相關(guān)的操作。以下是內(nèi)容改變前的sourcecode:
給這個(gè)程序添加
•計(jì)算結(jié)束時(shí)間功能。 •向服務(wù)器發(fā)送時(shí)間表功能。 •從服務(wù)器接收最高分功能。 通過游戲或游戲結(jié)束時(shí),顯示出最高分。 為了計(jì)算Http通信和時(shí)間表,給實(shí)際變量添加以下變量: //相關(guān)經(jīng)過時(shí)間 privateintsecond=0; privatelongstartMs; //http通信類 privatefinalStringSERVER_URL= "http://localhost:8080/nec_server/servlet/BlockScoreServlet";//服務(wù)器的UPL privateString[]highscore=null;//最高分 ex.10 2.1.計(jì)算結(jié)束時(shí)間 為了計(jì)算結(jié)束時(shí)間,要記錄游戲開始時(shí)的系統(tǒng)時(shí)間(startMs),以這個(gè)時(shí)間為準(zhǔn)計(jì)算經(jīng)過時(shí)間,如下畫面所示: /***************************************** *計(jì)時(shí)器相關(guān)處理 *****************************************/ /** *計(jì)算經(jīng)過時(shí)間 */ publicintgetSecond(){ return(int)((System.currentTimeMillis()-startMs)/1000); } ex.11 2.2.向服務(wù)器發(fā)送時(shí)間表,接收最高分 如上所述,游戲結(jié)束時(shí)顯示最高分。但是,游戲結(jié)束時(shí)向服務(wù)器發(fā)送時(shí)間表,而通過游戲時(shí)不發(fā)送時(shí)間表,只顯示最高分。[!--empirenews.page--] 為在通過游戲時(shí)顯示最高分,要與服務(wù)器進(jìn)行通信,由此獲得最高分。這里,可以用我們介紹的HttpConnection,利用GET取得最高分??梢栽谟螒蚪Y(jié)束時(shí)使用以下方法。 /** *與服務(wù)器進(jìn)行通信,獲取最高分。 */ 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 下面是進(jìn)行游戲時(shí)的操作。結(jié)束游戲時(shí)向服務(wù)器發(fā)送結(jié)束時(shí)間,即利用POST如下所示發(fā)送結(jié)束時(shí)間。然后,接收來自服務(wù)器的response最高分??梢栽谟螒蚪Y(jié)束時(shí)使用以下方法。 /** *向服務(wù)器發(fā)送時(shí)間表,取得最高分 */ 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(); //向服務(wù)器發(fā)送時(shí)間表 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.顯示最高分 通過游戲和游戲結(jié)束時(shí),都顯示最高分。用以下方法顯示最高分: /** *顯示最高分 */ 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.運(yùn)行 完成的sourcecode如下: •BlockApplication.java •BlockCanvas.java 另外,服務(wù)器使用的SERVLET的sourcecode式如下: •nec_server.zip 運(yùn)行后的結(jié)果如下: 3.總結(jié) 本講中,介紹了可以利用HTTP通信進(jìn)行網(wǎng)絡(luò)編程。利用本講介紹的東西,能夠制作簡單的chat程序以及聯(lián)網(wǎng)作戰(zhàn)游戲等應(yīng)用程序。請大家也試著制作一些新的獨(dú)特的應(yīng)用程序吧。