手机网络象棋开发(2):网络通信、逻辑处理模块

上次简单介绍了Server的写法,这个类比较简单,主要的功能包括:
1. 初始化,包括玩家列表、游戏桌子列表
2. 接收手机客户端连接
3. 启动网络连接处理


今天主要介绍:网络通讯类和业务处理类

Network类:
主要负责:
1. 接收手机客户端的连接
按照协议读取数据后,添加到消息队列
此处需要处理同步问题
2. 取出消息队列,调用业务逻辑类进行处理
主要是根据消息的cmdType
3. 发送消息
依次读取发送消息队列的消息,
按照协议,依次将cmdType, playerId, msg.length, msg 发送到客户端

具体代码如下:

/**
*
*/
package net.tuolian.newserver;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
* @author sean
*
* @since 2009/06/17
*
* 1. 构造方法
* 2. init, 获得输入输出流
* 3. 启动线程
*
* 问题: 1.全部读取服务器数据到Byte数组后,如何区别各个位数的内容
* 2. 如果光读取一个cmdType,然后由相应的方法来读取内容
*/
public class Network extends Thread {

Socket socket;
DataInputStream dis;
DataOutputStream dos;
public static List<Message> list = Collections.synchronizedList(new ArrayList<Message>()); //消息队列

/**
* 构造函数
* 初始化
* @param socket
*/
public Network(Socket socket) {
// TODO Auto-generated constructor stub
this.socket = socket;
init();
}

LogicHandler logic;
/**
* 初始化,获得输入输出流
*/
private void init() {
// TODO Auto-generated method stub
try {
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

logic = new LogicHandler(this);
}

/**
* 接收数据 逻辑处理
*/
public void run() {

while (true) {
// 接收客户端数据
recieveData();

// 逻辑处理
// handleLogic();
logic.logicProcess();

// 发送数据
sendData();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

/**
* 接收来自客户端的数据
* 重构:
* 本方法只是负责读取数据
* 同时打包成msg, 放入msgList
*
* @return
*/
private void recieveData() {
// TODO Auto-generated method stub
int len = 0;

try {
len = dis.available();

if(len <= 0){
return;
}

int cmdType = dis.readInt();
int playerId = dis.readInt();
len = dis.readInt();
byte[] data = new byte[len];
dis.read(data);
String str = new String(data);

//构建消息对象,放入队列
Message msg = new Message(cmdType, str);
if(playerId != 0){
msg.setPlayerId(playerId);
}
else{
//如果playerId==0, 则表示属于未注册的新客户端,设置为1
msg.setPlayerId(1);
}

list.add(msg);

} catch (IOException e) {
// TODO Auto-generated catch block
close();
System.out.println("网络连接错误");
// e.printStackTrace();
}
}


/**
* 负责根据消息的内容,大包成需要的格式,一次写入输出流
*
* @param msg
* @param player
*/
private void packMessage(Message msg, Player player) {
// TODO 将消息打包成msg进行发送

try {
player.getOutputStream().writeInt(msg.getCmdType());
System.out.println("Server: send cmdType: " + msg.getCmdType());
player.getOutputStream().writeInt(msg.getPlayerId());
System.out.println("Server: send playerId: " + msg.getPlayerId());
player.getOutputStream().writeInt(
msg.getMessage().getBytes().length);
player.getOutputStream().write(msg.getMessage().getBytes());
System.out.println("Server: send cmdType: " + msg.getMessage());
System.out.println("send data ok");

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}


/**
* 发送数据到客户端 获取player中包含的输出流通道
*/
private void sendData() {
// TODO Auto-generated method stub
if (Server.playerMap.isEmpty()) {
return;
}

Iterator it = Server.playerMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, Player> entry = (Entry<Integer, Player>) it
.next();
Player player = entry.getValue();

if (player == null) {
return;
}

/**
* 如果数据不为空,则发送队列中的数据到客户端
*/
if (!player.data.isEmpty()) {
Message msg = (Message) player.data.pop();
packMessage(msg, player);

}
}
}

/**
* 关闭连接
*/
private void close() {
try {
dis.close();
dos.close();
socket.close();
} catch (Exception e) {
}
}
}


逻辑处理类LogicHandler.java

该类的主要功能
1. 去除消息队列的消息对象
2. 分析消息的cmdType
3. 然后分发给相应的消息处理方法进行处理
基本流程包括:
玩家注册:就是将玩家对象放入playerMap的哈希表待用
玩家坐下:根据发送过来的消息,更新桌子列表情况,然后返回消息
玩家请求开始:设置玩家的状态为开始,检查该游戏桌子的状态是否满足条件
满足的话,就开始游戏,并且调用相关的裁判类进行逻辑判断处理
玩家的棋子移动:根据具体的棋子坐标,更新裁判类的棋牌位置
其他还包括玩家退出、离开游戏等,目前还未完成。

详细查看代码:

/**
*
*/
package net.tuolian.newserver;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
* @author sean
*
*
*/
public class LogicHandler {
private List list = null;

private Network network;


public LogicHandler(Network network){
this.network = network;

list = network.list;
}

/**
*
*/
public void logicProcess(){
if( list.size() <= 0){
return;
}
Message msg = (Message) list.remove(0);
if( msg == null){
return;
}

int cmdType = msg.getCmdType();

switch (cmdType) {
case Message.REGISTER_REQ:
handleRegister(msg);
break;

case Message.TAKE_REQ:
handleTake(msg);
break;

case Message.START_REQ:
handleStart(msg);
break;

case Message.MOVE_REQ:
handleMove(msg);
break;

case Message.EXIT_REQ:
handleExit(msg);
break;

case Message.EXITGAME_REQ:
handleExitGame(msg);
break;

default:

break;
}

}

/**
* 初次登陆用户的注册逻辑
* 将好友放入playerMap保存
* 设置playerId
*
*/
private void handleRegister(Message msg) {
Server.counter++;
System.out.println("counter: " + Server.counter);

Player player = null;
player = new Player();
player.setID(Server.counter);

player.setOutputStream(network.dos);

if(player != null){
Server.playerMap.put(new Integer(Server.counter), player);

//发送桌子信息到客户端
sendDesksInfo(player);
}
}

/**
* 处理客户端坐下的动作
*/
private void handleTake(Message msg) {
String message = null;
Player player = null;

int playerId = msg.getPlayerId();

System.out.println("handleTake playerid " + playerId);
player = Server.playerMap.get(playerId);
message = msg.getMessage();
System.out.println("Server recieve take msg: " + message);

try {
int index1 = message.indexOf(",");
int index2 = message.indexOf(",", index1 + 1);
int dindex = Integer
.parseInt(message.substring(index1 + 1, index2));
int pindex = Integer.parseInt(message.substring(index2 + 1));

if (dindex < Server.DESKNUM && dindex >= 0) {
if (Server.desks[dindex].isEmpty(pindex)) {
Server.desks[dindex].setPlayer(pindex, player);
player.setDesk(Server.desks[dindex]);

sendMessage(Message.UPDATEDESK_RESP, player, "takeseat");
updateClientsDesk(dindex);
}
}
} catch (Exception exc) {
}
}

/**
* 遍历所有玩家,更新桌子的玩家情况
*
* @param dindex
*/
private void updateClientsDesk(int dindex) {
// TODO Auto-generated method stub
Iterator it = Server.playerMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, Player> entry = (Entry<Integer, Player>) it
.next();
Player player = (Player) entry.getValue();
updateDesks(player, dindex);
}
}

/**
* 更新具体桌号的玩家情况
*
* @param player
* @param dindex
*/
private void updateDesks(Player player, int dindex) {
// TODO Auto-generated method stub
String message = "updatedesk," + dindex;
String str = "";

for (int i = 0; i < Server.desks[dindex].getPlayersCounter(); i++) {
if (i == 0) {
if (Server.desks[dindex].isEmpty(i)) {
str = "0";
} else {
str = "1";
}
} else {
if (Server.desks[dindex].isEmpty(i)) {
str = "0";
} else {
str = "1";
}
}
message = message + str;
}
sendMessage(Message.UPDATEDESK_RESP, player, message);
System.out.println("Server send updateDesk message");
}

/**
* 处理开始游戏的状态
*/
private void handleStart(Message msg) {
// TODO Auto-generated method stub
int playerId = msg.getPlayerId();
Player player = Server.playerMap.get(playerId);

// 开始处理游戏开始的逻辑
player.start();
Desk desk1 = player.getDesk();

if (desk1.isReady()) {
desk1.start();
}
System.out.println("Server: handle start process ok");
}

/**
* 处理游戏中移动的业务逻辑
*/
private void handleMove(Message msg) {
Player player = null;

int playerId = msg.getPlayerId();
String message1 = msg.getMessage();
System.out.println("server recieved move msg: "
+ message1);

player = Server.playerMap.get(playerId);
Desk desk = player.getDesk();
desk.moveChess(message1);
}

/**
* 退出当前游戏,回到游戏大厅
* @param msg
*/
private void handleExit(net.tuolian.newserver.Message msg) {
// TODO Auto-generated method stub


}

/**
* 玩家退出当前游戏的逻辑处理
*/
private void handleExitGame(Message msg) {
// TODO 玩家退出当前游戏的逻辑处理, 得到玩家的桌子,玩家初始化,桌子去掉玩家、玩家列表去掉玩家,更新桌子
int playerId = msg.getPlayerId();
Player player = Server.playerMap.get(playerId);
Desk desk = player.getDesk();

desk.removePlayer(player);
Server.playerMap.remove(player);
player = null;
updateClientsDesk(desk.getID());
}

/**
* 发送桌子的数据信息
*
* @param player
*/
private void sendDesksInfo(Player player) {
// TODO Auto-generated method stub
int cmdType = Message.DESKS_RESP;

String message = "desks," + Server.DESKNUM;
for (int i = 0; i < Server.DESKNUM; i++) {
String str = "";
for (int j = 0; j < Server.desks[i].getPlayersCounter(); j++) {
if (j == 0) {
if (Server.desks[i].isEmpty(j))
str = "0";
else
str = "1";
} else {
if (Server.desks[i].isEmpty(j))
str = str + ",0";
else
str = str + ",1";
}
}
message = message + ":" + str;
}
sendMessage(cmdType, player, message);
}

/**
* 发送消息
* 将速度打包成msg,放入队列中等待发送
* @param cmdType
* @param player
* @param message
*/
private void sendMessage(int cmdType, Player player, String message) {
// TODO Auto-generated method stub
Message msg = new Message(cmdType, message);
msg.setPlayerId(player.getID());
player.data.push(msg);
}
}



注:很多代码参考了java项目全程实录
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值