Netty和Mina。

      

一、优势对比:

        Netty是由JBoss提供的Java开发框架,适用于开发高性能、高稳定性的客户端或者服务端网络通信框架,相较于Mina有如下几点优点:

1.支持多种编解码方式,当然也包括当前游戏开发中应用最广的Google提供的Protobuff编解码方式;

2.典型的NIO架构,非阻塞异步的事件驱动网络通信架构,吞吐量高,支持高并发;


二、资源下载:

1.netty-all-4.0.42.Final.jar:在Netty官网下载所需版本的jar包,不同版本的Netty差别比较大,我选择的是Netty4.0.42 Final版本。

2.Log4j或common-logging:这是用于打印和记录日志的工具,非常实用,详细的使用方法可以参考:最详细的Log4j使用教程,当然也有更简单方便的一个工具:common-logging,使用方法参考: Apache Commons-logging使用实例。


三、Socket服务:

1.新建一个Java工程,步骤:File —— new —— Java Project;

2.资源导入:

        解压上面下载的Netty4.0.42压缩包,将netty-4.0.42.Final\jar\all-in-one目录下面的netty-all-4.0.42.Final.jar和commons-logging-1.2中的commons-logging-1.2.jar一起复制到eclipse中项目的libs目录下面(没有这个目录的话可以自行创建,专门用于存放外部导入的jar包):


3.编写服务代码:

        在src目录下新建一个包名com.tw.login.server,然后新建两个类:

LoginSocketServer.java:用于管理Socket,例如:ip端口绑定,Socket启动和关闭等;

SocketServerHandler.java:Socket数据接收监听和解析中心;

LoginSocketServer中启动一个ServerBootsrap服务器,并且绑定线程组,并且绑定用来监听数据的继承自SocketChannel的自定义监听器类,在其中设置网络传输数据的编码方式,然后设置连接到此服务器需要访问的IP和端口。

        关于传输数据协议,这里我们先以最简单的字符串为例,以("\n")为结尾分割的解码器作为数据协议格式,关于更复杂的数据类型协议在后面的篇章会继续设计。


LoginSocketServer源码:


public class LoginSocketServer {
	private static final Log logger = LogFactory.getLog(LoginSocketServer.class);
	private static final String IP = "127.0.0.1";
	private static final int PORT = 8088;
	
	//分配用于处理业务的线程组数量
	protected static final int BisGroupSize = Runtime.getRuntime().availableProcessors()*2;
	//每个线程组中线程的数量
	protected static final int worGroupSize = 4;
	
	private static final EventLoopGroup bossGroup = new NioEventLoopGroup(BisGroupSize);
	private static final EventLoopGroup workerGroup = new NioEventLoopGroup(worGroupSize);
	
	protected static void  run() throws Exception {
		ServerBootstrap bootstrap = new ServerBootstrap();
		bootstrap.group(bossGroup, workerGroup);
		bootstrap.channel(NioServerSocketChannel.class);
		bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
			@Override
			protected void initChannel(SocketChannel ch) throws Exception {
				ChannelPipeline pipeline = ch.pipeline();
				// 以("\n")为结尾分割的 解码器
				pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
		        pipeline.addLast("decoder", new StringDecoder());
		        pipeline.addLast("encoder", new StringEncoder());
				pipeline.addLast(new SocketServerHandler());
			}
		});
		bootstrap.bind(IP,PORT).sync();
		logger.info("Socket服务器已启动完成");
	}
	
	protected static void shutdown() {
		bossGroup.shutdownGracefully();
		workerGroup.shutdownGracefully();
	}
	
	public static void  main(String[] args) throws Exception {
		logger.info("开始启动Socket服务器...");
		run();
	}
	
}


SocketServerHandler源码:


public class SocketServerHandler extends SimpleChannelInboundHandler<String> {
	private static final Log logger = LogFactory.getLog(LoginSocketServer.class);

	@Override
	public void exceptionCaught(ChannelHandlerContext arg0, Throwable arg1) throws Exception {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void channelRead(ChannelHandlerContext arg0, Object msg) throws Exception {
		// TODO Auto-generated method stub
        logger.info("数据内容:data="+data);
	}
}



为了测试还需要创建一个客户端,其实创建过程很简单:直接复制一份上述服务器的代码,稍作修改即可:

LoginSocketClient源码:



private static final Log logger = LogFactory.getLog(LoginSocketClient.class);
	private static final String IP = "127.0.0.1";
	private static final int PORT = 8088;
	
	private static final EventLoopGroup group = new NioEventLoopGroup();
	
	@SuppressWarnings("rawtypes")
	protected static void  run() throws Exception {
		Bootstrap bootstrap = new Bootstrap();
		bootstrap.group(group);
		bootstrap.channel(NioSocketChannel.class);
		bootstrap.handler(new ChannelInitializer() {
			@Override
			protected void initChannel(Channel ch) throws Exception {
				// TODO Auto-generated method stub
				ChannelPipeline pipeline = ch.pipeline();
				/*
		         * 这个地方的 必须和服务端对应上。否则无法正常解码和编码
		         * 
		         * 解码和编码 我将会在下一张为大家详细的讲解。再次暂时不做详细的描述
		         * 
		         * */
		        pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
		        pipeline.addLast("decoder", new StringDecoder());
		        pipeline.addLast("encoder", new StringEncoder());
				pipeline.addLast(new SocketClientHandler());
			}
		});
		
		// 连接服务端
        Channel ch = bootstrap.connect(IP,PORT).sync().channel();
        
        
        ch.writeAndFlush("客户端数据"+"\r\n");
		
		logger.info("向Socket服务器发送数据:"+"客户端数据"+"\r\n");
	}
	
	public static void  main(String[] args){
		logger.info("开始连接Socket服务器...");
		try {
			run();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			group.shutdownGracefully();
		}
	}


SocketClientHandler源码:


public class SocketClientHandler extends SimpleChannelInboundHandler<String> {
	private static final Log logger = LogFactory.getLog(LoginSocketClient.class);

	@Override
	public void exceptionCaught(ChannelHandlerContext arg0, Throwable arg1) throws Exception {
		// TODO Auto-generated method stub
	}

	@Override
	public void channelRead(ChannelHandlerContext arg0, Object msg) throws Exception {
		// TODO Auto-generated method stub
		String data = msg.toString();
		logger.info("数据内容:data="+data);
	}

	@Override
	protected void channelRead0(ChannelHandlerContext arg0, String data) throws Exception {
		// TODO Auto-generated method stub
		logger.info("数据内容:data="+data);
	}
}



4.运行:

        运行方式其实很简单,直接在Eclipse中选中项目根目录,右键——Run As——Java Application,注意要先运行服务端工程再运行客户端工程,运行结果如下:


服务端Console结果:

Netty 游戏服务器架构设置高并发 netty开发游戏服务器_Netty 游戏服务器架构设置高并发


客户端Console结果:

Netty 游戏服务器架构设置高并发 netty开发游戏服务器_Netty 游戏服务器架构设置高并发_02