您的位置:

Netty4全方位解析

一、Netty4教程

Netty4是一款使用Java语言基于NIO框架构建的高性能异步网络通信框架,它提供了一种新的方式在Java平台上开发可扩展的、模块化的、高性能的、可维护的TCP/IP服务器和客户端。Netty4的特点是高性能、高清晰度,易于使用和灵活性。

在Netty4的教程中,我们可以学习如何使用Netty4来编写TCP/IP服务器、客户端和代码示例,如下所示:

public class NettyServer {
    public static void main(String[] args) throws Exception {
        //1.创建EventLoopGroup对象,是一个线程池,实际数量可以根据业务需求调整
        EventLoopGroup bossGroup = new NioEventLoopGroup(1); 
        EventLoopGroup workGroup = new NioEventLoopGroup();
        try {
            //2.创建ServerBootstrap对象,是启动服务的工具类
            ServerBootstrap b = new ServerBootstrap(); 
            b.group(bossGroup, workGroup)
             //3.设置TCP协议的Channel,NioServerSocketChannel是对java.nio.*包的封装
             .channel(NioServerSocketChannel.class) 
             //4.设置对client连接的数据处理逻辑PipeLine
             .childHandler(new ChannelInitializer<SocketChannel>() {     
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new NettyServerHandler());
                }
             })
             //5.设置TCP连接参数,SO_BACKLOG是指处于同一时刻待处理的连接队列的最大长度,超出的新连接会被拒绝,jvm会抛出ConnectionRefusedException
             .option(ChannelOption.SO_BACKLOG, 100)
             //6.设置缓冲区大小,通常可以不设置,会根据操作系统自适应,如果出现流量控制异常,可以考虑增加缓冲区大小
             .option(ChannelOption.SO_SNDBUF, 65535)
             .option(ChannelOption.SO_RCVBUF, 65535)
             //7.设置心跳检测机制以及关闭保护机制,保证TCP的正常关闭,防止TCP连接个数增长到JVM的最大值时出现宕机和内存耗尽等问题
             .childOption(ChannelOption.SO_KEEPALIVE, true)
             .childOption(ChannelOption.TCP_NODELAY, true);
            
            // Bind and start to accept incoming connections.
            //8.绑定端口
            ChannelFuture f = b.bind(PORT).sync(); 
            //9.监听channel关闭事件并执行shutdownGracefully关闭服务器和事件处理组
            f.channel().closeFuture().sync(); 
        } finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }   
}

二、Netty4 Client Pool

在我们使用Netty4来编写客户端时,为了保证程序的高效性,需要使用连接池来减少重新建立连接带来的开销,使用连接池来管理大量的连接可以提高程序的并发量和性能。

下面是使用Apache Commons Pool结合Netty4实现连接池的代码示例:

public class NettyClientFactory extends BasePooledObjectFactory<NettyClient> {
    private String ip;
    private int port;

    public NettyClientFactory(String ip, int port) {
        this.ip = ip;
        this.port = port;
    }

    @Override
    public NettyClient create() throws Exception {
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(new NioEventLoopGroup());
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
        //设置重连机制
        bootstrap.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel channel) throws Exception {
                channel.pipeline().addLast(new NettyClientHandler());
                channel.pipeline().addLast(new IdleStateHandler(0, 5, 0, TimeUnit.SECONDS));
            }
        });
        ChannelFuture channelFuture = bootstrap.connect(ip, port);
        channelFuture.awaitUninterruptibly();
        if (channelFuture != null && channelFuture.isSuccess()) {
            return new NettyClient(channelFuture.channel());
        }
        return null;
    }

    @Override
    public PooledObject<NettyClient> wrap(NettyClient nettyClient) {
        return new DefaultPooledObject<>(nettyClient);
    }
}

三、Netty4源码

深入探究Netty4源码可以大幅度提高我们对Netty4的理解和认识,方便我们更好的使用和维护Netty4。

Netty4的主要源码结构如下:

+- common   -- 通用的代码
+- buffer   -- 字节缓存相关的代码,包括ByteBuf的实现、池化等
+- codec    -- 编码和解码相关的代码
+- channel  -- 整体框架代码,包括Channel和EventLoop的实现
+- handler  -- 处理器相关的代码
+- transport -- 传输相关的代码,包括网络传输和本地传输
+- resolver -- 解析器相关的代码
+- resolver-dns -- DNS解析器相关的代码

其中,参考使用ChannelInboundHandlerAdapter实现简单的数据读取处理,如下代码所示:

public class NettyServerHandler extends ChannelInboundHandlerAdapter {
    private static final Logger log = LoggerFactory.getLogger(NettyServerHandler.class);

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf = (ByteBuf) msg;
        byte[] data = new byte[buf.readableBytes()];
        buf.readBytes(data);
        String request = new String(data, "UTF-8");
        log.info("Server received message: {}", request);

        ByteBuf resp = Unpooled.copiedBuffer("Hello, I'm server!", CharsetUtil.UTF_8);
        ctx.write(resp);
        ctx.flush();
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("Exception caught: {}", cause.getMessage());
        ctx.close();
    }
}

四、Netty4 TCP开发

使用Netty的TCP开发,可以让我们非常轻松、高效、安全地实现TCP协议方面的开发工作。

下面是一个基于Netty4实现的TCP客户端代码示例:

public class NettyTcpClient {
    static final String HOST = System.getProperty("host", "127.0.0.1");
    static final int PORT = Integer.parseInt(System.getProperty("port", "8080"));

    public static void main(String[] args) throws Exception {
        EventLoopGroup group = new NioEventLoopGroup(1);
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
             .channel(NioSocketChannel.class)
             .handler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 protected void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(new NettyClientHandler());
                 }
             });

            ChannelFuture f = b.connect(HOST, PORT).sync();

            f.channel().closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }
    }
}

五、Netty4核心原理

从底层分析Netty4的核心原理可以更好地帮助我们理解和使用Netty4。

Netty4的核心原理是基于NIO的异步网络通信,NIO通过Selector机制在一组Channel中逐个轮询事件,只有一个线程能够轮询并处理多个Channel,因此Netty4是通过NioEventLoop来负责I/O处理事件。

下面是NioEventLoop的源码片段:

public void run() {
    while (!Thread.interrupted()) {
        try {
            // 通过selector来取到Channel
            int numReady = selectStrategy.calculateStrategy(selectNowSupplier, hasTasks());
            // ...
            // 通过selector方式来获取I/O事件
            processSelectedKeys();
            // 处理Channel上的所有I/O任务和定时任务
            runAllTasks();
            // ...
        } catch (Throwable t) {
            // ...
        }
    }
    // ...
}

六、Netty4和5有什么区别

Netty5相比于Netty4在某些方面进行了较大的改变,比如在编解码器方面进行不同程度的优化、异步API使用更加灵活等。

下面是Netty4和Netty5对比的一些区别:

1、Netty4采用EventLoop和EventExecutor分离的设计思路,而Netty5采用异步的ActiveObject计算模型;
2、Netty5新增了一些基于HTTP/2协议的组件;
3、Netty5提供了更加灵活的异步API机制,可以更精细地控制异步事件的执行逻辑;
4、Netty5的通信协议栈进行了重新设计,比如在编解码器方面进行了不同程度的优化;
5、Netty5底层的异步事件处理引擎也进行了改进,更加适配不同场景的使用;

结语

Netty4是一个功能强大、易于使用、高性能的异步网络编程框架,它提供了丰富的网络协议支持和超高的吞吐量,是目前业界最为流行的异步网络编程框架之一。通过对Netty4的全方位解析,更加深入地理解Netty4的使用、原理和优势。