`
nbtlxx
  • 浏览: 253710 次
  • 性别: Icon_minigender_1
  • 来自: 宁波
社区版块
存档分类
最新评论

手机网络象棋开发(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项目全程实录
1
0
分享到:
评论

相关推荐

    手机网络象棋源码

    2. **棋局逻辑**:源码会详细描述象棋规则,如棋子的移动规则、吃子规则、将军和将死的判断、以及各种特殊棋局(如长将、五七炮等)的处理。这部分可能使用算法和数据结构来实现,如棋盘的状态表示、棋子的坐标系统...

    《php开发典型模块大全》源码之18_网络象棋游戏模块

    总的来说,《PHP开发典型模块大全》中的网络象棋游戏模块是一个综合性的实例,涵盖了PHP的很多重要知识点,包括但不限于游戏逻辑编程、用户交互、网络通信、数据库操作、安全性以及代码架构设计。通过研究这个模块,...

    基于java的网络象棋

    在这个网络象棋项目中,Java用于编写游戏逻辑、用户界面以及网络通信模块。 2. **TCP通信**: 传输控制协议(TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议。在本项目中,TCP被用来确保游戏数据在...

    j2me手机基于服务器的网络象棋游戏源代码

    2. 网络通信模块:负责客户端与服务器之间的数据交换,包括连接建立、消息编码解码、错误处理等。 3. 用户界面:显示棋盘、棋子,处理用户输入,提供反馈信息。 4. 多线程处理:服务器端可能需要多线程来处理多个...

    网络对战象棋游戏源代码

    在IT领域,开发一款网络对战象棋游戏不仅考验编程技能,还涉及到网络通信、图形界面设计、人工智能等多个方面的知识。本篇文章将详细探讨基于VC++实现的象棋游戏源代码,帮助读者深入理解其背后的原理与技术。 首先...

    CS框架下的中国象棋网络游戏代码

    这个项目中的“中国象棋网络对弈游戏”可能包含以下几个部分:游戏逻辑模块(处理象棋规则)、网络通信模块(实现客户端与服务器的套接字通信)、用户界面模块(展示游戏画面和交互)以及可能的多线程或并发处理模块...

    VB2005.net 开发含复盘功能网络象棋程序源码(08-4-22)

    文件“网络象棋VB.net 3.5复盘功能(4-22)”很可能包含了整个项目的源代码,包括界面设计、游戏逻辑、网络通信模块以及复盘功能的实现。通过深入研究这些代码,开发者不仅可以学习到如何使用VB2005.NET进行网络编程,...

    C#TCP/IP网络象棋

    理想情况下,应该将网络通信逻辑、游戏逻辑和用户界面分别封装在不同的类或模块中,以保持代码的清晰和可维护性。例如,可以创建一个`ChessServer`类负责处理网络通信,一个`ChessGame`类处理游戏规则,以及一个`...

    基于python的网络版中国象棋

    【标题】"基于Python的网络版中国象棋"是一个创新性的项目,它将传统的中国象棋游戏与现代的网络通信技术相结合,使玩家能够在局域网内通过网络进行双人对战。这个项目的核心在于利用Python编程语言实现游戏逻辑、...

    Qt项目开发中国象棋源码

    2. 游戏逻辑模块:负责处理棋局规则,如合法移动判断、胜负检测等。 3. 事件处理模块:处理用户输入和游戏状态的更新。 4. 可能存在AI模块:如果包含AI对弈,会有实现算法的代码。 5. 网络模块:如果支持在线对战,...

    网络版中国象棋,MFC制作,源代码

    2. **网络通信模块**:包括连接建立、数据发送和接收、错误处理等功能,可能使用异步I/O或线程池来提高并发性能。 3. **用户界面**:MFC的CDialog和CButton等类用于构建用户界面,事件驱动的编程模式使用户交互变得...

    易语言源码网络版中国象棋.rar

    3. **网络通信**:网络版中国象棋需要实现客户端与服务器之间的数据传输,易语言提供了网络模块,允许开发者编写网络应用。这涉及到TCP/IP协议、连接建立、数据包发送和接收等技术。 4. **多线程处理**:为了让游戏...

    C#源码 中国象棋网络版

    3. **Networking**:包含网络通信模块,负责客户端和服务器间的连接、数据交换。 4. **Server Management**:服务器端代码,处理客户端连接、请求处理、状态同步等。 5. **Database Integration**:数据库操作接口,...

    基于java的网络中国象棋

    2. **网络编程**:网络中国象棋涉及网络通信,需要理解TCP/IP协议,学会使用Java的Socket编程来建立客户端和服务器之间的连接,进行数据传输。 3. **多线程设计**: - **服务器端**:服务器端需要管理多个客户端的...

    winform 网络版象棋对战

    2. **多线程**:由于游戏需要同时处理用户的输入和网络通信,因此需要多线程技术来避免阻塞。可能使用Thread、Task或者异步编程模型(async/await)来保证程序的响应性和流畅性。 3. **对象序列化**:为了在网络上...

    网络版中国象棋

    QT的核心特性包括强大的图形渲染能力、丰富的UI组件库、多平台支持以及高效的网络通信功能,这些都使得QT成为开发网络版中国象棋的理想选择。 在这个项目中,开发者首先需要理解QT的事件驱动模型,这是构建用户界面...

    java写中国象棋手机网络游戏(J2ME+Servlet)

    【Java编写中国象棋手机网络游戏】是一个基于J2ME(Java Micro Edition)和Servlet技术的项目,主要目标是实现一个可以在移动设备上运行的在线中国象棋游戏平台。以下是这个项目涉及的关键知识点: 1. **J2ME**:...

    VB源码VB中国象棋网络版、单机版

    一个完整的中国象棋程序通常包含以下几个主要部分:用户界面(UI)、游戏逻辑、网络通信模块(针对网络版)以及可能的AI(人工智能)模块。在VB中,这些可以通过类和对象来实现,每个部分都可以看作是一个独立的实体...

    一个网络的中国象棋的源码.zip_delphi象棋_zip_中国象棋源码_象棋_象棋 delphi

    总之,这个基于Delphi的中国象棋网络版源码涵盖了游戏逻辑、用户界面、网络通信等多个方面的编程技术。通过深入分析和学习,不仅可以提升Delphi编程技能,也能深入了解游戏开发的全貌,对于任何希望从事游戏开发或者...

    网络中国象棋对弈程序源代码.rar.zip_网络象棋对弈

    通过这些文件,我们可以看出该程序的设计思路:使用C++语言编写,采用面向对象的方法,将界面显示、游戏逻辑、网络通信等模块化,使得代码结构清晰,易于维护。同时,集成MIDI支持提升了用户体验,而设置对话框则让...

Global site tag (gtag.js) - Google Analytics