`
kerlubasola
  • 浏览: 677002 次
文章分类
社区版块
存档分类
最新评论

一个手机上的网络聊天游戏(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到来之前吹点热风,催化催化。

效果图如下:

输入呢称并传送到Server端

输入聊天内容

显示呢称和说话内容

分享到:
评论

相关推荐

    java源码包33个实例源码阳光酒店管理系统手机游戏J2ME毕业设计书籍管理系统网络电视源代码TV

    手机游戏J2ME毕业设计.rar 数据持久层框架 Hibernate.zip 数据结构提取器.rar 文件压缩解压缩包 Commons Compress.rar 日历同步统计 GCALDaemon.zip 物业管理系统毕业设计+源码.rar 用iText类库制作PDF文档.rar 用...

    java源码包---java 源码 大量 实例

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    java源码包2

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    java源码包3

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    java源码包4

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    JAVA上百实例源码以及开源项目

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    Java编写的山寨QQ,多人聊天+用户在线 21个目标文件 摘要:JAVA源码,媒体网络,山寨QQ,Java聊天程序 Java编写的山寨QQ,多人聊天+用户在线,程序分服务端和客户端,典型C/S结构, 当用户发送第一次请求的时候,验证...

    成百上千个Java 源码DEMO 3(1-4是独立压缩包)

    Java编写的山寨QQ,多人聊天+用户在线 21个目标文件 摘要:JAVA源码,媒体网络,山寨QQ,Java聊天程序 Java编写的山寨QQ,多人聊天+用户在线,程序分服务端和客户端,典型C/S结构, 当用户发送第一次请求的时候,验证...

    JAVA上百实例源码以及开源项目源代码

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    java源码包实例源码JAVA开发源码55个合集.zip

    java源码包J实例源码JAVA开发...蜀山剑侠传游戏J2ME手机版源代码.rar 超市购物系统.rar 车间管控.rar 轻松商城系统.rar 选修课程管理系统V1.2.3.rar 配置ODBC数据源.rar 销售预测系统PDP系统.rar 阳光酒店管理系统.rar

    Java源码包100个设计实例.zip

    J2ME黑白棋游戏手机版 v2.1完整源码.rar JasperReports 报表类库v3.5.rar Java 3DMenu 界面源码.rar Java 3D魔方游戏源码及中文注释包.rar Java EJB中有、无状态SessionBean的两个例子 Java Socket 聊天通信演示代码...

    java源码包JSP实例源码JAVA开发源码65个合集.zip

    java源码包JSP实例源码JAVA...蜀山剑侠传游戏J2ME手机版源代码.rar 超市购物系统.rar 车间管控.rar 轻松商城系统.rar 选修课程管理系统V1.2.3.rar 邮政汇款打印程序.rar 配置ODBC数据源.rar 销售预测系统PDP系统.rar

    java源码包实例源码JAVA开发源码50个合集.zip

    java源码包实例源码JAVA开发源码50个合集: Ajax框架 ZK.rar Java图书馆管理系统源程序.rar Java图片倒影效果实例源码.rar Java图片翻折,将图像压扁.rar Java坦克大战网络对战版源代码.rar Java声音播放程序源代码....

    计算机毕业设计论文题目大全.doc

    "J2EE 音像店租赁管理系统的设计与实现 "Eclipse " " "J2ME手机游戏的开发-Beckham Goal "Eclipse " " "J2ME五子棋手机网络对战游戏的设计与实 "Eclipse "SQL Server " "现 " " " "JAVA "Eclipse "SQL Server " "ME...

Global site tag (gtag.js) - Google Analytics