java服务器开发:基于mina的网络通信模块

项目已分享到我的github上:https://github.com/LiuFeng1011/DGServer

客户端测试项目使用的是unity,之前的文章中已经有介绍

地址:http://blog.csdn.net/zgjllf1011/article/details/79216072


为了将业务层与网络层分离,使开发人员不必关心底层部分的内容,这里将此模块剥离为独立项目。

此项目使用maven进行管理。


使用

首先要把我们的项目发布到本地仓库,控制台跳转到我们的DGServer项目根目录,执行命令:mvn install,结束后看到如下内容就表示成功了:

然后就可以在我们的项目中直接使用了。

1.新建一个maven项目:


一直下一步,直到最后一个页面:


这里Group Id 填写com.公司名,Articact Id填写项目名,点击finish,完成项目的创建。然后看一下我们创建的项目的内容,应该是这样:


2.添加网络层项目
打开pom.xml文件在<dependencies>中加入如下内容:
<dependencies>
    	<dependency>
		<groupId>com</groupId>
		<artifactId>dgserver</artifactId>
		<version>0.0.2-SNAPSHOT</version>
	</dependency>
  </dependencies>


3.网络层的使用
打开文件App.java,其中main方法即为游戏入口:

在这里注册一些网络层的回调事件:

	final ServerApp app = ServerApp.getInstance();
    	System.out.println("=======main=============");
    	app.registPlugin(new Plugin()
        {
			public void onAppStart() throws Exception {
				// TODO Auto-generated method stub

		        System.out.println("-----------service start------------");
			}
			

			public void onAppStop() throws Exception {
				// TODO Auto-generated method stub
		        System.out.println("-----------service stop-----------");
			}
        });
    	
    	app.start();
    	
    	app.SetUserOfflineCallBack(
    			new DGServerCallBack(){

					public void ServerCallBack(Object obj) {
						// TODO Auto-generated method stub
						long uid = Long.parseLong(obj.toString());
						System.out.println("OfflineCallBack : " + uid);
					}
    				
    			}
    		);

然后创建一个类,用来管理游戏的所有内容:


该类需要使用单例模式:

	private static GameWorld instance;

	public static GameWorld GetInstance(){
		if(instance == null){
			instance = new GameWorld();
		}
		return instance;
	}
声明网络层引用:

private ServerManager server;
实现启动游戏的方法:
	public void StartGame(){

		try{
			//网络服务 端口号
			server = new ServerManager(port);
			server.Start();
			
			//注册游戏业务服务
			server.setServerList(RegistServer());
			
			//启动游戏
			Start();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	
	public void Start(){
		new MainLoop().start();
	}
	
	/**
	 * 游戏主线程
	 * 
	 */
	public class MainLoop extends Thread {
		@Override
		public void run() {
			System.out.println("MAIN LOOP THREAD START!");
			while (true) {
				try {
					// 游戏逻辑
					GameTick();
				} catch (Exception e) {
					System.out.println("error in MainLoop tick ");
					e.printStackTrace();
				}
			}
		}

		/**
		 * 游戏逻辑
		 */
		public void GameTick() {
			
		}
	}

	Map<Integer,BaseServer> RegistServer(){

		Map<Integer,BaseServer> servermap = new HashMap<Integer,BaseServer>();

		return servermap;
	}

这里RegistServer为业务层逻辑,所有业务服务需要在这里注册。

然后在App.java中调用启动方法:
GameWorld.GetInstance().StartGame();

接下来实现业务层逻辑

创建3个包:


其中server为业务层逻辑,request为请求数据,response为响应数据.

创建协议类:


这里定义所有的服务器与客户端通信的协议id,先创建两个测试协议,一个登录协议:

public class NetProtocol {

	public static final int ENTRY_GAME = 0x00000100;//登录游戏
	public static final int TEST_A = 0x10000001;
	public static final int TEST_B = 0x10000002;

}
然后分别创建登录以及2个测试协议的请求响应和业务类


这里所有的请求和响应都要继承消息类BaseMessage,并重写GetProtocol方法,GetProtocol返回请求类所对应的协议.
请求类需要重写deserialize方法,响应类需要重写serialize方法,重写时必须要先调用父类被重写的方法,这里以TestA为例:

public class TestAReq  extends BaseMessage{
	@Override
	public int GetProtocol() {
		// TODO Auto-generated method stub
		return NetProtocol.TEST_A;
	}
	

	@Override
	public void deserialize(MyBuffer in) {
		// TODO Auto-generated method stub
		super.deserialize(in);
	}
}

public class TestAResp  extends BaseMessage{
	@Override
	public int GetProtocol() {
		// TODO Auto-generated method stub
		return NetProtocol.TEST_A;
	}
	
	@Override
	public void serialize(MyBuffer buf){
    	super.serialize(buf);
	}
}
其中serialize和deserialize为序列化和反序列化函数。
接下来实现业务逻辑,server需要继承BaseServer类并重写GetProtocol,GetRequest和handle方法:
public class TestAServer implements BaseServer {

	public int GetProtocol() {
		// TODO Auto-generated method stub
		return NetProtocol.TEST_A;
	}

	public BaseMessage GetRequest() {
		// TODO Auto-generated method stub
		return new TestAReq();
	}

	public BaseMessage handle(IoSession is,BaseMessage request) {
		
		TestBResp resp = new TestBResp();
		
		return resp;
	}
}
业务层实现之后需要在GameWorld的RegistServer方法中进行注册:
	Map<Integer,BaseServer> RegistServer(){

		Map<Integer,BaseServer> servermap = new HashMap<Integer,BaseServer>();

		servermap.put(NetProtocol.ENTRY_GAME, new EntryGameServer());
		servermap.put(NetProtocol.TEST_A, new TestAServer());
		servermap.put(NetProtocol.TEST_B, new TestBServer());

		return servermap;
	}
这样服务器就可以正常的运行了,右键点击App.java :


这时可以从Console中看到输出


这样就说明服务器已经启动成功了。

注意:客户端想连接的服务器之后,必须首先发送EntryGameReq请求,此请求协议固定为0x00000100,不可更改,客户端收到EntryGameResp之后才可进行其它消息的发送,否则服务器不会对消息进行任何处理。


下面简单介绍一下此框架中服务器收到消息的处理流程

1.网络层收到消息会在GameWorld中注册的所有server(业务类)中根据协议ID找到与自身协议相同的业务类
2.然后调用server的GetRequest方法来获取request(请求类)
3.调用request的deserialize,对消息进行反序列化
4.调用server的handle方法并传入request
5.server执行业务逻辑,并返回response数据




jaca视频教程 jaca游戏服务器开发 Netty NIO AIO Mina视频教程 课程目录: 一、Netty快速入门教程 01、第一课NIO 02、第二课netty服务端 03、第三课netty客户端 04、第四课netty线程模型源码分析(一) 05、第五课netty线程模型源码分析(二) 06、第六课netty5案例学习 07、第七课netty学习之心跳 08、第八课protocol buff学习 09.第九课自定义序列化协议之自定义序列化协议 10、第十课自定义数据包协议 11.第十一课粘包分包分析,如何避免socket攻击 12.分析设计一个聊天室的小项目 二、java NIO,AIO编程视频教程 1、java NIO,AIO编程_01.flv 2、java NIO,AIO编程_02.flv 3、java NIO,AIO编程_03.flv 4、java NIO,AIO编程_04.flv 5、java NIO,AIO编程_05.flv 三、Java语言基础教程-Java NIO流篇 [第1节] Java NIO流-简介和概述.flv [第2节] Java NIO流-缓冲区.flv [第3节] Java NIO流-缓冲区操作.flv [第4节] JavaNIO流-通道1.flv [第5节] Java NIO流-通道2.flv [第6节] Java NIO流-socket通道操作.flv [第7节] Java NIO流-文件通道操作.flv [第8节] Java NIO流-选择器 .flv [第9节] Java NIO流-选择器操作.flv 四、Mina视频教程 00、Mina视频课程介绍.flv 01、Mina服务端helloWorld入门.flv 02、Mina客户端helloWorld入门.flv 03、Mina整体体系结构分析.flv 04、Mina学习之长短连接.flv 05、Mina学习之MinaIOService接口.flv 06、Mina学习之MinaIOFilter接口.flv 07、Mina学习之MinaIOSession接口.flv 08、Mina学习之MinaIOProcessor线程模型.flv 09、Mina学习之MinaIOBuffer接口.flv 10、Mina学习之自定义协议介绍.flv 11、Mina学习之自定义协议数据包分析.flv 12、Mina学习之自定义协议数据包实现.flv 13、Mina学习之自定义协议-编码器.flv 14、Mina学习之自定义协议-解码器.flv 15、Mina学习之自定义协议-服务端实例.flv 16、Mina学习之自定义协议-客户端实例.flv
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值