Netty入门使用

为什么会有Netty?

NIO 的类库和 API 繁杂,使用起来比较麻烦,需要熟练掌握 Selector、ServerSocketChannel、SocketChannel、ByteBuffer 等。开发工作量和难度都非常大,例如客户端面临断线重连、网络闪断、心跳处理、半包读写、网络拥塞和异常流的处理等。Netty 对 JDK 自带的 NIO 的 API 进行了良好的封装,解决了上述问题。此外,Netty 拥有高性能、吞吐量更高,延迟更低,减少资源消耗,最小化不必要的内存复制等优点。目前使用的是 Netty 4.x 版本,5.x 版本已经废弃,Netty 4.x 需要 JDK 6 以上版本支持.

Netty示例

引入maven依赖

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

服务端代码

public static void main(String[] args) throws Exception{
        // 创建两个线程组bossGroup和workerGroup
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            // 创建服务器端的启动对象
            ServerBootstrap bootstrap = new ServerBootstrap();
            // 使用链式编程来配置参数
            bootstrap.group(bossGroup,workerGroup) // 设置两个线程组
                    .channel(NioServerSocketChannel.class) // 使用NioServerSocketChannel作为服务器的通道实现
                    .option(ChannelOption.SO_BACKLOG,1024) // 初始化服务器连接队列大小
                    .childHandler(new ChannelInitializer<SocketChannel>() { // 创建通道初始化对象,设置初始化参数
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            // 对workerGroup的SocketChannel设置处理器
                            socketChannel.pipeline().addLast(new NettyServerHandler());
                        }
                    });
            System.out.println("Netty server start...");
            // 绑定一个端口并且同步
            ChannelFuture cf = bootstrap.bind(9999).sync();
            // 通过sync方法同步等待通道关闭处理完毕,这里会阻塞等待通道关闭完成
            cf.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }

// 服务端处理器
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
    /**
     * 客户端连接服务端后触发
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ByteBuf buf = Unpooled.copiedBuffer("Hello Netty Server", CharsetUtil.UTF_8);
        ctx.writeAndFlush(buf);
    }

    /**
     * 读取服务端发送的数据
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        System.out.println("收到服务端发送的数据:"+buf.toString(CharsetUtil.UTF_8));
        System.out.println("服务端地址:"+ctx.channel().remoteAddress());
    }

    /**
     * 异常关闭
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
}

// 启动Server服务端 -> 输出
Netty server start...

客户端代码

 public static void main(String[] args) throws Exception{
        // 客户端事件循环组
        NioEventLoopGroup group = new NioEventLoopGroup();
        try {
            // 客户端启动对象
            Bootstrap bootstrap = new Bootstrap();
            // 设置相关参数
            bootstrap.group(group) // 设置线程组
                    .channel(NioSocketChannel.class) // 使用NioSocketChannel作为客户端的通道实现
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            // 加入处理器
                            socketChannel.pipeline().addLast(new NettyClientHandler());
                        }
                    });
            System.out.println("Netty client start");
            // 启动客户端去连接服务器端
            ChannelFuture channelFuture = bootstrap.connect("localhost", 9999).sync();
            // 对关闭通道进行监听
            channelFuture.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }
    }
 // 处理器
 public class NettyClientHandler extends ChannelInboundHandlerAdapter {
    /**
     * 客户端连接服务端后触发
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ByteBuf buf = Unpooled.copiedBuffer("Hello Netty Server", CharsetUtil.UTF_8);
        ctx.writeAndFlush(buf);
    }

    /**
     * 读取服务端发送的数据
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        System.out.println("收到服务端发送的数据:"+buf.toString(CharsetUtil.UTF_8));
        System.out.println("服务端地址:"+ctx.channel().remoteAddress());
    }

    /**
     * 异常关闭
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
}
// 启动客户端 -> 输出
Netty client start
收到服务端发送的数据:ACK
服务端地址:localhost/127.0.0.1:9999
// 服务端 -> 输出
服务器读取线程:nioEventLoopGroup-3-1
客户端发送的消息是:Hello Netty Server

Netty应用场景

1)在互联网行业的分布式系统中,各个节点需要进行远程服务调用,因此需要高性能的RPC框架。Netty作为异步高性能的通信框架,通常作为这些 RPC 框架的基础通信组件。
例如阿里分布式服务框架 Dubbo 使用 Dubbo 协议进行节点间通信,而 Dubbo 协议默认采用 Netty 作为基础通信组件,用于实现各进程节点之间的内部通信。此外,Rocketmq 的底层也使用 Netty 作为基础通信组件。

2)在游戏行业不论是手游服务端还是大型网络游戏,Java 语言的应用越来越广泛。
Netty 作为高性能的基础通信组件,提供了 TCP/UDPHTTP 协议栈。

3)在大数据领域,经典的 Hadoop 的高性能通信和序列化组件 AvroRPC 框架,默认采用 Netty 进行跨界点通信。
它Netty Service 基于 Netty 框架进行二次封装实现。

你可能感兴趣的:(后端)