基于Java NIO的手机解题游戏开发
基于Java NIO的手机答题游戏开发
先上个游戏截图:


豌豆荚地址: http://apps.wandoujia.com/search?key=%E5%85%A8%E6%B0%91%E7%AD%94%E9%A2%98&source=index
本文概要介绍如何通过java nio来开发android客户端与服务器socket通信的过程。
1. 为什么要用java NIO
常规的socket通信为阻塞方式,服务器接收到消息并进行处理,处理完一个才能处理下一个。 如果要同时处理,就得自己开线程,为每一个客户端连接做一个线程,这样当连接数大的情况下,上万以上,服务器就难以承受了。 JAVA NIO是jdk1.4提供的API, 主要原理是以监听机制来处理客户端的连接。主要包含buffer和channel.

2. 服务器示例代码
package com.seya.onlineserver.socket.nio;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Vector;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.seya.onlineserver.jpush.JPushManager;
import com.seya.onlineserver.socket.dao.UserDAO;
import com.seya.onlineserver.socket.nio.Room.State;
/**
* NIO服务端
* @author Seyason
*/
public class NIOServer implements MsgProcessor{
//用户在线标示
public static final int STATUS_ONLINE = 1;
public static final int STATUS_OFFLINE = 0;
private static final int PORT = 2121;
//全部用户集合
private Vector<UserClient> allUserList = new Vector<UserClient>();
//房间数
private Vector<Room> oneVRoomList = new Vector<Room>();
private Vector<Room> twoVRoomList = new Vector<Room>();
private Vector<Room> threeVRoomList = new Vector<Room>();
public static Vector<UserClient> idleUserList = new Vector<UserClient>();
public Vector<UserClient> challegePendingList = new Vector<UserClient>();
//通道管理器
private Selector selector;
UserDAO uDao = new UserDAO();
/**
* 获得一个ServerSocket通道,并对该通道做一些初始化的工作
* @param port 绑定的端口号
* @throws IOException
*/
public void initServer(int port) throws IOException {
// 获得一个ServerSocket通道
ServerSocketChannel serverChannel = ServerSocketChannel.open();
// 设置通道为非阻塞
serverChannel.configureBlocking(false);
// 将该通道对应的ServerSocket绑定到port端口
serverChannel.socket().bind(new InetSocketAddress(port));
// 获得一个通道管理器
this.selector = Selector.open();
//将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,注册该事件后,
//当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
}
public static void startUp() {
NIOServer server = new NIOServer();
try {
server.initServer(PORT);
server.listen();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理
* @throws IOException
*/
@SuppressWarnings("unchecked")
public void listen() throws IOException {
System.out.println("服务端启动成功!");
// 轮询访问selector
while (true) {
//当注册的事件到达时,方法返回;否则,该方法会一直阻塞
selector.select();
// 获得selector中选中的项的迭代器,选中的项为注册的事件
Iterator ite = this.selector.selectedKeys().iterator();
while (ite.hasNext()) {
SelectionKey key = (SelectionKey) ite.next();
// 删除已选的key,以防重复处理
ite.remove();
// 客户端请求连接事件
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) key
.channel();
// 获得和客户端连接的通道
SocketChannel channel = server.accept();
// 设置成非阻塞
channel.configureBlocking(false);
UserClient uClient = new UserClient(channel, this);
//在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。
channel.register(this.selector, SelectionKey.OP_READ, uClient);
} else if (key.isReadable()) {
read(key);
}
}
}
}
public void addIdleMemb(UserClient uClient) {
idleUserList.add(uClient);
}
private int getOnlineMembCnt() {
int oneVMembCount = 0;
for(Room room : oneVRoomList) {
oneVMembCount += room.getMembCount();
}
int twoVMembCount = 0;
for(Room room : twoVRoomList) {
twoVMembCount += room.getMembCount();
}
int threeVMembCount = 0;
for(Room room : threeVRoomList) {
threeVMembCount += room.getMembCount();
}
int idleCount = 0;
for (UserClient userClient : idleUserList) {
if (userClient.state == UserClient.STATE_IN_HALL) {
if (userClient.getReqRoomSize() == 2) {
oneVMembCount++;
} else if (userClient.getReqRoomSize() == 4) {
twoVMembCount++;
} else if (userClient.getReqRoomSize() == 6) {
threeVMembCount++;
}
} else if (userClient.state == UserClient.STATE_IN_HOME) {
idleCount++;
}
}
//总在线人数
int totalCount = idleCount + oneVMembCount + twoVMembCount + threeVMembCount;
return totalCount;
}
private JSONObject getHomeJsonInfo() {
JSONObject json = new JSONObject();
int oneVMembCount = 0;
for(Room room : oneVRoomList) {
oneVMembCount += room.getMembCount();
}
int twoVMembCount = 0;
for(Room room : twoVRoomList) {
twoVMembCount += room.getMembCount();
}
int threeVMembCount = 0;
for(Room room : threeVRoomList) {
threeVMembCount += room.getMembCount();
}
int idleCount = 0;
for (UserClient userClient : idleUserList) {
if (userClient.state == UserClient.STATE_IN_HALL) {
if (userClient.getReqRoomSize() == 2) {
oneVMembCount++;
} else if (userClient.getReqRoomSize() == 4) {
twoVMembCount++;
} else if (userClient.getReqRoomSize() == 6) {
threeVMembCount++;
}
} else if (userClient.state == UserClient.STATE_IN_HOME) {
idleCount++;
}
}
if (oneVMembCount == 0) {
Random r = new Random();
oneVMembCount = r.nextInt(5);
}
json.put("oneVMembCount", oneVMembCount);
json.put("twoVMembCount", twoVMembCount);
json.put("threeVMembCount", threeVMembCount);
//总在线人数
int totalCount = idleCount + oneVMembCount + twoVMembCount + threeVMembCount;
// Random r = new Random();
// totalCount = r.nextInt(10000);
json.put("totalCount", totalCount);
return json;
}
/**
* 处理读取客户端发来的信息 的事件
* @param key
* @throws IOException
*/
public void read(SelectionKey key) {
// 服务器可读取消息:得到事件发生的Socket通道
UserClient uClient = (UserClient) key.attachment();
boolean isSuccess = uClient.onMessage();
if (!isSuccess) {
//发送失败,连接异常
removeFromIdle(uClient.getUserId());
}
}
@Override
public void process(String msg, UserClient userClient) {
try {
JSONObject json = JSON.parseObject(msg);
String cmd = json.getString("cmd");
if (Cmd.JOIN.equals(cmd)) {
//加入房间
json = json.getJSONObject("data");
String type = json.getString("type");
userClient.populateFromJson(json);
Room room = null;
if ("new".equals(type)) {
room = createNewRoom(userClient);
userClient.setFromHome(false);
} else if ("fast".equals(type)) {
room = fastJoin(userClient);
if (json.containsKey("isFromHome")) {
userClient.setFromHome(json.getBooleanValue("isFromHome"));
} else {
userClient.setFromHome(false);
}
} else if (Cmd.ENTERHALL.equals(cmd)) {
json = json.getJSONObject("data");
userClient.populateFromJson(json);
userClient.state = UserClient.STATE_IN_HALL;
notifyHomeInfo();
Cmd enter = new Cmd(Cmd.ENTERHALL);
JSONObject msgData = new JSONObject();
msgData.put("userid", userClient.getUserId());
msgData.put("username", userClient.userInfo.getUsername());
msgData.put("nickname", userClient.userInfo.getNickname());
msgData.put("msg", userClient.userInfo.getNickname() + "刚刚走进了" + getHallName(userClient.getReqRoomSize()) + "房间");
enter.data = msgData;
sendToIdle(enter);
} else if (Cmd.QUIT.equals(cmd)) {
//退出房间大厅,回到主界面
userClient.state = UserClient.STATE_IN_HOME;
notifyHomeInfo();
} else if (Cmd.UNPRESENCE.equals(cmd)) {
//退出登录, 断开连接
System.out.println("===退出登录===" + userClient.getUserId());
idleUserList.remove(userClient);
allUserList.remove(userClient);
//从挑战者列表中清除
for (int i=0; i < challegePendingList.size(); i++) {
if (challegePendingList.get(i).getUserId() == userClient.getUserId()) {
challegePendingList.remove(i);
i--;
}
}
uDao.setStatus(STATUS_OFFLINE, userClient.getUserId());
System.gc();
notifyHomeInfo();
} else if (Cmd.ROOMLIST.equals(cmd)) {
//客户端主动获取房间列表
sendRoomList(userClient);
} else if (Cmd.HOME_INFO.equals(cmd)) {
//客户端主动获取主页数据
sendHomeInfo(userClient);
} else if (Cmd.PRESENCE.equals(cmd)) {
Cmd alert = new Cmd(Cmd.ALERT);
JSONObject data = new JSONObject();
json = json.getJSONObject("data");
userClient.populateFromJson(json);
***********
alert.data = data;
userClient.sendCmd(alert);
notifyHomeInfo();
//给不在多人对战房间的人发送消息
sendToIdle(msg);
}
} catch (JSONException ex) {
ex.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void sendToIdle(String msg) throws IOException {
for (UserClient idleUser : idleUserList) {
idleUser.sendJsonMsg(msg);
}
}
private void sendToIdle(Cmd msg) throws IOException {
for (UserClient idleUser : idleUserList) {
idleUser.sendCmd(msg);
}
}
/**
* 删除无效链接对象
*/
private void checkInvalidUserClient(int userId) {
removeFromIdle(userId);
for (Room room : oneVRoomList) {
room.checkInvalidMember(userId);
}
for (Room room : twoVRoomList) {
room.checkInvalidMember(userId);
}
for (Room room : threeVRoomList) {
room.checkInvalidMember(userId);
}
}
/**
* 给处在主页面的人发送人数变动信息
*/
private void notifyHomeInfo() {
for (UserClient uClient : idleUserList) {
if (uClient.state == UserClient.STATE_IN_HOME) {
sendHomeInfo(uClient);
}
}
}
/**
* 房间列表变化
* @param room
*/
public void refreshRoom(Room room) {
Cmd cmd = new Cmd(Cmd.REFRESH_ROOM);
cmd.data = room.toJsonSummary();
for (UserClient uClient : idleUserList) {
if (uClient.state == UserClient.STATE_IN_HALL && uClient.getReqRoomSize() == room.capicity) {
uClient.sendCmd(cmd);
}
}
notifyHomeInfo();
}
/*
* 创建新房间
*/
public Room createNewRoom(UserClient uClient) {
List<Room> roomList = getMatchRoomList(uClient.getReqRoomSize());
boolean find = false;
Room rRoom = null;
//查找是否有空房间可以使用
for (Room room : roomList) {
if (room.state == State.EMPTY) {
rRoom = room;
room.addMember(uClient);
find = true;
break;
}
}
//无空房间,重新创建
if (!find) {
Room room = new Room(uClient);
roomList.add(room);
rRoom = room;
}
return rRoom;
}
/**
* 用户加入房间
* @param uClient
* @param roomId : 房间id
*/
public Room joinRoom(UserClient uClient, int roomId) {
int capicity = uClient.getReqRoomSize();
List<Room> roomList = getMatchRoomList(capicity);
int size = roomList.size();
Room room = null;
for (int i = size - 1; i >= 0; i--) {
room = roomList.get(i);
if (room.id == roomId) {
room.addMember(uClient);
break;
}
}
return room;
}
}
3. android 客户端连接ServerConn
package com.seya.onlineanswer.logic;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Timer;
import java.util.TimerTask;
import org.json.JSONException;
import org.json.JSONObject;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import com.seya.onlineanswer.ui.Cmd;
import com.seya.onlineanswer.ui.StageActivity;
import com.seya.onlineanswer.util.GlobalVar;
import com.seya.onlineanswer.util.LogX;
import com.seya.onlineanswer.util.PreferencesUtil;
/**
* Server connection thread
* @author Administrator
*
*/
public class ServerConn implements Runnable {
public static final int PING_DELAY = 2*1000; //2秒ping一次
Timer timer;
private BufferedReader in = null;
private PrintWriter out = null;
private Handler mHandler = null;
public ServerConn(Socket server, Handler handler) throws IOException {
/* obtain an input stream from the server */
in = new BufferedReader(new InputStreamReader(
server.getInputStream()));
out = new PrintWriter(server.getOutputStream(), true);
mHandler = handler;
}
public void setHandler (Handler handler) {
mHandler = handler;
}
private void sendMsg(String msg) {
new AsyncTask<String, Object, Boolean>() {
@Override
protected Boolean doInBackground(String... params) {
//防止消息连在一起发送
synchronized (out) {
out.println(params[0]);
out.flush();
}
return null;
}
}.execute(msg);
}
/**
* 客户端Ping服务器,测试连接
*/
public void ping() {
timer = new Timer();
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
sendMsg("");
}
};
timer.schedule(timerTask, 0, PING_DELAY);
}
public void cancelPing() {
if (timer != null) {
timer.cancel();
timer = null;
}
}
public void sendUnPresenceMsg(String msg) {
new AsyncTask<String, Object, Boolean>() {
@Override
protected Boolean doInBackground(String... params) {
out.println(params[0]);
return null;
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
mHandler.sendEmptyMessage(StageActivity.MSG_SHUTDOWN_CONN);
}
}.execute(msg);
}
public void run() {
String msg = null;
try {
/**
* loop message from server and process
*/
while ((msg = in.readLine()) != null) {
LogX.print("服务器返回=="+msg);
Message uiMsg = mHandler.obtainMessage(StageActivity.MSG_SERVER_PUSH);
uiMsg.obj = msg;
uiMsg.sendToTarget();
}
} catch (IOException e) {
System.err.println(e);
}
}
public void quit() {
JSONObject quit = new JSONObject();
try {
quit.put("cmd", Cmd.QUIT);
JSONObject data = new JSONObject();
data.put("userid", GlobalVar.userId);
quit.put("data", data);
sendMsg(quit.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
//下线
public void unPresence() {
JSONObject quit = new JSONObject();
try {
LogX.print("===unPresence===");
quit.put("cmd", Cmd.UNPRESENCE);
JSONObject data = new JSONObject();
data.put("userid", GlobalVar.userId);
quit.put("data", data);
sendUnPresenceMsg(quit.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
/**
* 进入房间
* @param roomSize
*/
public void join(int roomSize, String type, int roomId, boolean isFromHome, int challegeUid) {
JSONObject join = new JSONObject();
try {
join.put("cmd", Cmd.JOIN);
//进入房间, 再次验证
JSONObject data = new JSONObject();
data.put("userid", GlobalVar.userId);
data.put("roomsize", roomSize);
data.put("type", type);
data.put("roomid", roomId);
data.put("isFromHome", isFromHome);
data.put("chaUid", challegeUid);
join.put("data", data);
LogX.print("發送登錄: "+join.toString());
sendMsg(join.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
/**
* 发送就绪命令
*/
public void ready() {
JSONObject ready = new JSONObject();
try {
ready.put("cmd", Cmd.READY);
//进入房间, 再次验证
JSONObject data = new JSONObject();
data.put("userid", GlobalVar.userId);
ready.put("data", data);
LogX.print("發送就绪: "+ready.toString());
sendMsg(ready.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
}
欢迎了解学习交流
豌豆荚地址: http://apps.wandoujia.com/search?key=%E5%85%A8%E6%B0%91%E7%AD%94%E9%A2%98&source=index
先上个游戏截图:
豌豆荚地址: http://apps.wandoujia.com/search?key=%E5%85%A8%E6%B0%91%E7%AD%94%E9%A2%98&source=index
本文概要介绍如何通过java nio来开发android客户端与服务器socket通信的过程。
1. 为什么要用java NIO
常规的socket通信为阻塞方式,服务器接收到消息并进行处理,处理完一个才能处理下一个。 如果要同时处理,就得自己开线程,为每一个客户端连接做一个线程,这样当连接数大的情况下,上万以上,服务器就难以承受了。 JAVA NIO是jdk1.4提供的API, 主要原理是以监听机制来处理客户端的连接。主要包含buffer和channel.
2. 服务器示例代码
package com.seya.onlineserver.socket.nio;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Vector;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.seya.onlineserver.jpush.JPushManager;
import com.seya.onlineserver.socket.dao.UserDAO;
import com.seya.onlineserver.socket.nio.Room.State;
/**
* NIO服务端
* @author Seyason
*/
public class NIOServer implements MsgProcessor{
//用户在线标示
public static final int STATUS_ONLINE = 1;
public static final int STATUS_OFFLINE = 0;
private static final int PORT = 2121;
//全部用户集合
private Vector<UserClient> allUserList = new Vector<UserClient>();
//房间数
private Vector<Room> oneVRoomList = new Vector<Room>();
private Vector<Room> twoVRoomList = new Vector<Room>();
private Vector<Room> threeVRoomList = new Vector<Room>();
public static Vector<UserClient> idleUserList = new Vector<UserClient>();
public Vector<UserClient> challegePendingList = new Vector<UserClient>();
//通道管理器
private Selector selector;
UserDAO uDao = new UserDAO();
/**
* 获得一个ServerSocket通道,并对该通道做一些初始化的工作
* @param port 绑定的端口号
* @throws IOException
*/
public void initServer(int port) throws IOException {
// 获得一个ServerSocket通道
ServerSocketChannel serverChannel = ServerSocketChannel.open();
// 设置通道为非阻塞
serverChannel.configureBlocking(false);
// 将该通道对应的ServerSocket绑定到port端口
serverChannel.socket().bind(new InetSocketAddress(port));
// 获得一个通道管理器
this.selector = Selector.open();
//将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,注册该事件后,
//当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
}
public static void startUp() {
NIOServer server = new NIOServer();
try {
server.initServer(PORT);
server.listen();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理
* @throws IOException
*/
@SuppressWarnings("unchecked")
public void listen() throws IOException {
System.out.println("服务端启动成功!");
// 轮询访问selector
while (true) {
//当注册的事件到达时,方法返回;否则,该方法会一直阻塞
selector.select();
// 获得selector中选中的项的迭代器,选中的项为注册的事件
Iterator ite = this.selector.selectedKeys().iterator();
while (ite.hasNext()) {
SelectionKey key = (SelectionKey) ite.next();
// 删除已选的key,以防重复处理
ite.remove();
// 客户端请求连接事件
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) key
.channel();
// 获得和客户端连接的通道
SocketChannel channel = server.accept();
// 设置成非阻塞
channel.configureBlocking(false);
UserClient uClient = new UserClient(channel, this);
//在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。
channel.register(this.selector, SelectionKey.OP_READ, uClient);
} else if (key.isReadable()) {
read(key);
}
}
}
}
public void addIdleMemb(UserClient uClient) {
idleUserList.add(uClient);
}
private int getOnlineMembCnt() {
int oneVMembCount = 0;
for(Room room : oneVRoomList) {
oneVMembCount += room.getMembCount();
}
int twoVMembCount = 0;
for(Room room : twoVRoomList) {
twoVMembCount += room.getMembCount();
}
int threeVMembCount = 0;
for(Room room : threeVRoomList) {
threeVMembCount += room.getMembCount();
}
int idleCount = 0;
for (UserClient userClient : idleUserList) {
if (userClient.state == UserClient.STATE_IN_HALL) {
if (userClient.getReqRoomSize() == 2) {
oneVMembCount++;
} else if (userClient.getReqRoomSize() == 4) {
twoVMembCount++;
} else if (userClient.getReqRoomSize() == 6) {
threeVMembCount++;
}
} else if (userClient.state == UserClient.STATE_IN_HOME) {
idleCount++;
}
}
//总在线人数
int totalCount = idleCount + oneVMembCount + twoVMembCount + threeVMembCount;
return totalCount;
}
private JSONObject getHomeJsonInfo() {
JSONObject json = new JSONObject();
int oneVMembCount = 0;
for(Room room : oneVRoomList) {
oneVMembCount += room.getMembCount();
}
int twoVMembCount = 0;
for(Room room : twoVRoomList) {
twoVMembCount += room.getMembCount();
}
int threeVMembCount = 0;
for(Room room : threeVRoomList) {
threeVMembCount += room.getMembCount();
}
int idleCount = 0;
for (UserClient userClient : idleUserList) {
if (userClient.state == UserClient.STATE_IN_HALL) {
if (userClient.getReqRoomSize() == 2) {
oneVMembCount++;
} else if (userClient.getReqRoomSize() == 4) {
twoVMembCount++;
} else if (userClient.getReqRoomSize() == 6) {
threeVMembCount++;
}
} else if (userClient.state == UserClient.STATE_IN_HOME) {
idleCount++;
}
}
if (oneVMembCount == 0) {
Random r = new Random();
oneVMembCount = r.nextInt(5);
}
json.put("oneVMembCount", oneVMembCount);
json.put("twoVMembCount", twoVMembCount);
json.put("threeVMembCount", threeVMembCount);
//总在线人数
int totalCount = idleCount + oneVMembCount + twoVMembCount + threeVMembCount;
// Random r = new Random();
// totalCount = r.nextInt(10000);
json.put("totalCount", totalCount);
return json;
}
/**
* 处理读取客户端发来的信息 的事件
* @param key
* @throws IOException
*/
public void read(SelectionKey key) {
// 服务器可读取消息:得到事件发生的Socket通道
UserClient uClient = (UserClient) key.attachment();
boolean isSuccess = uClient.onMessage();
if (!isSuccess) {
//发送失败,连接异常
removeFromIdle(uClient.getUserId());
}
}
@Override
public void process(String msg, UserClient userClient) {
try {
JSONObject json = JSON.parseObject(msg);
String cmd = json.getString("cmd");
if (Cmd.JOIN.equals(cmd)) {
//加入房间
json = json.getJSONObject("data");
String type = json.getString("type");
userClient.populateFromJson(json);
Room room = null;
if ("new".equals(type)) {
room = createNewRoom(userClient);
userClient.setFromHome(false);
} else if ("fast".equals(type)) {
room = fastJoin(userClient);
if (json.containsKey("isFromHome")) {
userClient.setFromHome(json.getBooleanValue("isFromHome"));
} else {
userClient.setFromHome(false);
}
} else if (Cmd.ENTERHALL.equals(cmd)) {
json = json.getJSONObject("data");
userClient.populateFromJson(json);
userClient.state = UserClient.STATE_IN_HALL;
notifyHomeInfo();
Cmd enter = new Cmd(Cmd.ENTERHALL);
JSONObject msgData = new JSONObject();
msgData.put("userid", userClient.getUserId());
msgData.put("username", userClient.userInfo.getUsername());
msgData.put("nickname", userClient.userInfo.getNickname());
msgData.put("msg", userClient.userInfo.getNickname() + "刚刚走进了" + getHallName(userClient.getReqRoomSize()) + "房间");
enter.data = msgData;
sendToIdle(enter);
} else if (Cmd.QUIT.equals(cmd)) {
//退出房间大厅,回到主界面
userClient.state = UserClient.STATE_IN_HOME;
notifyHomeInfo();
} else if (Cmd.UNPRESENCE.equals(cmd)) {
//退出登录, 断开连接
System.out.println("===退出登录===" + userClient.getUserId());
idleUserList.remove(userClient);
allUserList.remove(userClient);
//从挑战者列表中清除
for (int i=0; i < challegePendingList.size(); i++) {
if (challegePendingList.get(i).getUserId() == userClient.getUserId()) {
challegePendingList.remove(i);
i--;
}
}
uDao.setStatus(STATUS_OFFLINE, userClient.getUserId());
System.gc();
notifyHomeInfo();
} else if (Cmd.ROOMLIST.equals(cmd)) {
//客户端主动获取房间列表
sendRoomList(userClient);
} else if (Cmd.HOME_INFO.equals(cmd)) {
//客户端主动获取主页数据
sendHomeInfo(userClient);
} else if (Cmd.PRESENCE.equals(cmd)) {
Cmd alert = new Cmd(Cmd.ALERT);
JSONObject data = new JSONObject();
json = json.getJSONObject("data");
userClient.populateFromJson(json);
***********
alert.data = data;
userClient.sendCmd(alert);
notifyHomeInfo();
//给不在多人对战房间的人发送消息
sendToIdle(msg);
}
} catch (JSONException ex) {
ex.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void sendToIdle(String msg) throws IOException {
for (UserClient idleUser : idleUserList) {
idleUser.sendJsonMsg(msg);
}
}
private void sendToIdle(Cmd msg) throws IOException {
for (UserClient idleUser : idleUserList) {
idleUser.sendCmd(msg);
}
}
/**
* 删除无效链接对象
*/
private void checkInvalidUserClient(int userId) {
removeFromIdle(userId);
for (Room room : oneVRoomList) {
room.checkInvalidMember(userId);
}
for (Room room : twoVRoomList) {
room.checkInvalidMember(userId);
}
for (Room room : threeVRoomList) {
room.checkInvalidMember(userId);
}
}
/**
* 给处在主页面的人发送人数变动信息
*/
private void notifyHomeInfo() {
for (UserClient uClient : idleUserList) {
if (uClient.state == UserClient.STATE_IN_HOME) {
sendHomeInfo(uClient);
}
}
}
/**
* 房间列表变化
* @param room
*/
public void refreshRoom(Room room) {
Cmd cmd = new Cmd(Cmd.REFRESH_ROOM);
cmd.data = room.toJsonSummary();
for (UserClient uClient : idleUserList) {
if (uClient.state == UserClient.STATE_IN_HALL && uClient.getReqRoomSize() == room.capicity) {
uClient.sendCmd(cmd);
}
}
notifyHomeInfo();
}
/*
* 创建新房间
*/
public Room createNewRoom(UserClient uClient) {
List<Room> roomList = getMatchRoomList(uClient.getReqRoomSize());
boolean find = false;
Room rRoom = null;
//查找是否有空房间可以使用
for (Room room : roomList) {
if (room.state == State.EMPTY) {
rRoom = room;
room.addMember(uClient);
find = true;
break;
}
}
//无空房间,重新创建
if (!find) {
Room room = new Room(uClient);
roomList.add(room);
rRoom = room;
}
return rRoom;
}
/**
* 用户加入房间
* @param uClient
* @param roomId : 房间id
*/
public Room joinRoom(UserClient uClient, int roomId) {
int capicity = uClient.getReqRoomSize();
List<Room> roomList = getMatchRoomList(capicity);
int size = roomList.size();
Room room = null;
for (int i = size - 1; i >= 0; i--) {
room = roomList.get(i);
if (room.id == roomId) {
room.addMember(uClient);
break;
}
}
return room;
}
}
3. android 客户端连接ServerConn
package com.seya.onlineanswer.logic;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Timer;
import java.util.TimerTask;
import org.json.JSONException;
import org.json.JSONObject;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import com.seya.onlineanswer.ui.Cmd;
import com.seya.onlineanswer.ui.StageActivity;
import com.seya.onlineanswer.util.GlobalVar;
import com.seya.onlineanswer.util.LogX;
import com.seya.onlineanswer.util.PreferencesUtil;
/**
* Server connection thread
* @author Administrator
*
*/
public class ServerConn implements Runnable {
public static final int PING_DELAY = 2*1000; //2秒ping一次
Timer timer;
private BufferedReader in = null;
private PrintWriter out = null;
private Handler mHandler = null;
public ServerConn(Socket server, Handler handler) throws IOException {
/* obtain an input stream from the server */
in = new BufferedReader(new InputStreamReader(
server.getInputStream()));
out = new PrintWriter(server.getOutputStream(), true);
mHandler = handler;
}
public void setHandler (Handler handler) {
mHandler = handler;
}
private void sendMsg(String msg) {
new AsyncTask<String, Object, Boolean>() {
@Override
protected Boolean doInBackground(String... params) {
//防止消息连在一起发送
synchronized (out) {
out.println(params[0]);
out.flush();
}
return null;
}
}.execute(msg);
}
/**
* 客户端Ping服务器,测试连接
*/
public void ping() {
timer = new Timer();
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
sendMsg("");
}
};
timer.schedule(timerTask, 0, PING_DELAY);
}
public void cancelPing() {
if (timer != null) {
timer.cancel();
timer = null;
}
}
public void sendUnPresenceMsg(String msg) {
new AsyncTask<String, Object, Boolean>() {
@Override
protected Boolean doInBackground(String... params) {
out.println(params[0]);
return null;
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
mHandler.sendEmptyMessage(StageActivity.MSG_SHUTDOWN_CONN);
}
}.execute(msg);
}
public void run() {
String msg = null;
try {
/**
* loop message from server and process
*/
while ((msg = in.readLine()) != null) {
LogX.print("服务器返回=="+msg);
Message uiMsg = mHandler.obtainMessage(StageActivity.MSG_SERVER_PUSH);
uiMsg.obj = msg;
uiMsg.sendToTarget();
}
} catch (IOException e) {
System.err.println(e);
}
}
public void quit() {
JSONObject quit = new JSONObject();
try {
quit.put("cmd", Cmd.QUIT);
JSONObject data = new JSONObject();
data.put("userid", GlobalVar.userId);
quit.put("data", data);
sendMsg(quit.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
//下线
public void unPresence() {
JSONObject quit = new JSONObject();
try {
LogX.print("===unPresence===");
quit.put("cmd", Cmd.UNPRESENCE);
JSONObject data = new JSONObject();
data.put("userid", GlobalVar.userId);
quit.put("data", data);
sendUnPresenceMsg(quit.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
/**
* 进入房间
* @param roomSize
*/
public void join(int roomSize, String type, int roomId, boolean isFromHome, int challegeUid) {
JSONObject join = new JSONObject();
try {
join.put("cmd", Cmd.JOIN);
//进入房间, 再次验证
JSONObject data = new JSONObject();
data.put("userid", GlobalVar.userId);
data.put("roomsize", roomSize);
data.put("type", type);
data.put("roomid", roomId);
data.put("isFromHome", isFromHome);
data.put("chaUid", challegeUid);
join.put("data", data);
LogX.print("發送登錄: "+join.toString());
sendMsg(join.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
/**
* 发送就绪命令
*/
public void ready() {
JSONObject ready = new JSONObject();
try {
ready.put("cmd", Cmd.READY);
//进入房间, 再次验证
JSONObject data = new JSONObject();
data.put("userid", GlobalVar.userId);
ready.put("data", data);
LogX.print("發送就绪: "+ready.toString());
sendMsg(ready.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
}
欢迎了解学习交流
豌豆荚地址: http://apps.wandoujia.com/search?key=%E5%85%A8%E6%B0%91%E7%AD%94%E9%A2%98&source=index