通过java进行网络编程,netty可以提高网络通信的开发效率的同时大大提高网络通信的效率。下面来看下如何使用netty进行高效编程。

引入依赖

<dependency>
    <groupId>io.netty</gro
    <artifactId>netty-all</artifactId>
    <version>4.0.25.Final</version>
</dependency>

netty3和netty4在编程api上有一定的区别,本篇是通过netty4进行实践的。

服务端句柄对象io.netty.bootstrap.ServerBootstrap

netty服务端和客户端的创建都是依赖于Bootstrap句柄对象,下面我们看下服务端是如何通过ServerBootstrap创建服务的。

serverBootstrap.group(new NioEventLoopGroup(), new NioEventLoopGroup()).channel(NioServerSocketChannel.class)
    .localAddress(new InetSocketAddress(nettyServerConfig.getListenPort()))
    .childHandler(new ChannelInitializer<SocketChannel>() {
        @Override
        public void initChannel(SocketChannel ch) throws Exception {
            ch.pipeline().addLast(
                    new NettyEncoder(),
                    new NettyDecoder(),
                    new NettyConnetManageHandler(),
                    new EchoServerHandler());
        }
    });

ChannelFuture f = serverBootstrap.bind().sync();

大家去看源码就可以知道上面都是在初始化ServerBootstrap对象的属性:

  • io.netty.bootstrap.ServerBootstrap#group(io.netty.channel.EventLoopGroup, io.netty.channel.EventLoopGroup)第一个参数是用于接收请求的EventLoopGroup,第二个参数是处理请求的EventLoopGroup。

  • io.netty.bootstrap.AbstractBootstrap#channel用于初始化channelFactory,channel创建为NioServerSocketChannel的类型。

  • io.netty.bootstrap.AbstractBootstrap#localAddress(java.net.SocketAddress)这个没什么好说的设置监听的地址。

  • io.netty.bootstrap.ServerBootstrap#childHandler数据流的handler处理器,上面我们设置了四个handler,分别有数据流出和流进是待处理的handler链。

  • 上面都是在初始化句柄接下来,serverBootstrap.bind().sync()同步开启服务。

客户端句柄对象io.netty.bootstrap.Bootstrap

bootstrap.group(new NioEventLoopGroup()).channel(NioSocketChannel.class)
    .handler(new ChannelInitializer<SocketChannel>() {
        @Override
        public void initChannel(SocketChannel ch) throws Exception {
            ch.pipeline().addLast(
                    new NettyEncoder(),
                    new NettyDecoder(),
                    new NettyClientHandler());
        }
    });

bootstrap.connect(new InetSocketAddress(ip, port));

客户端句柄初始化相对来说简单,初始化处理EventLoopGroup,channel factory,handler处理链,最后connect就可以连接到netty的服务端了。

handler实现

1、NettyEncoder

public class NettyEncoder extends MessageToByteEncoder<NettyCommand> {

    @Override
    public void encode(ChannelHandlerContext ctx, NettyCommand msg, ByteBuf out)
            throws Exception {

        out.writeBytes(msg.encode());
    }
}

2、NettyDecoder

public class NettyDecoder extends ByteToMessageDecoder {

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        byte[] tmpBuf = new byte[in.readableBytes()];
        in.readBytes(tmpBuf);
        NettyCommand command = new NettyCommand();
        out.add(command.decode(tmpBuf));
    }
}

传输对象的encode和decode都依赖于自定义的NettyCommand进行定义。

3、EchoServerHandler

class EchoServerHandler extends ChannelInboundHandlerAdapter {

        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            System.out.println("phase: channelReadComplete");
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx,
                                    Throwable cause) {
            System.out.println("phase: exceptionCaught");
            cause.printStackTrace();
            ctx.close();
        }

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            NettyCommand requestCommand = (NettyCommand) msg;
            System.out.println("Server received: " + new String(requestCommand.getBody()));

            processMessageReceive(ctx, requestCommand);
        }

    }

4、NettyClientHandler

class NettyClientHandler extends SimpleChannelInboundHandler<NettyCommand> {

        @Override
        public void channelActive(ChannelHandlerContext ctx) {
            System.out.println("channelActive");
        }

        @Override
        protected void channelRead0(ChannelHandlerContext ctx, NettyCommand msg)
                throws Exception {
            NettyCommand command = (NettyCommand) msg;
            processMessageReceive(ctx, command);
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx,
                                    Throwable cause) {                    //4
            System.out.println("exceptionCaught");
            cause.printStackTrace();
            ctx.close();
        }

        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            System.out.println("channelReadComplete");
        }
    }

到这里一个简单的hello netty就实现完毕了。

后记

到这里整个脑袋还不是太清晰,可能是因为初次使用netty,很多深入的原理性东西还没有充分的认识到,后面不断学习升华。


博予liutxer
266 声望14 粉丝

专业写代码的代码仔。