一个手机上的网络聊天游戏(J2ME)

这是一个Client基于J2ME以及TCP/IP协议的简单的聊天程序,在本人模拟器上测试没问题,但并不保证真机上会出现问题。

代码以及整个游戏框架你可以拿来自由使用,但请注明出处。

(一)

这部分是程序Cilent端和Server端共用的一些类,之所以把它们拿出来单独写,是为了让整个程序的框架更清晰。

其实也就一个类、一个接口,但思想是一样的,或许你需要更多的类来让Client和Server共用,举个例子来说:如果你采用了“脏矩形技术”,那么可以把每个Item、每个Frame做个共享类放在这里。

Server接口:

public interface Server {
public static final int PORT = 8042;
}

这个接口里很简单,之定义了一个端口号,以便于以后的程序修改和维护。

Message类:

听其名字就知道了,这个是消息类,因为无论是Client端还是Server端,其消息是能抽象出很多相似的东西的。

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

public class Message {
public static final int NO_VALUE = -1;
public static final int SIGNUP = 0;
public static final int SIGNUP_ACK = 1;
public static final int CLIENT_STATUS = 2;
public static final int SERVER_STATUS = 3;
public static final int ERROR = 4;
public static final int SIGNOFF = 5;
private int type;
private String str;
public static int player_id;

public Message(int type,int player_id,String str) {
this.type = type;
Message.player_id = player_id;
this.str = str;
}

public int getType() {
return type;
}

public String getStr(){
return str;
}

public void archive(DataOutputStream out) throws IOException {
out.writeInt(type);
out.writeInt(player_id);
out.writeUTF(str);
out.flush();
System.out.println("***Client has send :"+type);
}

public static Message createFromStream(DataInputStream in) throws IOException {
Message msg = new Message(in.readInt(), in.readInt(),in.readUTF());
return msg;
}

public String toString() {
return "Message: type # = " + type + ", player_id = "
+ player_id+", content = "+str;
}

}

因为我们只是实现了简单的聊天功能,只是发送简单的字符给Server端,然后让其传送到各个Client端,因此功能比较简单,目的也仅仅用于学习,但你可以在此功能上增加更多的功能。

服务器端类

服务器端也很简单,就是开一个ServerSocket监听Client端的连接,如果有连接,就把此连接加入到一个List中。之所以这样处理, 是为了管理用户连接,比如将来你可能需要增加给特定的用户发送私人消息的功能,那么就可以从这个用户列表中寻找特定的用户进行发送。

连接建立以后利用一个单独的线程来进行通讯。

MultiPlayerServer类:

import java.io.IOException;
import java.net.ServerSocket;
import java.util.List;
import java.util.Vector;

public class MultiPlayerServer implements Server,Runnable{
private List list;

public MultiPlayerServer() {
list = new Vector();
Thread t2 = new Thread(this);
t2.start();
}

public void distributeUpdate(int type,int player_id,String content) {
ServerConnection conn;
Message msg = new Message(type,player_id,content);
for (int i = 0; i < list.size(); i++) {
conn = (ServerConnection) list.get(i);
conn.sendMessage(msg);
}
}

public synchronized void removeConnection(ServerConnection conn) {
list.remove(conn);
System.out.println("removed connection for player " + conn.getPlayerID());
System.out.println("connection list size is now " + list.size());
}

public void run() {
ServerSocket socket;

try {
socket = new ServerSocket(PORT);
System.out.println("multiplayer server listening @ " + PORT);

for (; ; ) {
synchronized (this) {
list.add(new ServerConnection(socket.accept(),this));
}
}
} catch (IOException ioe) {
System.out.println("*** MultiPlayerServer.run(): " + ioe);
}
}

}

ServerConnection类:

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.*;

public class ServerConnection implements Runnable {
private MultiPlayerServer server;
private Socket socket;
private DataInputStream in;
private DataOutputStream out;
private int player_id;
private Message err;
private boolean done;

public static Hashtable userList = new Hashtable();
public static int player_count;

/**
* Create a new instance for use with game engine 'engine',
* socket 'socket', and server 'server'.
*/
public ServerConnection(Socket socket,MultiPlayerServer server) {
this.server = server;
this.socket = socket;
done = false;
Thread thread = new Thread(this);
thread.start();
}

private synchronized void handleSignup(String str) {
player_id = player_count++;
if (player_id < 0) {
System.out.println("ServerConnection.handleSignup(): engine refused player sign-up");
return;
}
userList.put(new Integer(player_id),str);
System.out.println("signed up player " + player_id);
Message msg = new Message(Message.SIGNUP_ACK,player_id,"-1");

try {
msg.archive(out);
} catch (IOException e) {
System.out.println("***: could not send msg " + err);
}
}

private void handleClientStatus(Message msg) {
server.distributeUpdate(Message.SERVER_STATUS,player_id,userList.get(new Integer(player_id))+" 说 :"+msg.getStr());
}

public int getPlayerID() {
return player_id;
}

/**
* Send a message to the client connected to this instance
*/
public synchronized void sendMessage(Message msg) {
try {
msg.archive(out);
} catch (IOException e) {
System.out.println("***: could not send msg " + msg);
}
}

/**
* main loop
*/
public void run() {
Message msg;

try {
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());

while (!done) {
msg = Message.createFromStream(in);
switch (msg.getType()) {
case Message.SIGNUP:
System.out.println("Server is handling : SIGNUP");
handleSignup(msg.getStr());
System.out.println("Server After : SIGNUP");
break;
case Message.CLIENT_STATUS:
System.out.println("Server receive : CIENT_STATUS");
handleClientStatus(msg);
break;
case Message.SIGNOFF:
break;
default:
break;
}
}

in.close();
out.close();
socket.close();
} catch (Exception ioe) {
System.out.println("*** ServerConnection.run(): " + ioe);
server.removeConnection(this);
}
server.removeConnection(this);
System.out.println("player " + player_id + " disconnected.");
}

}

客户端类

客户端很简单,就是开一个线程处理用户的数据发送和接收,并做出相应的界面处理。

由于其简单,我就不再罗嗦,看代码:

MIDlet类:

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.TextField;
import javax.microedition.midlet.MIDlet;


/**
* @author 孙东风
*
**/

public class ChatMIDlet extends MIDlet implements Runnable,CommandListener{

private static final String SERVER_IP = "127.0.0.1";
private Command exit = new Command("exit",Command.EXIT,1);
private GameScreen screen;
private DataInputStream in;
private DataOutputStream out;
private StreamConnection conn;
private boolean done;
private int player_id;

public static Display display;

Form login_form = new Form("登陆界面");
TextField name_textfield = new TextField("请输入呢称 :","",10,TextField.ANY);
Command loginCommand = new Command("登陆",Command.SCREEN,1);
static String name;

public ChatMIDlet() {
super();
login_form.append(name_textfield);
login_form.addCommand(loginCommand);
login_form.setCommandListener(this);
display = Display.getDisplay(this);
}


protected void startApp(){
try {
conn = (StreamConnection) Connector.open("socket://"+SERVER_IP+":"+Server.PORT);
in = new DataInputStream(conn.openInputStream());
out = new DataOutputStream(conn.openOutputStream());
} catch (IOException e) {
closeConnection();
System.out.println("*** could not connect to server: " + e);
destroyApp(true);
}
Display.getDisplay(this).setCurrent(login_form);
}

public DataInputStream getInput(){
return in;
}

public DataOutputStream getOutput(){
return out;
}

//关闭所有资源
private void closeConnection() {
try {
if (in != null) {
in.close();
}

if (out != null) {
out.close();
}

if (conn != null) {
conn.close();
}
} catch (IOException e) {
System.out.println(e);
}
}

protected void pauseApp() {

}


protected void destroyApp(boolean bool){
System.out.println("MidpTestClient.destroyApp()");
Message msg = new Message(Message.SIGNOFF, Message.NO_VALUE,null);
try {
msg.archive(out);
} catch (IOException e) {
}

closeConnection();
Display.getDisplay(this).setCurrent(null);
}

public void handleStatus(Message msg){
GameScreen.revStr = msg.getStr();
screen.repaint();
}

public void handleError(){
Message msg = new Message(Message.SIGNOFF, Message.NO_VALUE,null);

try {
msg.archive(out);
} catch (IOException e) {
e.printStackTrace();
}
}

public void handleUnknown(Message msg){
System.out.println("received unknown message: " + msg);
}

public void run() {

Message msg;

while (!done) {
try {
msg = Message.createFromStream(in);
} catch (IOException e) {
System.out.println("cant read message from stream");

continue;
}

switch (msg.getType()) {
case Message.SERVER_STATUS:
System.out.println("Client receive SERVER_STATUS");
handleStatus(msg);
break;
case Message.ERROR:
handleError();
break;
default:
handleUnknown(msg);
break;
}
}

}

public void commandAction(Command cmd, Displayable g) {
if (cmd == exit) {
done = true;
destroyApp(true);
notifyDestroyed();
}else if(cmd == loginCommand){
if(name_textfield.getString().length() != 0){
name = name_textfield.getString();
Message msg = new Message(Message.SIGNUP,Message.NO_VALUE,name_textfield.getString());
try{
msg.archive(out);
msg = Message.createFromStream(in);
if (msg.getType() != Message.SIGNUP_ACK) {
System.out.println("*** could not sign up: " + msg);
destroyApp(true);
}

player_id = Message.player_id;
System.out.println("received sign-up ack, id = " + player_id);
System.out.println("--------------1");
screen = new GameScreen();
screen.initialize(this, player_id);
done = false;
Thread thread = new Thread(this);
thread.start();
Display.getDisplay(this).setCurrent(screen);
}catch(Exception e){
System.out.println("*** could not sign up with server: " + e);
destroyApp(true);
}
}else{
Alert alert = new Alert("警告","用户名和密码不能为空",null,AlertType.ERROR);
alert.setTimeout(Alert.FOREVER);
Display.getDisplay(this).setCurrent(alert);
}
}
}

}
GameScreen类:

import javax.microedition.lcdui.*;

public class GameScreen extends Canvas implements CommandListener{

public Form message_form = new Form("Send Message Form");
public Command sendCommand = new Command("Send",Command.OK,1);
public Command sendCommand2 = new Command("Send",Command.OK,1);
public TextField content_textfield = new TextField("Content :","",10,TextField.ANY);
public String content;

public static String revStr = "null";

public int player_id;
ChatMIDlet chatmidlet;

public GameScreen(){
message_form.append(content_textfield);
message_form.addCommand(sendCommand2);
message_form.setCommandListener(this);
this.addCommand(sendCommand);
this.setCommandListener(this);
}

public void initialize(ChatMIDlet midlet,int player_id){
this.chatmidlet = midlet;
this.player_id = player_id;
}

protected void paint(Graphics g) {
g.setColor(0x000000);
g.fillRect(0,0,getWidth(),getHeight());
g.setColor(0xffffff);
g.drawString(revStr,0,0,Graphics.LEFT|Graphics.TOP);
}


public void commandAction(Command cmd, Displayable g) {
if(cmd == sendCommand){
System.out.println("CommandListenning this");
ChatMIDlet.display.setCurrent(message_form);
}else if(cmd == sendCommand2){
content = content_textfield.getString();
Message msg = new Message(Message.CLIENT_STATUS,player_id,content);
try{
msg.archive(chatmidlet.getOutput());
}catch(Exception e){
e.printStackTrace();
System.out.println("Send Message Failed!");
}
ChatMIDlet.display.setCurrent(this);
}
}

}

后话:希望此文能为3G到来之前吹点热风,催化催化。

效果图如下:

一个手机上的网络聊天游戏(J2ME)

输入呢称并传送到Server端

一个手机上的网络聊天游戏(J2ME)

输入聊天内容

一个手机上的网络聊天游戏(J2ME)

显示呢称和说话内容

你可能感兴趣的:(j2me)