Netty入门应用之第一个netty项目

来源:互联网 发布:office mac 更新补丁 编辑:程序博客网 时间:2024/04/29 18:52

服务器端代码

public class TimeServer {    public void bind(int port) throws Exception{        //创建两NioEventLoopGroup实例。        //NioEventLoopGroup是个线程组。        EventLoopGroup bossGroup = new NioEventLoopGroup();        EventLoopGroup workerGroup = new NioEventLoopGroup();        try{            //创建ServerBootstrap对象,它是Netty用于启动NIO服务端的辅助启动类,目的是降低服务端的开发复杂度。            ServerBootstrap b = new ServerBootstrap();            //调用ServerBootstrap的group方法,将两个NIO线程组当做入参传递到ServerBootstrap中。            b.group(bossGroup, workerGroup)                    .channel(NioServerSocketChannel.class)                    .option(ChannelOption.SO_BACKLOG, 1024)                    .childHandler(new ChannelInitializer<SocketChannel>() {                        @Override                        protected void initChannel(SocketChannel socketChannel) throws Exception {                            socketChannel.pipeline().addLast(new TimeServerHandler());                        }                    });            ChannelFuture f = b.bind(port).sync();            //等待服务锻炼路关闭之后main函数才退出。            f.channel().closeFuture().sync();        }finally {            //优雅退出,释放线程池资源。            bossGroup.shutdownGracefully();            workerGroup.shutdownGracefully();        }    }    public static void main(String[] args) throws Exception{        int port = 8088;        new TimeServer().bind(port);    }}
Netty服务器端Handler端代码

public class TimeServerHandler extends ChannelInboundHandlerAdapter {    @Override    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {        //类型转换:将msg转成ByteBuf对象        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 java.util.Date(                System.currentTimeMillis()).toString() : "BAD ORDER" ;        ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());        ctx.write(resp);    }    @Override    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {        // TODO Auto-generated method stub        super.channelReadComplete(ctx);        ctx.flush();    }    @Override    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {        // TODO Auto-generated method stub        super.exceptionCaught(ctx, cause);        ctx.close();    }}
先对服务器端的代码进行一下解析:

        EventLoopGroup bossGroup = new NioEventLoopGroup();        EventLoopGroup workerGroup = new NioEventLoopGroup();
创建两个NioEventLoopGroup实例,NioEventLoopGroup是一个线程组,专门用于网络事件的处理。

这里创建两个的原因是一个用于服务器端接受客户端的连接,另一个用于进行SocketChannel的网络读写。


       ServerBootstrap b = new ServerBootstrap();
创建ServerBootstrap用于启动NIO服务端的辅助启动类,目的是降低服务端的开发复杂度。


 b.group(bossGroup, workerGroup)                    .channel(NioServerSocketChannel.class)                    .option(ChannelOption.SO_BACKLOG, 1024)                    .childHandler(new ChannelInitializer<SocketChannel>() {                        @Override                        protected void initChannel(SocketChannel socketChannel) throws Exception {                            socketChannel.pipeline().addLast(new TimeServerHandler());                        }                    });
调用ServerBootstrap的group方法将两个NIO线程组传递到ServerBootstrap中,设置创建的channel为NioSeverSocketChannel,功能是对应JDK NIO类库中的ServerSocketChannel类。然后配置NioServerSocektChannel的TCP参数。最后绑定处理类,主要用于处理网络I/O事件。


 f.channel().closeFuture().sync();
阻塞方法,等待服务端链路关闭之后main函数才退出。

            bossGroup.shutdownGracefully();            workerGroup.shutdownGracefully();
优雅退出,释放相关资源。

        ByteBuf buf = (ByteBuf) msg;        byte[] req = new byte[buf.readableBytes()];        buf.readBytes(req);        String body = new String(req , "UTF-8");
将msg转换成netty的ByteBuf对象。通过ByteBuf的readableBytes方法可以获取缓冲区可读字节数,根据可读字节数创建byte数组,通过ByteBuf的readBytes方法将缓冲区中的字节数组复制到新建的byte数组中。

    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {        // TODO Auto-generated method stub        super.exceptionCaught(ctx, cause);        ctx.close();    }
当发生异常时,关闭ChannelHandlerContext,释放和channelHandlerContext相关联的句柄资源。


Netty客户端TimeClient

public class TimeClient {    public void connent(int port , String host) throws Exception {        EventLoopGroup group = new NioEventLoopGroup();        try{            Bootstrap b = new Bootstrap();            b.group(group).channel(NioSocketChannel.class)                    .option(ChannelOption.TCP_NODELAY, true)                    .handler(new ChannelInitializer<SocketChannel>() {                        @Override                        protected void initChannel(SocketChannel ch) throws Exception {                            ch.pipeline().addLast(new TimeClientHandler());                        }                    });            ChannelFuture f = b.connect(host , port).sync();            f.channel().closeFuture().sync();        }finally {            group.shutdownGracefully();        }    }    public static void main(String[] args) throws Exception{        int port = 8088;        new TimeClient().connent(port, "127.0.0.1");    }}

Netty客户端TimeClientHandler 代码

public class TimeClientHandler extends ChannelInboundHandlerAdapter {    private static final Logger logger = Logger.getLogger(TimeClientHandler.class.getName());    private byte[] req ;    @Override    public void channelActive(ChannelHandlerContext ctx) throws Exception {        this.req = "QUERY TIME ORDER".getBytes();        ByteBuf message = Unpooled.buffer(req.length);        message.writeBytes(req);        ctx.writeAndFlush(message);    }    @Override    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {        ByteBuf buf = (ByteBuf) msg;        byte[] req = new byte[buf.readableBytes()];        buf.readBytes(req);        String body = new String(req , "UTF-8");        System.out.println("Now is : "+ body);    }    @Override    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {        logger.warning("Unexpected exception from downstream : "+cause.getMessage());        ctx.close();    }}
重点在channelActive, channelRead 和 execptionCaught 三个方法上。当客户端和服务器端TCP链路建立成功之后,Netty的NIO线程会调用channelActive方法,发送查询指令给服务器端,调用ChannelHandlerContext的writeAndFlush方法将请求消息发送给客户端。 当服务端返回应答时,channelRead方法被调用。


原创粉丝点击