Netty权威指南读书笔记-(3) netty入门应用

搭建一个netty应用demo

before:先在pom引入jar包:

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>5.0.0.Alpha2</version>
</dependency>

1)先搭建服务端

public class TimeServer {
   public void bind(int port) throws Exception {
      /**
       * 创建两个线程组,它包含一nio线程,专门用于处理网络事件的处理,实际上他们就是reactor线程组(专门用于服务端接受客户端的链接)
       * 另一个是:进行socketchannel的网络读写,
       */
      EventLoopGroup bossGroup = new NioEventLoopGroup();
      EventLoopGroup workerGroup = new NioEventLoopGroup();

      try {
         /**
          * 创建一个serverbootstrap对象,是启动nio服务端的辅助启动类,
          */
         ServerBootstrap b = new ServerBootstrap();
         /**
          * 将两个线程组当做参数传递到辅助类,创建serversocketchannel类,配置tcp参数, io处理类,类似于reactor模式中handler类
          */
         b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
               .option(ChannelOption.SO_BACKLOG, 1024).childHandler(new ChildChannelHandler());
         /**
          * 绑定端口,调用同步阻塞方法sync等待绑定完成,完成后返回一个ChannelFuture,主要作用于异步操作的通知回调
          */
         ChannelFuture f = b.bind(port).sync();
         /**
          * 等待服务链路关闭之后main方法函数退出,类似于thread.sleep
          */
         f.channel().closeFuture().sync();
      } catch (Exception e) {
         // TODO: handle exception
      } finally {
         /**
          * 释放资源
          */
         bossGroup.shutdownGracefully();
         workerGroup.shutdownGracefully();
      }
   }

   private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {

      @Override
      protected void initChannel(SocketChannel arg0) throws Exception {
         arg0.pipeline().addLast(new TimeServerHandler());
      }

   }

   public static void main(String[] args) throws Exception {
      int port = 8080;
      if (args != null && args.length > 0) {
         try {
            port = Integer.valueOf(args[0]);
         } catch (Exception e) {
            // TODO: handle exception
         }
      }

      new TimeServer().bind(port);
   }
}

2)服务端  读写的操作类(也就是以后在那读写写数据的地方)

/**
 * ChannelHandlerAdapter主要负责对网络时间进行读写操作,通常我们只要关心channelRead,和exceptionCaught方法就可
 */
public class TimeServerHandler extends ChannelHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
/**
 * 消息经过类型转换,讲msg转为bytebuf,通过buf.readableBytes()方法获取缓存区可读的字节数,根据可读的字节数创建一个byte数组,
 * 然后通过buf.readBytes把可读的数组复制到新建的byte req数据组中,最后通过new string构造函数获取请求消息,然后对消息进行处理,
 * 有“关键字”就发送异步应答消息给客户端
 */
        ByteBuf buf = (ByteBuf) msg;
        byte[] req = new byte[buf.readableBytes()];
        buf.readBytes(req);
        String body = new String(req, "UTF-8");
        System.out.println("The time server receive order: " + body);
        String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new Date(System.currentTimeMillis())
                .toString() : "BAD ORDER";
        ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());
        ctx.write(resp);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();//将消息发送队列中的消息写入到socketchannel中发送给对方,(一般是将消息放到缓存数组中,通过调用flush 才讲缓存中数据全部发给socketchannel)
    }

    @Override



    public void exceptionCaught(ChannelHandlerContext arg0, Throwable arg1) throws Exception {
        arg0.close();
    }
}

3)客户端类

/**
 * 客户端开发
 */
public class TimeClient {
    public void connect(int port ,String host)throws Exception{
        NioEventLoopGroup nioEventLoopGroup = new NioEventLoopGroup();

        try {
            /**
             * 创建客户端处理io的读写nioeventlopgroup线程组,然后创建客户端辅助启动类bootstrap,
             * 注意,这里使用的channel需要设置为niosocketchannel,然后为其添加handler,,然后初始化等
             *
             */
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(nioEventLoopGroup)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new TimeClientHandler());
                        }
                    });
            /**
             * 启动辅助类,发起异步链接,
             */
            ChannelFuture future=bootstrap.connect(host,port).sync();
            future.channel().closeFuture().sync();
        }finally {
            nioEventLoopGroup.shutdownGracefully();
        }


    }

    public static void main(String[] args) throws Exception {
        int port=8080;
        if(args!=null&& args.length>0){
            port=Integer.valueOf(args[0]);
        }
        new TimeClient().connect(port,"127.0.0.1");
    }
}

4)客户端读写数据的地方(实现方式和server实现的接口一样)

public class TimeClientHandler extends ChannelHandlerAdapter{
    private  static final Logger logger= Logger.getLogger(TimeClientHandler.class.getName());
    private final ByteBuf firstMessage;

    public TimeClientHandler(){
        byte[] req="QUERY TIME ORDER".getBytes();
        firstMessage = Unpooled.buffer(req.length);
        firstMessage.writeBytes(req);

    }
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
       ctx.writeAndFlush(firstMessage);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf byteBuf = (ByteBuf) msg;
        byte[] req = new byte[byteBuf.readableBytes()];
        byteBuf.readBytes(req);
        String s = new String(req, "UTF-8");
        System.out.println("Now is :"+s);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
     logger.info("exceptionCaught from downstream :"+cause.getMessage());
     ctx.close();}

运行结果:服务端收到特定的消息,客户端收到服务端返回的时间戳,。


猜你喜欢

转载自blog.csdn.net/skycanf/article/details/80199022