开发J2ME低级联网应用
【IT168 技术文档】
在开发J2ME联网应用程序中介绍了如何通过Http协议进行联网,通常我们把通过Http联网叫做高级联网,在这片文章中我们讲述如何使用Socket在TCP/IP层进行联网操作。如果你还不清楚J2ME平台的通用联网框架,那么请参考介绍J2ME通用联网框架。
在MIDP2.0中提供了如下重要的类对TCP/IP和UDP进行支持。
javax.microedition.io.SocketConnection
javax.microedition.io.ServerSocketConnection
javax.microedition.io.UDPDatagramConnection
今天主要讲述在客户端使用SocketConnection和TCP/IP服务器进行通信,后面的两个类将在后续的文章中介绍,SocketConnection定义了socket流连接。调用Connector.open(\"socket://host:port\")会返回一个SocketConnection的实例。通过调用socket.openInputStream()和socket.openOutputStream()两个方法我们将得到InputStream和OutputStream的实例,这样我们就可以和服务器进行通信了,如下所示:
SocketConnection client = (SocketConnection) Connector.open(\"socket://\" + hostname + \":\" + port);
client.setSocketOption(DELAY, 0);
client.setSocketOption(KEEPALIVE, 0);
InputStream is = client.openInputStream();
OutputStream os = client.openOutputStream();
os.write(\"some string\".getBytes());
int c = 0;
while((c = is.read()) != -1) ...{
// do something with the response
}
is.close();
os.close();
client.close();
注意在联网的时候我们还是必须要在另一个线程内进行联网操作,而不能再主线程进行。这样的目的是为了避免用户界面的堵塞。通常我们可以定义一个类扩展Thread类并提供一个把MIDlet作为参数的构造器,为了提高效率我们通过使用wait()和notify()方法,这样只有在用户按下按钮的时候,线程才被唤醒去执行联网操作,否则再启动后他一直出去\"wait\"的状态。
class CommandThread extends Thread ...{
MIDlet parent;
![]()
StreamConnection socket = null;
InputStream is = null;
![]()
boolean exit = false;
![]()
public CommandThread(MIDlet parent) ...{
this.parent = parent;
}
![]()
public void run() ...{
while (!exit) ...{
synchronized(parent) ...{
while(!commandAvailable) ...{
try ...{
parent.wait();
}
catch (InterruptedException e) ...{
}
}
}
}
}
......................
..................
}
TCP/IP服务器的写法和一般的服务器写法是一样的,因此不再多介绍。如果有问题可以参考java.net包的内容。下面通过例子演示一下,我们构建一个时间服务器,在手机端来通过socket访问并得到当前时间显示在屏幕上。代码如下:
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.ServerSocket;
import java.util.Date;
![]()
public class DayTimeServer ...{
![]()
public static void main(String args[]) ...{
![]()
int dayTimePort = 13;
![]()
if (args.length == 1) ...{
try ...{
dayTimePort = Integer.parseInt(args[0]);
} catch (NumberFormatException e) ...{
System.out.println("invalid port number");
System.exit(0);
}
}
![]()
ServerSocket serverSocket = null;
Socket sock;
![]()
DataOutputStream dataout;
![]()
try ...{
serverSocket = new ServerSocket(dayTimePort);
} catch (IOException e) ...{
System.out.println(e.getMessage());
e.printStackTrace();
System.exit(0);
}
![]()
while (true) ...{
try ...{
sock = serverSocket.accept();
dataout = new DataOutputStream(new BufferedOutputStream(sock
.getOutputStream()));
String dateString = new Date().toString();
dataout.write(dateString.getBytes(), 0, dateString.length());
dataout.flush();
sock.close();
} catch (IOException e) ...{
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
}
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
![]()
import java.io.*;
import javax.microedition.io.*;
![]()
public class DayTimeClient extends javax.microedition.midlet.MIDlet implements
CommandListener ...{
![]()
Display display;
![]()
private boolean commandAvailable;
![]()
CommandThread commandThread;
![]()
List menu;
![]()
Form outputForm;
![]()
StringItem dt;
![]()
Command cmdBack;
![]()
Command cmdExit;
![]()
private static final String PROTOCOL = "socket:";
![]()
private String dayTimeURL;
![]()
public void startApp() ...{
String host = getAppProperty("HOST");
String port = getAppProperty("DAYTIME_PORT");
try ...{
Integer.parseInt(port);
} catch (NumberFormatException e) ...{
destroyApp(false);
notifyDestroyed();
}
![]()
dayTimeURL = PROTOCOL + "//" + host + ":" + port;
display = Display.getDisplay(this);
outputForm = new Form("Date/Time");
dt = new StringItem(null, null);
outputForm.append(dt);
cmdBack = new Command("Back", Command.BACK, 1);
outputForm.addCommand(cmdBack);
cmdExit = new Command("Exit", Command.EXIT, 1);
outputForm.addCommand(cmdExit);
outputForm.setCommandListener(this);
![]()
menu = new List("Menu", List.IMPLICIT);
menu.append("Get Date/Time", null);
menu.append("Exit", null);
menu.setCommandListener(this);
display.setCurrent(menu);
![]()
commandAvailable = false;
commandThread = new CommandThread(this);
commandThread.start();
}
![]()
public void pauseApp() ...{
}
![]()
public void destroyApp(boolean unconditional) ...{
}
![]()
public void commandAction(Command cmd, Displayable d) ...{
if (cmd == cmdExit) ...{
destroyApp(false);
notifyDestroyed();
} else if (cmd == cmdBack) ...{
display.setCurrent(menu);
} else if ((d == menu) && (cmd == List.SELECT_COMMAND)) ...{
synchronized (this) ...{
commandAvailable = true;
notify();
}
}
}
![]()
class CommandThread extends Thread ...{
MIDlet parent;
![]()
StreamConnection socket = null;
![]()
InputStream is = null;
![]()
boolean exit = false;
![]()
public CommandThread(MIDlet parent) ...{
this.parent = parent;
}
![]()
public void run() ...{
while (!exit) ...{
synchronized (parent) ...{
while (!commandAvailable) ...{
try ...{
parent.wait();
} catch (InterruptedException e) ...{
}
}
}
commandAvailable = false;
![]()
switch (menu.getSelectedIndex()) ...{
case 0:
getDate();
break;
case 1:
exit = true;
}
}
destroyApp(false);
notifyDestroyed();
}
![]()
public void getDate() ...{
try ...{
socket = (StreamConnection) Connector.open(dayTimeURL,
Connector.READ, true);
![]()
is = socket.openInputStream();
} catch (Exception e) ...{
}
![]()
try ...{
int b;
StringBuffer sb = new StringBuffer();
while ((b = is.read()) != -1) ...{
sb.append((char) b);
}
socket.close();
dt.setText(sb.toString());
display.setCurrent(outputForm);
} catch (Exception e) ...{
}
}
}
}
你需要在jad文件中定义两个属性值,当然你也可以直接写在源代码中:
DAYTIME_PORT: 13
HOST: 127.0.0.1
