Netty框架的简单实现(客户端和服务端收发消息)
Netty框架的简单实现
一、Netty的原理分析图
二、使用Netty框架的简单实现(实现client和server的消息收发)
(1)NettyServer
1 public class NettyServer { 2 public static void main(String[] args) throws Exception{ 3 4 //创建两个线程池 5 6 //创建一个线程组,接收客户端的连接 7 EventLoopGroup bossGroup = new NioEventLoopGroup(); 8 //创建一个线程组,用于处理网络操作 9 EventLoopGroup workerGroup = new NioEventLoopGroup(); 10 //创建服务器端启动助手(用于配置参数) 11 ServerBootstrap serverBootstrap = new ServerBootstrap(); 12 serverBootstrap.group(bossGroup,workerGroup)//设置两个线程组 13 .channel(NioServerSocketChannel.class)//精华部分,设置通道的底层实现, 14 //通过NioServerSocketChannel 15 //这也是Netty的与NIO搭配的地方(此处作为服务器端通道的实现) 16 .option(ChannelOption.SO_BACKLOG, 12)//设置线程队列中等待连接的个数 17 .childOption(ChannelOption.SO_KEEPALIVE, true) 18 //是否启用心跳保活机制。在双方TCP套接字建立连接后(即都进入ESTABLISHED状态)并 19 //且在两个小时左右 20 //上层没有任何数据传输的情况下,这套机制才会被激活。 21 * */ 22 .childHandler(new ChannelInitializer<SocketChannel>() {//(用内部类的方法) 23 //创建一个通道初始化对象 24 public void initChannel(SocketChannel sc){ 25 sc.pipeline().addLast(new NettyServerHandler());//往pipeline链中添加 26 //自定义的handler类 27 } 28 }); 29 System.out.println("...Server is Ready..."); 30 //ChannelFuture接口,用于在之后的某个时间点确定结果 31 ChannelFuture sf = serverBootstrap.bind(9999).sync();//绑定端口 非阻塞 异步 32 System.out.println("....Server is Start...."); 33 //关闭通道,关闭线程组 34 sf.channel().closeFuture().sync(); 35 bossGroup.shutdownGracefully(); 36 workerGroup.shutdownGracefully(); 37 } 38 }
(2)NettyServerHandler
1 //服务器中的业务处理类 2 public class NettyServerHandler extends ChannelInboundHandlerAdapter { 3 4 //数据读取事件 5 public void channelRead(ChannelHandlerContext ctx,Object msg){ 6 //传来的消息包装成字节缓冲区 7 ByteBuf byteBuf = (ByteBuf) msg; 8 //Netty提供了字节缓冲区的toString方法,并且可以设置参数为编码格式:CharsetUtil.UTF_8 9 System.out.println("客户端发来的消息:" + byteBuf.toString(CharsetUtil.UTF_8)); 10 } 11 12 //数据读取完毕事件 13 public void channelReadComplete(ChannelHandlerContext ctx){ 14 //数据读取完毕,将信息包装成一个Buffer传递给下一个Handler,Unpooled.copiedBuffer会返回一个Buffer 15 //调用的是事件处理器的上下文对象的writeAndFlush方法 16 //意思就是说将 你好 传递给了下一个handler 17 ctx.writeAndFlush(Unpooled.copiedBuffer("你好!", CharsetUtil.UTF_8)); 18 } 19 20 //异常发生的事件 21 public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause){ 22 //异常发生时关闭上下文对象 23 ctx.close(); 24 } 25 }
(3)NettyClient
1 //网络客户端 2 public class NettyClient { 3 public static void main(String[] args) throws Exception{ 4 //创建一个线程组(不像服务端需要有连接等待的线程池) 5 EventLoopGroup group = new NioEventLoopGroup(); 6 //创建客户端的服务启动助手完成相应配置 7 Bootstrap b = new Bootstrap(); 8 b.group(group) 9 .channel(NioSocketChannel.class) 10 .handler(new ChannelInitializer<SocketChannel>() {//创建一个通道初始化对象 11 @Override 12 protected void initChannel(SocketChannel socketChannel) throws Exception { 13 socketChannel.pipeline().addLast(new NettyClientHandler());//往pipeline中添加自定义的handler 14 } 15 }); 16 System.out.println("...Client is Ready..."); 17 //启动客户端去连接服务器端(通过启动助手) 18 ChannelFuture cf = b.connect("127.0.0.1", 9999).sync(); 19 //关闭连接(异步非阻塞) 20 cf.channel().closeFuture().sync(); 21 22 } 23 }
(4)NettyClientHandler
1 //客户端业务处理类 2 public class NettyClientHandler extends ChannelInboundHandlerAdapter { 3 4 //通道就绪事件(就是在bootstrap启动助手配置中addlast了handler之后就会触发此事件) 5 //但我觉得也可能是当有客户端连接上后才为一次通道就绪 6 public void channelActive(ChannelHandlerContext ctx){ 7 System.out.println("Client :" + ctx); 8 //向服务器端发消息 9 ctx.writeAndFlush(Unpooled.copiedBuffer("你好啊!", CharsetUtil.UTF_8)); 10 } 11 //数据读取事件 12 public void channelRead(ChannelHandlerContext ctx,Object msg){ 13 //传来的消息包装成字节缓冲区 14 ByteBuf byteBuf = (ByteBuf) msg; 15 //Netty提供了字节缓冲区的toString方法,并且可以设置参数为编码格式:CharsetUtil.UTF_8 16 System.out.println("服务器端发来的消息:" + byteBuf.toString(CharsetUtil.UTF_8)); 17 } 18 19 }
通道的消息处理都是通过channelHandlerContext对象的writeAndFlush方法来处理的。