聊聊分布式架构06——[NIO入门]简单的Netty NIO示例

这篇具有很好参考价值的文章主要介绍了聊聊分布式架构06——[NIO入门]简单的Netty NIO示例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

Java NIO和Netty NIO比较

Java NIO:

Netty:

Netty NIO中的主要模块

Transport(传输层)

Buffer(缓冲区)

Codec(编解码器)

Handler(处理器)

EventLoop(事件循环)

Bootstrap和Channel(引导和通道)

Future和Promise(异步编程)

Netty示例

服务端时序图

服务端代码

客户端时序图

客户端代码

总结


聊聊分布式架构06——[NIO入门]简单的Netty NIO示例,分布式架构,分布式,架构,nio

Java NIO和Netty NIO比较

Java NIO:
  1. 原生Java库: Java NIO是Java标准库的一部分,提供了非阻塞I/O的核心功能。它是Java平台上的底层API,允许开发者直接操作通道、缓冲区和选择器等组件。

  2. 较低级别: Java NIO是相对较低级别的API,需要开发者编写更多的底层代码来处理网络通信和协议。这可以提供更多的控制权,但也增加了开发复杂性。

  3. 多路复用: Java NIO通过选择器(Selector)实现多路复用,允许一个线程管理多个通道。这对于处理大量并发连接非常有用。

  4. 手动管理缓冲区: Java NIO需要开发者手动管理缓冲区,包括分配、读取、写入和释放缓冲区。这可能导致更复杂的代码结构。

  5. 适用场景: Java NIO适用于需要高度自定义的网络协议网络服务器。它在性能和灵活性方面提供了更多的控制权。

Netty:
  1. 高级别框架: Netty是一个基于Java NIO的高级别框架,它封装了底层的NIO细节,提供了更简单和强大的API来处理网络通信。

  2. 事件驱动: Netty是事件驱动的框架,使用事件处理器(Event Handlers)来处理入站和出站事件。这使得编写网络应用程序更加模块化和可维护。

  3. 自动管理缓冲区: Netty自动管理缓冲区,无需开发者手动分配和释放缓冲区。这减轻了内存管理的负担。

  4. 丰富的功能: Netty提供了丰富的功能,包括HTTP、WebSocket、TLS/SSL支持、UDP通信、拆包和粘包处理等。它还支持异步和同步I/O操作。

  5. 社区和生态系统: Netty拥有强大的社区支持和丰富的生态系统,有大量的扩展和插件可用。这使得开发人员可以更快地构建复杂的网络应用。

  6. 适用场景: Netty适用于构建高性能、可扩展、可维护的网络应用程序,特别是在处理协议复杂、并发连接众多的情况下。

为什么选择Netty?

Java NIO Netty NIO
API和类库 繁杂麻烦,需掌握Selector、Channel、Buffer等 封装简单,门槛低
扩展实现 需要熟悉多线程和网络编程保证代码质量 通过ChannelHandler对框架灵活扩展
可靠性 可靠性能力需手动补齐,工作量和难度大 预编码、多协议,功能强,性能高
Bug Fixed 臭名昭著的epoll bug(selector空轮询,CPU到100%)1.6版本说修复,1.7版本还在,只是调低了触发率 稳定,成熟,修复了所有已发现的Java NIO Bug
社区生态 / 社区活跃,迭代周期短
生存迭代 / 经历大规模商业应用考验,质量得到验证

基础篇我们使用Java NIO举例演示了简单的RPC通信。代码的行数和步骤确实挺繁琐,不如来看看Netty 的操作,是骡子是马牵出来溜溜先,就当诸君饭后消个食。

Netty NIO中的主要模块

Netty是一个强大的网络编程框架,它由多个主要模块组成,每个模块负责不同的功能。以下是Netty中的一些主要模块:

  1. Transport(传输层)
    • NIO: 这个模块实现了基于Java NIO的传输层,提供了非阻塞的网络通信功能。它包括NioEventLoopGroupNioServerSocketChannelNioSocketChannel等类,用于创建和管理NIO通道。

  2. Buffer(缓冲区)
    • Java NIO中的ByteBuffer局限性:

      • ByteBuffer长度固定,不能动态伸缩和扩展,编码对象时容易引起索引越界异常

      • ByteBuffer只有一个标识位置的指针position,需要手工调用flip()和rewind(),不方便

      • ByteBuffer的API功能有限,需要使用者自己编程实现一些高级和实用的特性

    • 为了弥补这些不足,Netty NIO提供了自己的实现——ByteBuf:

      Netty提供了高性能的缓冲区实现ByteBuf,用于处理数据的读取和写入。ByteBuf提供了直接和间接缓冲区,并支持池化,以减少内存分配和回收的开销。

  3. Codec(编解码器)
    • 编码器和解码器: 这个模块包括一系列编解码器,用于将数据序列化和反序列化为字节,以便在网络中传输。Netty提供了JSON、Protobuf、HTTP、WebSocket等多种编解码器。

  4. Handler(处理器)
    • ChannelHandler: ChannelHandler是Netty中的核心概念,用于处理事件和数据。它可以自定义,用于构建处理链。Netty提供了各种内置的ChannelHandler,如SimpleChannelInboundHandlerChannelDuplexHandler等。

  5. EventLoop(事件循环)
    • EventLoopGroup: 这个模块包括了EventLoopGroupEventLoop,用于实现事件循环机制。EventLoopGroup管理一组EventLoop,每个EventLoop负责处理一组通道上的事件。事件循环是Netty实现异步和事件驱动的关键。

  6. Bootstrap和Channel(引导和通道)
    • ServerBootstrap和Bootstrap: 这两个类用于引导Netty应用程序的启动。ServerBootstrap用于启动服务器端,而Bootstrap用于启动客户端。

    • Channel和ChannelPipeline: Channel表示通道,它代表了一个网络连接。在Channel接口层,采用Fade模式进行统一封装。ChannelPipeline是处理链,包含一系列ChannelHandler,用于处理事件和数据。

  7. Future和Promise(异步编程)
    • Future: Netty使用Future来表示异步操作的结果,允许开发者异步地等待操作完成。

    • Promise: PromiseFuture的扩展,允许开发者设置操作的结果,使得异步编程更加方便。

Netty示例

服务端时序图

聊聊分布式架构06——[NIO入门]简单的Netty NIO示例,分布式架构,分布式,架构,nio

服务端代码
/**
 * Netty Server
 * 开始:需要绑定端口用于启动
 * 1.创建线程组bossGroup用于处理客户端连接
 * 2.创建线程组workGroup用于socket网络读写
 * 3.创建Bootstrap服务启动辅助类,类似serverSocketChannel
 * 4.链式编程,构造线程组、serverChannel、options、channelHandle
 * 5.ChannelHandle继承自ChannelInitializer<SocketChannel>进行功能扩展
 * 结束:优雅退出关闭资源
 */
public class Server {
    public static void main(String[] args) {
        new Server().bind(8088);
    }
​
    /**
     * 绑定端口用于启动
     * @param port 服务端口
     */
    public void bind(int port) {
        // 1.创建线程组bossGroup处理客户端连接
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        // 2.创建线程组workGroup用于socket网络读写
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            // 3.创建Bootstrap服务启动辅助类,类似serverSocketChannel
            ServerBootstrap server = new ServerBootstrap();
            // 4.链式编程,构造线程组、serverChannel、options、channelHandle
            server.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childHandler(new ChildChannelHandler());
            System.out.println("server start on port:" + port);
​
            // 绑定端口异步调用连接客户端,同步阻塞等待(连接结果)连接成功
            ChannelFuture channelFuture = server.bind(port).sync();
​
            // 异步调用close关闭链路,同步阻塞等待(关闭结果)关闭成功后退出main函数
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 优雅退出关闭资源
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
​
    /**
     * 5.ChannelHandle继承自ChannelInitializer<SocketChannel>进行功能扩展
     */
    private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
​
        @Override
        protected void initChannel(SocketChannel socketChannel) throws Exception {
            socketChannel.pipeline().addLast(new ServerHandler());
        }
    }
​
    private class ServerHandler extends ChannelHandlerAdapter {
        @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("Server receive msg:" + body);
            String currTime = "query time".equalsIgnoreCase(body) ? new Date(System.currentTimeMillis()).toString() : "error code";
            ByteBuf resp = Unpooled.copiedBuffer(currTime.getBytes());
            ctx.write(resp);
        }
​
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            ctx.close();
        }
​
        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            ctx.flush(); // 将发送缓冲数组中的消息通过flush()写入socketChannel发送,避免了频繁调用selector进行发送
        }
    }
}
客户端时序图

聊聊分布式架构06——[NIO入门]简单的Netty NIO示例,分布式架构,分布式,架构,nio

客户端代码
/**
 * 开始:连接服务端ip:port
 * 1.创建EventLoopGroup管理socket读取
 * 2.创建客户端辅助类Bootstrap,类似于之前的SocketChannel
 * 3.链式编程,构造客户端流程client、option、handler
 * 4.handler使用的是ChannelInitializer<SocketChannel>
 * 结束:优雅的关闭资源
 */
public class Client {
    public static void main(String[] args) {
        new Client().connect("localhost", 8088);
    }
​
    /**
     * 连接服务端ip:port
     * @param ip 服务端地址
     * @param port 服务端端口
     */
    public void connect(String ip, int port) {
        // 1.创建EventLoopGroup管理socket读取
        EventLoopGroup group =new NioEventLoopGroup();
        try {
            // 2.创建客户端辅助类Bootstrap,类似于之前的SocketChannel
            Bootstrap client = new Bootstrap();
            // 3.链式编程,构造客户端流程client、option、handler
            client.group(group).channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new ClientHandler());
                        }
                    });
​
            // 发起异步连接操作
            ChannelFuture channelFuture = client.connect(ip, port).sync();
​
            // 等待服务端链路关闭
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 优雅退出,释放资源
            group.shutdownGracefully();
        }
    }
​
    /**
     * 4.handler使用的是ChannelInitializer<SocketChannel>
     */
    public class ClientHandler extends ChannelHandlerAdapter {
        @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("client receive server send:" + body);
            channelActive(ctx);
        }
​
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入");
            String clientIn = scanner.nextLine();
            ByteBuf firstMessage = Unpooled.buffer(clientIn.getBytes().length);
            firstMessage.writeBytes(clientIn.getBytes());
            System.out.println("client send:" + clientIn);
            ctx.writeAndFlush(firstMessage);
        }
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            ctx.close();
        }
    }
}

运行结果:

聊聊分布式架构06——[NIO入门]简单的Netty NIO示例,分布式架构,分布式,架构,nio

总结

不难看出,不管是流程步骤还是实现功能的代码行数,Netty NIO都是优于Java原生NIO的。到此,一个简单的NIO入门示例完成。

资料参考:《Netty权威指南》文章来源地址https://www.toymoban.com/news/detail-726605.html

到了这里,关于聊聊分布式架构06——[NIO入门]简单的Netty NIO示例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 聊聊分布式架构02——Http到Https

    目录 HTTP通信协议 请求报文 响应报文 持久连接 状态管理 HTTPS通信协议 安全的HTTPS HTTP到HTTPS的演变 对称加密 非对称加密 混合加密机制 证书机构 SSL到底是什么 HTTPS是身披SSL外壳的HTTP HTTP通信协议 一次HTTP请求的通信流程:客户端浏览器通过域名访问网页资源,由DNS解析得到

    2024年02月07日
    浏览(35)
  • 聊聊分布式架构08——SpringBoot开启微服务时代

    目录 微服务架构时代 快速入门 入门详解 SpringBoot的自动配置 石器时代:XML配置bean 青铜时代:SpringConfig 铁器时代:AutoConfigurationImportSelector 手写简单Starter SpringApplication启动原理 微服务架构时代 Spring Boot的出现与微服务架构有关,它是Spring Framework的一部分,旨在简化开发独

    2024年02月06日
    浏览(37)
  • 聊聊什么是分布式事务

    分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上,以上是百度百科的解释。 简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务

    2024年02月08日
    浏览(26)
  • 【分布式系统】聊聊高性能设计

    对于以上的数字,其实每个程序员都应该了解,因为只有了解这些基本的数字,才能知道对于CPU、内存、磁盘、网络之间数据读写的时间。1000ms = 1S。毫秒-微秒-纳秒-秒-分钟 为什么高性能如此重要的呢,在架构设计中,高性能、高可用、高并发是三高问题。其实背后对应的就

    2024年02月13日
    浏览(37)
  • 聊聊分布式解决方案Saga模式

    Saga模式使用一系列本地事务来提供事务管理,而一个本地事务对应一个Saga参与者,在Saga流程里面每一个本地事务只操作本地数据库,然后通过消息或事件来触发下一个本地事务,如果其中一个本地事务失败了,Saga就会执行一系列补偿事务来实现回滚操作。(补偿事务简单来

    2024年02月06日
    浏览(27)
  • 【分布式锁】06-Zookeeper实现分布式锁:可重入锁源码分析

    前言 前面已经讲解了Redis的客户端Redission是怎么实现分布式锁的,大多都深入到源码级别。 在分布式系统中,常见的分布式锁实现方案还有Zookeeper,接下来会深入研究Zookeeper是如何来实现分布式锁的。 Zookeeper初识 文件系统 Zookeeper维护一个类似文件系统的数据结构 image.png 每

    2024年02月22日
    浏览(33)
  • 聊聊分布式 SQL 数据库Doris(八)

    密集索引:文件中的每个搜索码值都对应一个索引值,就是叶子节点保存了整行. 稀疏索引:文件只为索引码的某些值建立索引项. 稀疏索引的创建过程包括将集合中的元素分段,并给每个分段中的最小元素创建索引。在搜索时,先定位到第一个大于搜索值的索引的前一个索引

    2024年02月05日
    浏览(30)
  • 聊聊分布式 SQL 数据库Doris(二)

    Doris中,Leader节点与非Leader节点和Observer节点之间的元数据高可用和一致性,是通过bdbje(全称:Oracle Berkeley DB Java Edition)的一致性和高可用实现的。 元数据与同步流程 元数据主要存储四类数据: 用户数据信息. 包括数据库, 表的schema, 分片信息等 各类作业信息. 如导入作业, clo

    2024年02月05日
    浏览(48)
  • 聊聊分布式 SQL 数据库Doris(一)

    MPP:Massively Parallel Processing, 即大规模并行处理. 一般用来指多个SQL数据库节点搭建的数据仓库系统. 执行查询的时候, 查询可以分散到多个SQL数据库节点上执行, 然后汇总返回给用户. Doris 作为一款开源的 MPP 架构 OLAP 高性能、实时的分析型数据库,能够运行在绝大多数主流的商

    2024年02月05日
    浏览(34)
  • 聊聊分布式 SQL 数据库Doris(九)

    优化器的作用是优化查询语句的执行效率,它通过评估不同的执行计划并选择最优的执行计划来实现这一目标。 CBO: 一种基于成本的优化器,它通过评估不同查询执行计划的成本来选择最优的执行计划。CBO会根据数据库系统定义的统计信息以及其他因素,对不同的执行计划进

    2024年02月05日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包