您的位置:首页 > 编程语言 > Java开发

8.Utm示例-Netty集成

2016-03-27 13:47 561 查看
Utm示例-Netty集成

 

在各个平台上集成utm主要是通过一个过滤器将该平台收到的信息转发到utm里,由utm线程调度处理。

 

Netty4(4.1.0.Beta5)

一个Java写的基于NIO的客户,服务器端编程框架,这里就不介绍关于Netty的基本内容了,只是关注如何在Netty4上集成utm。(这次是本人刚接触Netty,所以可能对于其中的一些细节不甚了解,如果有什么不对的地方希望大家提出)。

测试代码中前后端交互的编码使用了 netty自带的长度LengthFieldxxx和自己定义的消息体编码CommonObjB(这里就不做详细介绍);而客户端采用的是java写的一个简单的Socket处理(BIO),使得代码相对更加简洁易懂,而且比较容易移植到其他语言上(当然把它改成NIO是很容易的事情,不过如果只是和一个服务端通信,其实客户端并不太需要做这种改变)。

 

 

相关的代码:GitHub: https://github.com/dga4654dan/UTM-DEMO下的 V_1_0_1 下的 UtmDemo_Netty_4.1.0.Beta5

或 Git@OSC: http://git.oschina.net/daemon_c/UTM-demo下的 V_1_0_1 下的 UtmDemo_Netty_4.1.0.Beta5

 

 

首先在Netty的ChannelInitializer中实例化utm,对应MainHandlerInitializer类,在该类里的构造方法中实例化utm:

(如上提及的“实例化utm”)

 

 

然后是在Netty的消息控制器(MainHandler)将信息转发到utm上:

(在Netty上给定的接口是基于连接的,就是:一个连接 连接上了,连接 断开了,连接 发送来消息了,而utm也并不包含连接与用户的映射关系(在“Utm详细实现 ->用户生命流程 -> 用户登录 -> 详细流程 -> 关于为什么要有loginLinkCheck问题”中已有说明),所以这部分内容需要外围的程序实现,封装在了ControlCenter中(可以查看该具体类方法的说明和实现))

 

MainHandler:

1.      连接 连接到服务端,这里utm并不做处理,只是记录连接信息(ControlCenter.visitorLink)

    publicvoid channelActive(ChannelHandlerContext ctx)throws
Exception {
       
      //客户端连接到服务
      Channelchannel = ctx.channel();
      ChannelIdchannelId = channel.id();
      Stringaddress = channel.remoteAddress().toString();
      Stringip = address.substring(1, address.indexOf(':'));
     
     
//将连接信息(Link)放入到linkMap
      ControlCenter.visitorLink(channelId,channel, ip);
       
       super.channelActive(ctx);
    }

 

 

 

 

2.      连接断开,如果该连接对应一个客户,则调用utm的客户断线方法(userThreadModeFilter.disconnect)

 

    publicvoid channelInactive(ChannelHandlerContext ctx)throws
Exception {
     
     
//客户端断开连接
     
      ChannelIdchannelId = ctx.channel().id();
      IntegeruserId = ControlCenter.disconnect(channelId);
     
     
//如果是用户则调用utm的用户断线事件
      if( userId !=null ) {
           
            Useruser = ControlCenter.getUser( userId );
            if( user !=null ) {
                 
                  LoggerCenter.userRquestLogger.log(user.userName,
                             LoggerCenter.getBeforeInfo().append("cmd:netty user disconnect\n") );
                 
                 
userThreadModeFilter.disconnect(requestIds.getAndIncrement(), userId);
                 
            }
      }
    }

 

3.      接收到连接的消息,如果该连接是用户则调用utm的用户cmd请求处理方法(userThreadModeFilter.handleUserRequest),如果该连接是游客则调用utm的游客cmd请求处理方法(userThreadModeFilter.handleVisitorRequest)。

 

   
protectedvoid channelRead0(ChannelHandlerContext ctx, ByteBuf buf)throws
Exception {
     
     
//接收到客户端消息
      ChannelIdchannelId = ctx.channel().id();
      Linklink = ControlCenter.getLink(channelId);
      IntegeruserId = link.getUserId();
      //解析请求参数
      Integercmd =
cmdCoder.decoder(buf);
      CommonObjBparam =
decoder.decoder(buf);
     
      if( userId ==null ) {
           
//处理游客请求
            
userThreadModeFilter.handleVisitorRequest(requestIds.getAndIncrement(), cmd, channelId, link.visitor,
param);
            
      } else {
           
//如果是断开,则设置  连接信息(Link) 为断开
            if( cmd ==Cmd.Logout.CMD )
                  link.logout();
           
//处理用户请求
           
userThreadModeFilter.handleUserRequest(requestIds.getAndIncrement(), cmd, userId, param);
      }
    }

再来看下一个前后端简单的交互过程(HeartbeatHandler心跳):

由客户端发给服务端,带有一个requestCode参数,服务端接收到并返回该参数。

 

服务端:(HeartbeatHandler)

服务端处理器只需要实现IRequestHandler接口即可,由于该接口方法较多,所以直接继承了一个实现了部分方法的实现类,通常的cmd处理器只需要继承它并实现handlerUserRequest和queueFull即可。

 

      publicvoid handlerUserRequest(int
requestId, User user, CommonObjB param) {
           //给用户返回心跳信息
           try {
//获得请求参数
                 int requestCode = param.getInt(Cmd.Heartbeat.REQUEST_CODE);
                 //给用户返回信息
                 CommonObjB returnObject =new CommonObjB();
                 returnObject.putInt(Cmd.Heartbeat._RESULT_CODE,Cmd.SuccessCode.SUCCESS);
                 returnObject.putInt(Cmd.Heartbeat._REQUEST_CODE, requestCode);
                 ControlCenter.sendToUser(Cmd.Heartbeat.CMD, returnObject,user);
                
           } catch (Exception e) {
                
                 CommonObjB returnObject =new CommonObjB();
                 returnObject.putInt(Cmd.Heartbeat._RESULT_CODE,Cmd.ErroCode.UNKNOW);
                 ControlCenter.sendToUser(Cmd.Heartbeat.CMD, returnObject,user);
                 LoggerCenter.userRquestLogger.log(user.userName, e);
           }
      }

 

客户端:(UTM-Demo\V_1_0_1\UtmDemo_Netty_4.1.0.Beta5\UtmDemo_Netty_4.1.0.Beta5_Client 项目的ClientTest)

发送:

      publicvoid sendHeartBeat(int
requestCode) {
          
           CommonObjB heartbeat =new CommonObjB();
           heartbeat.putInt(Cmd.Heartbeat.REQUEST_CODE, requestCode);
          
           client.send(Cmd.Heartbeat.CMD, heartbeat);
      }

 

接收:(此处仅简单的打印出收到的信息)

      publicvoid cmdResponse(Integer cmd, CommonObjB obj) {
          
           System.out.println(prefix +
"cmd:" + cmd +
": " + obj.toString() );
          
      }

 

 

运行效果:

左边为服务端,可以看到有关资源数量的打印:原来为0,后面客户端连上后变为1

右边是客户端,可以看到

1.      登录成功后服务端返回的cmd:Login,其中参数1=0(resultCode=SUCCESS)

2.      客户端给后台发送心跳后后台的返回cmd:-1006(心跳),其中参数1=0(resultCode=SUCCESS),101=n(请求参数=n)



 

也可以在服务端的用户日志中看到该用户和后台的交互日志:



 

更多细节可以查看NettyUserThreadMode_V_0.9.0 和 NettyUserThreadModeTest_V_0.9.0 的源码

2. Utm 模块设计

3. Utm详细实现-用户生命流程

4. Utm详细实现-用户资源管理

5.Utm线程模型

6. Utm示例-公共部分

7. Utm示例-SmartFoxServer集成

8. Utm示例-Netty集成
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息