J2ME无线联网技术
首先看一下GCF框架体系,如下图所示:
CLDC只是定义了基于底层通信协议(如传输流或数据报等)的网络连接中的一些接口定义,至于具体某种高层协议
的网络连接一般在简表中定义,因为不同的设备支持的高层网络通信协议是不一样的,因此完全没必要在CLDC配置中来定义。
在专门针对移动信息设备的MIDP简表中,定义了ServerSocketConnection、SocketConnection、UDPDatagramConnection和HttpConnection接口来提供对高层网络协议的网络通信进行支持。其中HttpConnection是MIDP规定设备必须支持的。
因此,可以总结出我们需要掌握的方面:使用Http连接Internet、开发Socket网络连接应用、开发Datagram网络连接应用,下面着重讲解前两种。
1.使用Http连接Internet
我写了一个使用Http从http://life.yule.com.cn/UploadPic/2008-1/200814142026328.jpg下载并显示图片的例子。代码如下:
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
import java.io.*;
public class ViewImage extends MIDlet implements CommandListener{
private Display dis;
private TextBox tbMain;
private Alert alStatus;
private Form fm;
private Command cmExit;
private Command cmView;
private Command cmBack;
private static final int ALERT_DISPLAY_TIME =3000;
Image im=null;
public ViewImage() {
// TODO Auto-generated constructor stub
dis=Display.getDisplay(this);
tbMain=new TextBox("输入图片地址","http://life.yule.com.cn/UploadPic/2008-1/200814142026328.jpg",75,0);
cmExit=new Command("退出",Command.EXIT,1);
cmView=new Command("下载",Command.SCREEN,2);
tbMain.addCommand(cmExit);
tbMain.addCommand(cmView);
tbMain.setCommandListener(this);
fm=new Form("");
cmBack=new Command("后退",Command.BACK,1);
fm.addCommand(cmBack);
fm.setCommandListener(this);
}
protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
// TODO Auto-generated method stub
}
protected void pauseApp() {
// TODO Auto-generated method stub
}
protected void startApp() throws MIDletStateChangeException {
// TODO Auto-generated method stub
dis.setCurrent(tbMain);
}
public void commandAction(Command c,Displayable s)
{
if(c==cmExit)
{
try{
destroyApp(false);
notifyDestroyed();
}catch(Exception e){
}
}else if(c==cmView)
{
showAlert("下载中",false,tbMain);
Thread dl=new Download(tbMain.getString(),this);
dl.start();
}
else if(c==cmBack)
{
dis.setCurrent(tbMain);
}
}
public void showImage(boolean flag)
{
if(flag==false)
{
showAlert("下载失败",true,tbMain);
}
else
{
ImageItem ii=new ImageItem(null,im,ImageItem.LAYOUT_CENTER,null);
if(fm.size()!=0)
fm.set(0, ii);
else
fm.append(ii);
showAlert("下载成功",true,fm);
}
}
public void showAlert(String msg,boolean modal,Displayable displayable)
{
alStatus=new Alert("状态",msg,null,AlertType.INFO);
if(modal)
{
alStatus.setTimeout(Alert.FOREVER);
}
else
{
alStatus.setTimeout(ALERT_DISPLAY_TIME);
}
dis.setCurrent(alStatus, displayable);
}
class Download extends Thread
{
private String url;
private ViewImage Midlet;
private boolean downloadSuccess=false;
public Download(String url,ViewImage Midlet)
{
this.url=url;
this.Midlet=Midlet;
}
public void run() {
// TODO Auto-generated method stub
try{
getImage(url);
}catch(Exception e){
}
}
private void getImage(String url) throws IOException
{
ContentConnection connection=(ContentConnection)Connector.open(url);
DataInputStream iStrm=connection.openDataInputStream();
ByteArrayOutputStream bStrm=null;
Image im=null;
try{
byte[] imageData;
int length=(int)connection.getLength();
if(length!=-1)
{
imageData=new byte[length];
iStrm.readFully(imageData);
}
else
{
bStrm=new ByteArrayOutputStream();
int ch;
while((ch=iStrm.read())!=-1)
{
bStrm.write(ch);
}
imageData=bStrm.toByteArray();
}
im=Image.createImage(imageData, 0, imageData.length);
}
finally{
if(connection!=null)
connection.close();
if(iStrm!=null)
iStrm.close();
if(bStrm!=null)
bStrm.close();
}
if(im==null)
Midlet.showImage(false);
else
{
Midlet.im=im;
Midlet.showImage(true);
}
}
}
}
最终显示结果如下图所示:
注:1.ContentConnection connection=(ContentConnection)Connector.open(url);
为什么用ContentConnection 而不用HttpConnection ,个人认为应该可以,没有试验,有时间验证一下。
2.
byte[] imageData;
int length=(int)connection.getLength();
if(length!=-1)
{
imageData=new byte[length];
iStrm.readFully(imageData);
}
else
{
bStrm=new ByteArrayOutputStream();
int ch;
while((ch=iStrm.read())!=-1)
{
bStrm.write(ch);
}
imageData=bStrm.toByteArray();
}
im=Image.createImage(imageData, 0, imageData.length);
不是很明白!
2.开发Socket网络连接应用
我做的是一个聊天软件,有服务端和客户端,代码如下:
Server.java
import java.io.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
public class Server implements Runnable,CommandListener {
private SocketMidlet parent;
private Display dis;
private Form f;
private StringItem si;
private TextField tf;
private boolean stop;
private Command sendCommand=new Command("发送",Command.OK,1);
private Command exitCommand=new Command("退出",Command.EXIT,1);
InputStream is;
OutputStream os;
SocketConnection sc;
ServerSocketConnection scn;
Sender sender;
public Server(SocketMidlet m) {
// TODO Auto-generated constructor stub
parent=m;
dis=Display.getDisplay(parent);
f=new Form("Socket服务器端");
si=new StringItem("状态:","");
tf=new TextField("发送:","",30,TextField.ANY);
f.append(si);
f.append(tf);
f.addCommand(exitCommand);
f.setCommandListener(this);
dis.setCurrent(f);
this.start();
}
public void start()
{
Thread t=new Thread(this);
t.start();
}
public void run() {
// TODO Auto-generated method stub
try{
si.setText("等待客户端连接");
scn=(ServerSocketConnection)Connector.open("socket://:50009");
sc=(SocketConnection)scn.acceptAndOpen();
si.setText("Connection accepted");
is=sc.openInputStream();
os=sc.openOutputStream();
sender=new Sender(os);
f.addCommand(sendCommand);
while(true)
{
StringBuffer sb=new StringBuffer();
int c=0;
while(((c=is.read())!='\n')&&(c!=-1))
{
sb.append((char)c);
}
if(c==-1) break;
si.setText("接收到的消息:"+ sb.toString());
}
stop();
si.setText("连接已经关闭");
f.removeCommand(sendCommand);
}catch(IOException ioe){
if(ioe.getMessage().equals("ServerSocket Open"))
{
Alert a=new Alert("Server","端口可能已经被占用",null,AlertType.ERROR);
a.setTimeout(Alert.FOREVER);
a.setCommandListener(this);
dis.setCurrent(a);
}
else if(!stop)
{
ioe.printStackTrace();
}
}catch(Exception e)
{
}
}
public void stop()
{
try{
stop=true;
if(is!=null)
is.close();
if(os!=null)
os.close();
if(sc!=null)
sc.close();
if(scn!=null)
scn.close();
}catch(Exception e){
}
}
public void commandAction(Command c, Displayable s) {
// TODO Auto-generated method stub
if(c==sendCommand&&!parent.isPaused())
sender.send(tf.getString());
if((c==Alert.DISMISS_COMMAND)||c==exitCommand)
{
try{
parent.notifyDestroyed();
parent.destroyApp(true);
}catch(Exception e){
}
}
}
}
Cilent.java
import java.io.*;
import javax.microedition.io.*;
import javax.microedition.lcdui.*;
public class Client implements Runnable,CommandListener {
private SocketMidlet parent;
private Display dis;
private Form f;
private StringItem si;
private TextField tf;
private boolean stop;
private Command sendCommand=new Command("发送",Command.OK,1);
private Command exitCommand=new Command("退出",Command.EXIT,1);
InputStream is;
OutputStream os;
SocketConnection sc;
Sender sender;
public Client(SocketMidlet m) {
// TODO Auto-generated constructor stub
parent=m;
dis=Display.getDisplay(parent);
f=new Form("Socket服务器端");
si=new StringItem("状态:","");
tf=new TextField("发送:","",30,TextField.ANY);
f.append(si);
f.append(tf);
f.addCommand(exitCommand);
f.setCommandListener(this);
dis.setCurrent(f);
this.start();
}
public void start()
{
Thread t=new Thread(this);
t.start();
}
public void run() {
// TODO Auto-generated method stub
try{
sc=(SocketConnection)Connector.open("socket://localhost:50009");
si.setText("已经连接到服务器");
is=sc.openInputStream();
os=sc.openOutputStream();
sender=new Sender(os);
f.addCommand(sendCommand);
while(true)
{
StringBuffer sb=new StringBuffer();
int c=0;
while(((c=is.read())!='\n')&&(c!=-1))
{
sb.append((char)c);
}
if(c==-1) break;
si.setText("接收到的消息:"+ sb.toString());
}
stop();
si.setText("连接已经关闭");
f.removeCommand(sendCommand);
}catch(ConnectionNotFoundException cnfe){
Alert a=new Alert("Client","请先运行服务器节点",null,AlertType.ERROR);
a.setTimeout(Alert.FOREVER);
a.setCommandListener(this);
dis.setCurrent(a);
}catch(IOException ioe)
{
if(!stop)
{
ioe.printStackTrace();
}
}catch(Exception e)
{
}
}
public void stop()
{
try{
stop=true;
if(is!=null)
is.close();
if(os!=null)
os.close();
if(sc!=null)
sc.close();
}catch(Exception e){
}
}
public void commandAction(Command c, Displayable s) {
// TODO Auto-generated method stub
if(c==sendCommand&&!parent.isPaused())
sender.send(tf.getString());
if((c==Alert.DISMISS_COMMAND)||c==exitCommand)
{
try{
parent.notifyDestroyed();
parent.destroyApp(true);
}catch(Exception e){
}
}
}
}
Sender.java
import java.io.*;
public class Sender extends Thread {
private OutputStream os;
private String message;
public Sender(OutputStream os) {
// TODO Auto-generated constructor stub
this.os=os;
start();
}
public synchronized void send(String msg)
{
message=msg;
notify();
}
public synchronized void run()
{
while(true)
{
if(message==null)
{
try{
wait();
}catch(Exception e){
}
}
if(message==null) break;
try{
os.write(message.getBytes());
os.write("\r\n".getBytes());
}catch(Exception e){
}
message=null;
}
}
public synchronized void stop()
{
message=null;
notify();
}
}
SocketMidlet.java
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class SocketMidlet extends MIDlet implements CommandListener{
private static final String SERVER="服务器";
private static final String CLIENT="客户端";
private static final String[] names={SERVER,CLIENT};
private Display dis;
private Form f;
private ChoiceGroup cg;
private boolean isPaused;
private Server server;
private Client client;
private Command startCommand=new Command("启动",Command.OK,1);
private Command exitCommand=new Command("退出",Command.EXIT,1);
public SocketMidlet() {
// TODO Auto-generated constructor stub
dis=Display.getDisplay(this);
f=new Form("Socket连接示例");
cg=new ChoiceGroup("选择端点类型",Choice.EXCLUSIVE,names,null);
f.append(cg);
f.addCommand(startCommand);
f.addCommand(exitCommand);
f.setCommandListener(this);
dis.setCurrent(f);
}
public boolean isPaused()
{
return isPaused;
}
protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
// TODO Auto-generated method stub
if(server!=null)
server.stop();
if(client!=null)
client.stop();
}
protected void pauseApp() {
// TODO Auto-generated method stub
isPaused=true;
}
protected void startApp() throws MIDletStateChangeException {
// TODO Auto-generated method stub
isPaused=false;
}
public void commandAction(Command c, Displayable s) {
// TODO Auto-generated method stub
if(c==exitCommand)
{
try {
destroyApp(false);
notifyDestroyed();
} catch (MIDletStateChangeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if(c==startCommand)
{
String name=cg.getString(cg.getSelectedIndex());
if(name.equals(SERVER))
{
server=new Server(this);
}
else if(name.equals(CLIENT))
{
client=new Client(this);
}
}
}
}
运行结果如下:
3.开发Datagram网络连接应用
大体上和开发Socket网络连接应用差不多,只是Socket是面向连接的,而他不是,我也没有认真看,呵呵!