项目已分享到我的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,完成项目的创建。然后看一下我们创建的项目的内容,应该是这样:
打开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数据