基于Java NIO的手机答题游戏开发

先上个游戏截图:

豌豆荚地址:http://apps.wandoujia.com/search?key=%E5%85%A8%E6%B0%91%E7%AD%94%E9%A2%98&source=index

本文概要介绍如何通过javanio来开发android客户端与服务器socket通信的过程。

1.为什么要用javaNIO

常规的socket通信为阻塞方式,服务器接收到消息并进行处理,处理完一个才能处理下一个。如果要同时处理,就得自己开线程,为每一个客户端连接做一个线程,这样当连接数大的情况下,上万以上,服务器就难以承受了。JAVANIO是jdk1.4提供的API,主要原理是以监听机制来处理客户端的连接。主要包含buffer和channel.

2.服务器示例代码

packagecom.seya.onlineserver.socket.nio;

importjava.io.File;

importjava.io.IOException;

importjava.net.InetSocketAddress;

importjava.nio.channels.SelectionKey;

importjava.nio.channels.Selector;

importjava.nio.channels.ServerSocketChannel;

importjava.nio.channels.SocketChannel;

importjava.util.ArrayList;

importjava.util.Arrays;

importjava.util.Comparator;

importjava.util.Iterator;

importjava.util.List;

importjava.util.Random;

importjava.util.Vector;

importcom.alibaba.fastjson.JSON;

importcom.alibaba.fastjson.JSONArray;

importcom.alibaba.fastjson.JSONException;

importcom.alibaba.fastjson.JSONObject;

importcom.seya.onlineserver.jpush.JPushManager;

importcom.seya.onlineserver.socket.dao.UserDAO;

importcom.seya.onlineserver.socket.nio.Room.State;

/**

*NIO服务端

*@authorSeyason

*/

publicclassNIOServerimplementsMsgProcessor{

//用户在线标示

publicstaticfinalintSTATUS_ONLINE=1;

publicstaticfinalintSTATUS_OFFLINE=0;

privatestaticfinalintPORT=2121;

//全部用户集合

privateVector<UserClient>allUserList=newVector<UserClient>();

//房间数

privateVector<Room>oneVRoomList=newVector<Room>();

privateVector<Room>twoVRoomList=newVector<Room>();

privateVector<Room>threeVRoomList=newVector<Room>();

publicstaticVector<UserClient>idleUserList=newVector<UserClient>();

publicVector<UserClient>challegePendingList=newVector<UserClient>();

//通道管理器

privateSelectorselector;

UserDAOuDao=newUserDAO();

/**

*获得一个ServerSocket通道,并对该通道做一些初始化的工作

*@paramport绑定的端口号

*@throwsIOException

*/

publicvoidinitServer(intport)throwsIOException{

//获得一个ServerSocket通道

ServerSocketChannelserverChannel=ServerSocketChannel.open();

//设置通道为非阻塞

serverChannel.configureBlocking(false);

//将该通道对应的ServerSocket绑定到port端口

serverChannel.socket().bind(newInetSocketAddress(port));

//获得一个通道管理器

this.selector=Selector.open();

//将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,注册该事件后,

//当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。

serverChannel.register(selector,SelectionKey.OP_ACCEPT);

}

publicstaticvoidstartUp(){

NIOServerserver=newNIOServer();

try{

server.initServer(PORT);

server.listen();

}catch(IOExceptione){

e.printStackTrace();

}

}

/**

*采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理

*@throwsIOException

*/

@SuppressWarnings("unchecked")

publicvoidlisten()throwsIOException{

System.out.println("服务端启动成功!");

//轮询访问selector

while(true){

//当注册的事件到达时,方法返回;否则,该方法会一直阻塞

selector.select();

//获得selector中选中的项的迭代器,选中的项为注册的事件

Iteratorite=this.selector.selectedKeys().iterator();

while(ite.hasNext()){

SelectionKeykey=(SelectionKey)ite.next();

//删除已选的key,以防重复处理

ite.remove();

//客户端请求连接事件

if(key.isAcceptable()){

ServerSocketChannelserver=(ServerSocketChannel)key

.channel();

//获得和客户端连接的通道

SocketChannelchannel=server.accept();

//设置成非阻塞

channel.configureBlocking(false);

UserClientuClient=newUserClient(channel,this);

//在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。

channel.register(this.selector,SelectionKey.OP_READ,uClient);

}elseif(key.isReadable()){

read(key);

}

}

}

}

publicvoidaddIdleMemb(UserClientuClient){

idleUserList.add(uClient);

}

privateintgetOnlineMembCnt(){

intoneVMembCount=0;

for(Roomroom:oneVRoomList){

oneVMembCount+=room.getMembCount();

}

inttwoVMembCount=0;

for(Roomroom:twoVRoomList){

twoVMembCount+=room.getMembCount();

}

intthreeVMembCount=0;

for(Roomroom:threeVRoomList){

threeVMembCount+=room.getMembCount();

}

intidleCount=0;

for(UserClientuserClient:idleUserList){

if(userClient.state==UserClient.STATE_IN_HALL){

if(userClient.getReqRoomSize()==2){

oneVMembCount++;

}elseif(userClient.getReqRoomSize()==4){

twoVMembCount++;

}elseif(userClient.getReqRoomSize()==6){

threeVMembCount++;

}

}elseif(userClient.state==UserClient.STATE_IN_HOME){

idleCount++;

}

}

//总在线人数

inttotalCount=idleCount+oneVMembCount+twoVMembCount+threeVMembCount;

returntotalCount;

}

privateJSONObjectgetHomeJsonInfo(){

JSONObjectjson=newJSONObject();

intoneVMembCount=0;

for(Roomroom:oneVRoomList){

oneVMembCount+=room.getMembCount();

}

inttwoVMembCount=0;

for(Roomroom:twoVRoomList){

twoVMembCount+=room.getMembCount();

}

intthreeVMembCount=0;

for(Roomroom:threeVRoomList){

threeVMembCount+=room.getMembCount();

}

intidleCount=0;

for(UserClientuserClient:idleUserList){

if(userClient.state==UserClient.STATE_IN_HALL){

if(userClient.getReqRoomSize()==2){

oneVMembCount++;

}elseif(userClient.getReqRoomSize()==4){

twoVMembCount++;

}elseif(userClient.getReqRoomSize()==6){

threeVMembCount++;

}

}elseif(userClient.state==UserClient.STATE_IN_HOME){

idleCount++;

}

}

if(oneVMembCount==0){

Randomr=newRandom();

oneVMembCount=r.nextInt(5);

}

json.put("oneVMembCount",oneVMembCount);

json.put("twoVMembCount",twoVMembCount);

json.put("threeVMembCount",threeVMembCount);

//总在线人数

inttotalCount=idleCount+oneVMembCount+twoVMembCount+threeVMembCount;

//Randomr=newRandom();

//totalCount=r.nextInt(10000);

json.put("totalCount",totalCount);

returnjson;

}

/**

*处理读取客户端发来的信息的事件

*@paramkey

*@throwsIOException

*/

publicvoidread(SelectionKeykey){

//服务器可读取消息:得到事件发生的Socket通道

UserClientuClient=(UserClient)key.attachment();

booleanisSuccess=uClient.onMessage();

if(!isSuccess){

//发送失败,连接异常

removeFromIdle(uClient.getUserId());

}

}

@Override

publicvoidprocess(Stringmsg,UserClientuserClient){

try{

JSONObjectjson=JSON.parseObject(msg);

Stringcmd=json.getString("cmd");

if(Cmd.JOIN.equals(cmd)){

//加入房间

json=json.getJSONObject("data");

Stringtype=json.getString("type");

userClient.populateFromJson(json);

Roomroom=null;

if("new".equals(type)){

room=createNewRoom(userClient);

userClient.setFromHome(false);

}elseif("fast".equals(type)){

room=fastJoin(userClient);

if(json.containsKey("isFromHome")){

userClient.setFromHome(json.getBooleanValue("isFromHome"));

}else{

userClient.setFromHome(false);

}

}elseif(Cmd.ENTERHALL.equals(cmd)){

json=json.getJSONObject("data");

userClient.populateFromJson(json);

userClient.state=UserClient.STATE_IN_HALL;

notifyHomeInfo();

Cmdenter=newCmd(Cmd.ENTERHALL);

JSONObjectmsgData=newJSONObject();

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);

}elseif(Cmd.QUIT.equals(cmd)){

//退出房间大厅,回到主界面

userClient.state=UserClient.STATE_IN_HOME;

notifyHomeInfo();

}elseif(Cmd.UNPRESENCE.equals(cmd)){

//退出登录,断开连接

System.out.println("===退出登录==="+userClient.getUserId());

idleUserList.remove(userClient);

allUserList.remove(userClient);

//从挑战者列表中清除

for(inti=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();

}elseif(Cmd.ROOMLIST.equals(cmd)){

//客户端主动获取房间列表

sendRoomList(userClient);

}elseif(Cmd.HOME_INFO.equals(cmd)){

//客户端主动获取主页数据

sendHomeInfo(userClient);

}elseif(Cmd.PRESENCE.equals(cmd)){

Cmdalert=newCmd(Cmd.ALERT);

JSONObjectdata=newJSONObject();

json=json.getJSONObject("data");

userClient.populateFromJson(json);

***********

alert.data=data;

userClient.sendCmd(alert);

notifyHomeInfo();

//给不在多人对战房间的人发送消息

sendToIdle(msg);

}

}catch(JSONExceptionex){

ex.printStackTrace();

}catch(IOExceptione){

e.printStackTrace();

}

}

privatevoidsendToIdle(Stringmsg)throwsIOException{

for(UserClientidleUser:idleUserList){

idleUser.sendJsonMsg(msg);

}

}

privatevoidsendToIdle(Cmdmsg)throwsIOException{

for(UserClientidleUser:idleUserList){

idleUser.sendCmd(msg);

}

}

/**

*删除无效链接对象

*/

privatevoidcheckInvalidUserClient(intuserId){

removeFromIdle(userId);

for(Roomroom:oneVRoomList){

room.checkInvalidMember(userId);

}

for(Roomroom:twoVRoomList){

room.checkInvalidMember(userId);

}

for(Roomroom:threeVRoomList){

room.checkInvalidMember(userId);

}

}

/**

*给处在主页面的人发送人数变动信息

*/

privatevoidnotifyHomeInfo(){

for(UserClientuClient:idleUserList){

if(uClient.state==UserClient.STATE_IN_HOME){

sendHomeInfo(uClient);

}

}

}

/**

*房间列表变化

*@paramroom

*/

publicvoidrefreshRoom(Roomroom){

Cmdcmd=newCmd(Cmd.REFRESH_ROOM);

cmd.data=room.toJsonSummary();

for(UserClientuClient:idleUserList){

if(uClient.state==UserClient.STATE_IN_HALL&&uClient.getReqRoomSize()==room.capicity){

uClient.sendCmd(cmd);

}

}

notifyHomeInfo();

}

/*

*创建新房间

*/

publicRoomcreateNewRoom(UserClientuClient){

List<Room>roomList=getMatchRoomList(uClient.getReqRoomSize());

booleanfind=false;

RoomrRoom=null;

//查找是否有空房间可以使用

for(Roomroom:roomList){

if(room.state==State.EMPTY){

rRoom=room;

room.addMember(uClient);

find=true;

break;

}

}

//无空房间,重新创建

if(!find){

Roomroom=newRoom(uClient);

roomList.add(room);

rRoom=room;

}

returnrRoom;

}

/**

*用户加入房间

*@paramuClient

*@paramroomId:房间id

*/

publicRoomjoinRoom(UserClientuClient,introomId){

intcapicity=uClient.getReqRoomSize();

List<Room>roomList=getMatchRoomList(capicity);

intsize=roomList.size();

Roomroom=null;

for(inti=size-1;i>=0;i--){

room=roomList.get(i);

if(room.id==roomId){

room.addMember(uClient);

break;

}

}

returnroom;

}

}

3.android客户端连接ServerConn

packagecom.seya.onlineanswer.logic;

importjava.io.BufferedReader;

importjava.io.IOException;

importjava.io.InputStreamReader;

importjava.io.PrintWriter;

importjava.net.Socket;

importjava.util.Timer;

importjava.util.TimerTask;

importorg.json.JSONException;

importorg.json.JSONObject;

importandroid.os.AsyncTask;

importandroid.os.Handler;

importandroid.os.Message;

importcom.seya.onlineanswer.ui.Cmd;

importcom.seya.onlineanswer.ui.StageActivity;

importcom.seya.onlineanswer.util.GlobalVar;

importcom.seya.onlineanswer.util.LogX;

importcom.seya.onlineanswer.util.PreferencesUtil;

/**

*Serverconnectionthread

*@authorAdministrator

*

*/

publicclassServerConnimplementsRunnable{

publicstaticfinalintPING_DELAY=2*1000;//2秒ping一次

Timertimer;

privateBufferedReaderin=null;

privatePrintWriterout=null;

privateHandlermHandler=null;

publicServerConn(Socketserver,Handlerhandler)throwsIOException{

/*obtainaninputstreamfromtheserver*/

in=newBufferedReader(newInputStreamReader(

server.getInputStream()));

out=newPrintWriter(server.getOutputStream(),true);

mHandler=handler;

}

publicvoidsetHandler(Handlerhandler){

mHandler=handler;

}

privatevoidsendMsg(Stringmsg){

newAsyncTask<String,Object,Boolean>(){

@Override

protectedBooleandoInBackground(String...params){

//防止消息连在一起发送

synchronized(out){

out.println(params[0]);

out.flush();

}

returnnull;

}

}.execute(msg);

}

/**

*客户端Ping服务器,测试连接

*/

publicvoidping(){

timer=newTimer();

TimerTasktimerTask=newTimerTask(){

@Override

publicvoidrun(){

sendMsg("");

}

};

timer.schedule(timerTask,0,PING_DELAY);

}

publicvoidcancelPing(){

if(timer!=null){

timer.cancel();

timer=null;

}

}

publicvoidsendUnPresenceMsg(Stringmsg){

newAsyncTask<String,Object,Boolean>(){

@Override

protectedBooleandoInBackground(String...params){

out.println(params[0]);

returnnull;

}

@Override

protectedvoidonPostExecute(Booleanresult){

super.onPostExecute(result);

mHandler.sendEmptyMessage(StageActivity.MSG_SHUTDOWN_CONN);

}

}.execute(msg);

}

publicvoidrun(){

Stringmsg=null;

try{

/**

*loopmessagefromserverandprocess

*/

while((msg=in.readLine())!=null){

LogX.print("服务器返回=="+msg);

MessageuiMsg=mHandler.obtainMessage(StageActivity.MSG_SERVER_PUSH);

uiMsg.obj=msg;

uiMsg.sendToTarget();

}

}catch(IOExceptione){

System.err.println(e);

}

}

publicvoidquit(){

JSONObjectquit=newJSONObject();

try{

quit.put("cmd",Cmd.QUIT);

JSONObjectdata=newJSONObject();

data.put("userid",GlobalVar.userId);

quit.put("data",data);

sendMsg(quit.toString());

}catch(JSONExceptione){

e.printStackTrace();

}

}

//下线

publicvoidunPresence(){

JSONObjectquit=newJSONObject();

try{

LogX.print("===unPresence===");

quit.put("cmd",Cmd.UNPRESENCE);

JSONObjectdata=newJSONObject();

data.put("userid",GlobalVar.userId);

quit.put("data",data);

sendUnPresenceMsg(quit.toString());

}catch(JSONExceptione){

e.printStackTrace();

}

}

/**

*进入房间

*@paramroomSize

*/

publicvoidjoin(introomSize,Stringtype,introomId,booleanisFromHome,intchallegeUid){

JSONObjectjoin=newJSONObject();

try{

join.put("cmd",Cmd.JOIN);

//进入房间,再次验证

JSONObjectdata=newJSONObject();

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(JSONExceptione){

e.printStackTrace();

}

}

/**

*发送就绪命令

*/

publicvoidready(){

JSONObjectready=newJSONObject();

try{

ready.put("cmd",Cmd.READY);

//进入房间,再次验证

JSONObjectdata=newJSONObject();

data.put("userid",GlobalVar.userId);

ready.put("data",data);

LogX.print("發送就绪:"+ready.toString());

sendMsg(ready.toString());

}catch(JSONExceptione){

e.printStackTrace();

}

}

}

欢迎了解学习交流

豌豆荚地址:http://apps.wandoujia.com/search?key=%E5%85%A8%E6%B0%91%E7%AD%94%E9%A2%98&source=index

相关推荐