网上的netty资料很少,感觉很少有人分享这方面的东西,最近捣鼓了下netty,一哥们说还不错,做底层通信,呵呵 ,测试结果 还不错 ,目前打算作为项目的备用底层通信方案 不说其他的 直接上代码,分享下 。有什么疑问直接留言。
package com.commons.nettyCore;
import com.commons.logger.NioSocket_log;
import com.commons.nettyCore.MServerconfig.MServerConfig;
import org.jboss.netty.channel.*;
import org.jboss.netty.handler.timeout.IdleState;
import org.jboss.netty.handler.timeout.IdleStateAwareChannelUpstreamHandler;
import org.jboss.netty.handler.timeout.IdleStateEvent;
import org.jboss.netty.util.Timer;
/**
* Created with IntelliJ IDEA.
* User: CHENLEI
* Date: 12-10-28
* Time: 下午7:45
* To change this template use File | Settings | File Templates.
* channelPipeFactory &Timer
*/
public class MServerChannelPipelineFactory extends IdleStateAwareChannelUpstreamHandler implements ChannelPipelineFactory {
private Timer timer=null;
private ChannelHandler idleStateHandler=null;
/**
*
* @param timer 定时器
* @param idleStateHandler
*/
public MServerChannelPipelineFactory(Timer timer, ChannelHandler idleStateHandler){
this.timer=timer;
this.idleStateHandler=idleStateHandler;
}
private MServerChannelPipelineFactory(){}
/**
* Returns a newly created {@link org.jboss.netty.channel.ChannelPipeline}.
*/
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline= Channels.pipeline(this.idleStateHandler, new MServerChannelPipelineFactory());
pipeline.addLast("decoder", MServerDecoder.getDecoder());
pipeline.addLast("handler", MServerHandler.getMServerHandler());
pipeline.addLast("encoder", MServerEncoder.getEncoder());
return pipeline; //To change body of implemented methods use File | Settings | File Templates.
}
/**
* 超时处理 。。。。
* @param ctx
* @param e
*/
@Override
public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) {
Channel c=e.getChannel();
if (e.getState() == IdleState.READER_IDLE) {
if(MServerConfig.debug) NioSocket_log.log.info(c.getRemoteAddress()+"--connect timeout");
c.close();
/**
* 回写玩家数据
*/
}
}
}
package com.commons.nettyCore;
import com.commons.logger.NioSocket_log;
import com.commons.nettyCore.MServerconfig.MServerConfig;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.frame.FrameDecoder;
/**
* 数据解析类
* 获取的数据存放在字节队列中
*/
public class MServerDecoder extends FrameDecoder {
private MServerDecoder(){}
public static MServerDecoder getDecoder(){
return singlton.mserverDecoder;
}
/**
*
* @param ctx
* @param channel
* @param buffer 非共享 “one” --当接收完毕一个消息后 丢弃
* @return
* @throws Exception
*/
@Override
protected Object decode(
ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
// NioSocket_log.log.info(channel.getRemoteAddress() + "connection server.");
if (buffer.readableBytes() < MServerConfig.packlen) {//可读字节小包长2,等待下一次读事件
return null;
}
//pack_length
int dataLength = buffer.getShort(buffer.readerIndex());
if (buffer.readableBytes() < dataLength + MServerConfig.packlen) { //可读字节数小于一个完整的包,等待下一次读事件
return null;
}
buffer.skipBytes(MServerConfig.packlen); //skip pack_length bytes 2
byte[] pack = new byte[dataLength];
buffer.readBytes(pack);
if(MServerConfig.debug) NioSocket_log.log.info("reciveMessage:"+ new String(pack).trim());
return pack; //FrameDecoder将继续调用 decode()
}
private static final class singlton{
private static final MServerDecoder mserverDecoder=new MServerDecoder();
}
}
package com.commons.nettyCore;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipelineCoverage;
import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
/**
* MServerEncoder
*/
@Sharable
public class MServerEncoder extends OneToOneEncoder {
// private MSession mSession;
private MServerEncoder(){}
public static MServerEncoder getEncoder(){
return Singleton.mencoder;
}
// OneToOneEncoder调用Channels.write(),将数据推送回client
@Override
protected Object encode(
ChannelHandlerContext ctx, Channel channel, Object msg) throws Exception {
if (!(msg instanceof ChannelBuffer)){
return null;
}
return msg;
}
private static final class Singleton{
private static final MServerEncoder mencoder=new MServerEncoder();
}
}
package com.commons.nettyCore;
import com.commons.define.BaseDefinition;
import com.commons.logger.NioSocket_log;
import com.commons.logic.DataProcess;
import com.commons.nettyCore.MServerconfig.MServerConfig;
import game.user.User;
import org.jboss.netty.channel.*;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.DefaultChannelGroup;
/**
* SimpleChannelUpstreamHandler提供多种事件重写的方法</br>
* 服务端业务处理handler</br>
*/
@ChannelPipelineCoverage("all") //一个处理器是否可以被多个channel共享
public class MServerHandler extends SimpleChannelHandler {
private MSocket mSession=null;
private MServerHandler(){}
/**
* 获取messageServerHandler
* @return
*/
public static MServerHandler getMServerHandler(){
return siglton.mServerHandler;
}
/**
* 获取ChannelGroup--管理channel集合
* @return
*/
public static ChannelGroup getChannelGrop(){
return siglton.chanelGrop;
}
/**
* Invoked when a message object (e.g: {@link org.jboss.netty.buffer.ChannelBuffer}) was received
* from a remote peer.
*/
@Override
public void messageReceived(
ChannelHandlerContext ctx, MessageEvent e) throws InterruptedException {
byte []pack= (byte[]) e.getMessage();
if (pack!=null)this.mSession.getHandBuffers().add((byte[]) e.getMessage());
if(this.mSession.getHandBuffers().size()>0) DataProcess.getDataProcess().onData(this.mSession);
}
/**
* 异常处理
* @param ctx
* @param e
*/
@Override
public void exceptionCaught(
ChannelHandlerContext ctx, ExceptionEvent e) {
NioSocket_log.log.warn("Unexpected exception from downstream.", e.getCause());
e.getChannel().close();
}
/**
* 当建立一个连接时候触发
* @param ctx
* @param e
* @throws Exception
*/
@Override
public void channelConnected(
ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
Channel channel=e.getChannel();
if (MServerConfig.debug) NioSocket_log.log.info(channel.getRemoteAddress()+"--connected server"+channel.getId());
this.mSession=new MSocket(channel,ctx);//创建一个MSession
ctx.setAttachment(this.mSession);
User user = new User();
user.setmSocket(mSession);
BaseDefinition.SocketUserMaps.put(mSession, user);
}
/**
* channel关闭触发事件
* @param ctx
* @param e
* @throws Exception
*/
@Override
public void channelClosed(
ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
Channel channel=e.getChannel();
if (MServerConfig.debug)NioSocket_log.log.info(channel.getRemoteAddress()+"--disconnected server"+channel.getId());
siglton.chanelGrop.remove(channel);
/**
* 持久化数据
*/
ctx.sendUpstream(e);
}
/**
* Invoked when a {@link org.jboss.netty.channel.Channel} is open, but not bound nor connected.
* <br/>
*
* <strong>Be aware that this event is fired from within the Boss-Thread so you should not
* execute any heavy operation in there as it will block the dispatching to other workers!</strong>
*/
@Override
public void channelOpen(
ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
siglton.chanelGrop.add(e.getChannel());
// siglton.chanelGrop.size();
ctx.sendUpstream(e);
}
private static final class siglton{
private static final ChannelGroup chanelGrop=new DefaultChannelGroup();
private static final MServerHandler mServerHandler=new MServerHandler();
}
}
package com.commons.nettyCore;
import com.commons.logger.NioSocket_log;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* Created with IntelliJ IDEA.
* User: CHENLEI
* Date: 12-10-28
* Time: 下午11:06
* To change this template use File | Settings | File Templates.
* 会话,代表一个建立连接的客户端
*/
public class MSocket{
private Channel channel;
private ChannelHandlerContext ctx;
private final ConcurrentLinkedQueue<byte[]> HandBuffers = new ConcurrentLinkedQueue<byte[]>();
private final ConcurrentLinkedQueue<ChannelBuffer> writeBuffers = new ConcurrentLinkedQueue<ChannelBuffer>();
MSocket(Channel channel,ChannelHandlerContext ctx){
this.channel=channel;
this.ctx=ctx;
}
public Channel getChannel() {
return channel;
}
public void setChannel(Channel channel) {
this.channel = channel;
}
/**
* 添加channelbuffer在待发送的队列
* @param buffer ChannelBuffer
*/
public void addQueue(ChannelBuffer buffer) {
if(buffer!=null){
this.getWriteBuffers().add(buffer);
NioSocket_log.log.info("添加数据buffer:"+ buffer);
if (this.getWriteBuffers().size()>0){
ChannelBuffer msg=this.getWriteBuffers().poll();
channel.write(msg,channel.getRemoteAddress());
}
}else {
NioSocket_log.log.error("buffer is nullException,please checked it");
}
}
/**
* 获取处理的缓存对列
* @return
*/
public ConcurrentLinkedQueue<byte[]> getHandBuffers() {
return HandBuffers;
}
/**
* 获取带发送的缓存队列
* @return
*/
public ConcurrentLinkedQueue<ChannelBuffer> getWriteBuffers() {
return writeBuffers;
}
}
package com.commons.nettyCore;
import com.commons.logger.NioSocket_log;
import com.commons.nettyCore.MServerconfig.MServerConfig;
import com.commons.nettyCore.SafeBox.SafeBox;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.timeout.IdleStateHandler;
import org.jboss.netty.util.HashedWheelTimer;
import org.jboss.netty.util.Timer;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
/**
* Created with IntelliJ IDEA.
* User: CHENLEI
* Date: 12-10-30
* Time: 上午11:03
* To change this template use File | Settings | File Templates.
* start netty
*/
public class nettyServer {
private nettyServer(){}
public static nettyServer getInstance(){
return singelton.nettyserver;
}
public void startServer(){
try{
//初始化netty配置
boolean status= MServerConfig.IntiServerConfig();
if(!status)System.exit(0);
/**
* ChannelFactory创建和管理channel的以及相关资源的接口</br>
* 处理相应的I/O请求,并产生相应的channelEvent</br>
*/
ChannelFactory factory=new NioServerSocketChannelFactory( Executors.newCachedThreadPool(),
Executors.newCachedThreadPool(),MServerConfig.workerThread);
// ChannelFactory factory=new NioServerSocketChannelFactory( Executors.newCachedThreadPool(),
// Executors.newCachedThreadPool(),MServerConfig.workerThread);
// Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap(factory);
/**
* 当一个新的连接上来,创建新的ChannelPipeline对象
* 所以添加的channelhandler对象将被添加在新创建的对象</br></>
*/
Timer timer = new HashedWheelTimer();
ChannelHandler idleStateHandler=new IdleStateHandler(timer, MServerConfig.readTimeOut,MServerConfig.writeTimeOut,0);
bootstrap.setPipelineFactory(new MServerChannelPipelineFactory(timer,idleStateHandler));
// bootstrap.releaseExternalResources();
// Bind and start to accept incoming connections.
bootstrap.setOption("tcpNoDelay", true);
bootstrap.setOption("keepAlive", true);
bootstrap.bind(new InetSocketAddress(MServerConfig.port));
if(MServerConfig.debug) NioSocket_log.log.info("service is listen on port:"+MServerConfig.port);
if(MServerConfig.isSafeopen)new SafeBox().startService();
}catch (Exception e){
NioSocket_log.log.error("netty start failed ",e);
}
}
private static final class singelton{
private static final nettyServer nettyserver=new nettyServer();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<root>
<!--true:调试打印日志;false:运行打印日志-->
<debug>true</debug>
<!-- 服务端口 -->
<port>8888</port>
<!--netty worker线程数 -->
<workerThread>3</workerThread>
<!--read data time out ..secs-->
<readTimeOut>36000</readTimeOut>
<!--write data time out ..secs-->
<writeTimeOut>0</writeTimeOut>
<!--是否打开安全沙箱-->
<isSafeopen>true</isSafeopen>
<!--包长-->
<packlen>2</packlen>
</root>