【netty系列-07】Netty中组件初步了解和基本使用

news2024/9/22 19:40:27

Netty系列整体栏目


内容链接地址
【一】深入理解网络通信基本原理和tcp/ip协议https://zhenghuisheng.blog.csdn.net/article/details/136359640
【二】深入理解Socket本质和BIOhttps://zhenghuisheng.blog.csdn.net/article/details/136549478
【三】深入理解NIO的基本原理和底层实现https://zhenghuisheng.blog.csdn.net/article/details/138451491
【四】深入理解反应堆模式的种类和具体实现https://zhenghuisheng.blog.csdn.net/article/details/140113199
【五】深入理解直接内存与零拷贝https://zhenghuisheng.blog.csdn.net/article/details/140721001
【六】select、poll和epoll多路复用的区别https://zhenghuisheng.blog.csdn.net/article/details/140795733
【七】深入理解和使用Netty中组件https://zhenghuisheng.blog.csdn.net/article/details/141166098

深入理解和使用Netty中组件

  • 一、netty的初步了解和使用
    • 1. netty基本组件初步了解
    • 2. netty的基本使用
      • 2.1. netty服务端实现
      • 2.2 netty客户端编写
      • 2.3 调试

一、netty的初步了解和使用

在了解netty组件之前,最好先查看一下本人之前的netty文章,结合nio以及前面的socket,对了解netty有很大的帮助,因为netty基于nio。

1. netty基本组件初步了解

BootStrap: netty中的主启动类,类似于Main方法。在客户端中用BootStrap,在服务端中用ServerBootStrap

Channel:用于封装Socket的实现类,类似于nio中的SocketChannel和ServerSocketChannel

EventLoop:表示的是事件循环,类似于那个nio中反应堆模式核心组件的selector,用于事件注册和循环。在这里可以理解为一个线程,用于做循环处理的。那么EventLoopGroup就是一个线程组,用于管理EventLoop

事件:在官网中已经对netty做出过解释,netty是一个异步事件驱动的网络框架。也就是说在netty中,所有的请求和响应以及要做的事情等都被统一的定义成事件,如读取数据,写数据等。事件又分为两种,分别是入站事件和出站事件

ChannelHandler:ChannelHandle就是用于事件的触发器,根据不同的事件触发不同的动作然后做出对应的响应。如在发送数据时,需要对数据进行加密和压缩的动作,因此分别可以给加密一个事件,给压缩一个事件。可以通过ChannelHandle中的方法,定制化一个具体动作的事件

在这里插入图片描述

ChannelPipeline:上面讲解到了加密和压缩两个事件,为了满足这两个事件都被触发,因此就引入了一个ChannelPipeline 的管道,可以将所有的事件阻塞。就是一个简单的责任链模式,当事件在这个 channelPipeline 中执行到哪个ChannelHandle时,则触发对应的动作。

ChannelFuture:依旧是加密和压缩两个事件,需要先将数据加密,后将数据压缩,为了保证事件实现异步的同时,也需要实现事件的顺序性,因此引入了这个ChannelFuture,和线程中的Future是一样的,通过get方法阻塞拿到上一个异步事件的结果

2. netty的基本使用

通过上面在了解了netty的基本组件之后,接下来通过netty内部的一些接口和类,实现一个简单的客户端和服务端之间的通信。在使用netty之前,先说一下以下使用netty的版本,版本为 4.1.42.Fanal

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

2.1. netty服务端实现

首先定义一个NettyServer类,定义服务端这边的端口为8888,然后定义一个处理循环事件的事件组EventLoopGroup,以及定义一个 ServerBootstrap 服务端这边的主启动类,然后主启动类绑定这个事件组,并将封装socket的类定义为 NioServerSocketChannel ,这样就实现了一个基础的netty服务端。

然后netty服务端需要加入对应的事件和处理对应的事件,需要将全部的Handler事件作为子事件加入,并且将对应的handler事件加入到pipeline 中,后面会通过这个EventLoopGrop 事件处理器中的线程通过责任链的模式去处理这些事件。每一个Handler可以交给开发人员去定制化,因此后续自定义实现了一个 NettyServerChannelHandler 的事件。最后需要注意的是,在绑定和获取结果都需要通过阻塞,因为netty底层实现的接口基本是基于异步的。

package com.ruoyi.web.controller.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class NettyServer {
    private static Integer port = 8888;
    public static void main(String[] args) {
        // 创建自定义事件组,一个线程循环的处理事件,类似与nio的selector
        EventLoopGroup loopGroup = new NioEventLoopGroup();
        try{
            //创建服务端主启动类
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(loopGroup)    //绑定组
                    .channel(NioServerSocketChannel.class)
                    .localAddress(port)         //绑定端口
                    .childHandler(new ChannelInitializer<SocketChannel>() { //初始化channel,将事件加入
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new NettyServerChannelHandler());     //将事件加入到管道中
                        }
                    });
            //完成绑定,内部如果异步实现bind,因此需要阻塞拿到返回结果
            ChannelFuture future = bootstrap.bind().sync();
            //关闭future时也需要阻塞,内部也采用的是异步操作
            future.channel().closeFuture().sync();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                //处理中断异常
                loopGroup.shutdownGracefully().sync();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

接下来就是服务端的定制化Handler事件,用于服务端具体的处理事件的动作。如下面这个 NettyServerChannelHandler 类,实现了 ChannelInboundHandlerAdapter 的抽象类,其父类就是一个公共的 ChannelHandler ,然后入通过具体的适配器模式,提供一个可以直接使用的类

在这里插入图片描述

然后在这个适配类中,里面有着各种具体的实现方法。最主要的就是这些注册事件,读事件,写事件等

在这里插入图片描述

接下来主要看看这个 NettyServerChannelHandler 实现类,在该类中继承了ChannelInboundHandlerAdapter抽象类,并且实现了一个read读事件的方法。在接收到客户端的数据之后,将接收到的数据打印出来即可。最后直接关闭此次连接,中断三次握手,将该连接作为短连接

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;

//适配器类,用于处理具体的事件
@Slf4j
public class NettyServerChannelHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf byteBuf = (ByteBuf) msg;
        log.info("接收到的数据为:" + byteBuf.toString(CharsetUtil.UTF_8));
        super.channelRead(ctx, msg);
        //短连接,直接关闭
        ctx.close();
    }
}

2.2 netty客户端编写

其代码编写和服务端基本相同,只有部分代码不同。首先就是客户端需要连接服务端,需要知道服务端的主机和端口号,需要主动的去绑定对应的地址,其次就是客户端这边使用的是BootStrap启动类,还有就是 服务端使用的childHandler客户端只需要具体的handler,最后就是在异步获取服务端使用的是bind阻塞,客户端使用的是connet阻塞。由于直接是在本地开发,所以直接设置这个主机为127.0.0.1本地的即可,端口为上面服务端设置的端口8888

public class NettyClient {
    private static Integer port = 8888;
    private static String host = "127.0.0.1";
    public static void main(String[] args) {
        // 创建自定义事件组,一个线程循环的处理事件,类似与nio的selector
        EventLoopGroup loopGroup = new NioEventLoopGroup();
        try{
            //客户端只需要用bootStrap
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(loopGroup)
                    .channel(NioSocketChannel.class)
                    .remoteAddress(new InetSocketAddress(host,port))    //和服务器不一样,这里只需要连接服务器地址即可
                    .handler(new ChannelInitializer<SocketChannel>() {  //和服务端不同,服务端使用的childHandler客户端只需要具体的handler即可
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new NettyClientChannelHandler());
                        }
                    });
            //完成绑定,内部如果异步实现bind,因此需要阻塞拿到返回结果
            ChannelFuture future = bootstrap.connect().sync();
            //关闭future时也需要阻塞,内部也采用的是异步操作
            future.channel().closeFuture().sync();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

接下来就是服务端这边的事件,由于服务端那边写的是接收消息,那么在客户端这些就写一个发送消息的,即重写一个 channelActive 方法,然后发送一条数据

public class NettyClientChannelHandler extends SimpleChannelInboundHandler {
    protected NettyClientChannelHandler() {
        super();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {

    }

    //tcp三次握手成功之后,触发的事件,可以用于做具体的业务需求
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.copiedBuffer("Hello Netty", CharsetUtil.UTF_8));
    }
}

2.3 调试

在编写完上面的代码之后,先启动服务端的main方法,然后再启动客户端去连接客户端。可以看到服务端这边成功的接收到了数据

[nioEventLoopGroup-2-2] INFO c.r.w.c.n.NettyServerChannelHandler - [channelRead,22] 接收到的数据为:Hello Netty

服务端中的代码和客户端的代码很像,不仅仅是在这,在所有用了netty的组件中,底层都是这样子写的流程都是那一套,都需要主启动类BootStrap或者ServerBootStrap,然后执行事件的任务组EventGroupEvent,然后事件Handler,责任链模式执行事件的管道Pipeline,任务结果Future。有了组件之后,就能完成一个简单又高效的通信组件了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2034355.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java语言程序设计基础篇_编程练习题*16.20(累计秒表)

目录 题目&#xff1a;*16.20&#xff08;累计秒表&#xff09; 习题思路 代码示例 结果展示 题目&#xff1a;*16.20&#xff08;累计秒表&#xff09; 编写一个程序&#xff0c;模拟一个秒表&#xff0c;如图16-45a所示。当用户单击Start按钮时&#xff0c;按钮的标签变为Pa…

AHB协议解读

1.定义 AHB或者ASB系统总线在需要做大量数据传送的模块之间提供了高带宽的接口。同时&#xff0c;外围总线APB在AHB或者ASB和低带宽的外围设备之间提供了通信的桥梁。所以APB是AHB或者ASB的二级扩展总线 2.拓扑结构 2.1 Master: 可以是CPU、DMA控制器、外设控制器等。Maste…

国内外AI大语言模型推荐分享 除了Chatgpt 你会选择哪个模型?

当前AI技术飞速发展&#xff0c;Ai已经成为许多人日常工作和生活中不可或缺的工具&#xff0c;特别是以大语言模型为首的人工智能&#xff0c;它能够与我们进行自然语言对话&#xff0c;支持多种应用场景&#xff0c;如技术问答、代码生成、内容创作等&#xff0c;而且适用于各…

js入门经典学习小结

简介 js是解释型语言&#xff0c;虽然名字有java&#xff0c;但和java&#xff0c;c等编译型语言不同&#xff0c;它是解释型的&#xff0c;类似perl&#xff0c;py 历史 90年代最早js 1.0版本是网景navigator2引入的 然后欧洲计算机制造商协会&#xff08;ECMA&#xff09…

链上数字供应链高级研修班举办 隆道总裁吴树贵分享供应链数字化实践

8月8日-8月9日&#xff0c;链上数字产业研究院联合中国物流与采购联合会举办的“链上数字供应链高级研修班”在上海开班&#xff0c;隆道公司总裁吴树贵作为培训讲师出席&#xff0c;并系统地分享了供应链理论及数字化转型创新实践经验。 “链上数字供应链高级研修班”旨在贯彻…

TCP详解(一)报文详情/MSS/MTU

本文旨在介绍TCP的报文格式详情和传输层、链路层的字节数限制 1 TCP 协议的报文格式 TCP 报文段包括协议首部和数据两部分&#xff0c;协议首部的固定部分是 20 个字节&#xff0c;头部是固定部分&#xff0c;后面是选项部分。 1.1 端口号 16位源端口&#xff1a;发送方主机…

笔记:在WPF中如何控件级全局事件和应用程序级全局事件

一、目的&#xff1a;在WPF中如何控件级全局事件和应用程序级全局事件 二、实现 应用程序级全局事件 //注册应用程序级全局事件 EventManager.RegisterClassHandler(typeof(Button), Button.ClickEvent, new RoutedEventHandler(ic_event_Click)); 如上代码既会注册全局Butt…

Linux--C语言之循环结构

文章目录 一、循环结构&#xff08;一&#xff09;循环的概念&#xff08;二&#xff09;循环的类型&#xff08;三&#xff09;循环的构成&#xff08;四&#xff09;当型循环的实现while死循环 &#xff08;五&#xff09;for...总结死循环 &#xff08;七&#xff09;循环实…

数据结构:链式二叉树(2)

目录 前言 一、节点个数 1.1 二叉树的节点个数 1.2 二叉树叶子节点个数 1.3 二叉树第k层节点个数 二、查找值为x的节点 三、判断二叉树是否为完全二叉树 前言 上一篇 链式二叉树&#xff08;1&#xff09;&#xff0c;主要是讲了了一些链式二叉树的实现基础以及链式二叉…

day28 代码随想录 | 贪心 买卖股票 跳跃游戏 K次取反

买卖股票的最佳时机 II 给你一个整数数组 prices &#xff0c;其中 prices[i] 表示某支股票第 i 天的价格。 在每一天&#xff0c;你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买&#xff0c;然后在 同一天 出售。返回 你能获得的 …

测绘工程项目管理系统,为测绘企业量身定制!测绘项目一体化管理

在日益复杂的测绘工程项目管理领域&#xff0c;高效、精准的信息化管理成为提升工作效率、降低运营成本的关键。企智汇软件&#xff0c;作为一款专为勘察、设计、监测、测绘等多元化工程项目量身打造的管理系统&#xff0c;正逐步成为行业内的佼佼者。 企智汇测绘管理系统深度…

Java FX 学习

声明&#xff1a;参考视频 一. Stage与Scene 舞台与场景&#xff1a;JavaFX应用程序将Ul容器定义为舞台&#xff08;Stage&#xff09;与场景&#xff08;Scene&#xff09;Stage类是顶级容器&#xff0c;它对应于窗体&#xff0c;其内容由Scene决定。Scene类是所有可视化内容…

运维监控体系实践与探索

在当今的数字化时代&#xff0c;运维工作作为企业IT服务的核心&#xff0c;面临着前所未有的挑战与机遇。随着业务规模的扩大和技术栈的复杂化&#xff0c;如何确保系统稳定运行、高效响应&#xff0c;成为运维团队亟需解决的问题。监控体系作为运维工作的基石&#xff0c;其建…

Python+selenium基于PO模式的Web自动化测试框架详解

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、什么是Selenium&#xff1f; Selenium是一个基于浏览器的自动化测试工具&#xff0c;它提供了一种跨平台、跨浏览器的端到端的web自动化解决方案。Selenium主…

分布式锁 分布式锁解决了什么问题 如何实现 看门狗机制是什么

分布式锁的基本概念 在 Redis 中实现分布式锁的常用方式是通过 SETNX 命令&#xff08;SET with NX option&#xff09;来设置一个键&#xff08;key&#xff09;&#xff0c;这个键代表锁。如果 key 不存在&#xff0c;SETNX 会设置成功&#xff0c;并返回 1&#xff0c;表示…

【LinuxPython】linux中通过源码方式安装python环境

python环境安装直接看第二部分即可。 文章目录 1.背景2.python安装3.包环境复制 1.背景 部署一个线上任务时&#xff0c;相同的代码本地开发机正常产出数据&#xff0c;线上产出数据为0&#xff0c;排查到原因是&#xff1a; ...File "/home/disk1/wangdeyong/venv/pyth…

linux搭建zabbix

zabbix简介 Zabbix是一个监控系统&#xff0c;它可以帮助我们实时检查设备的状态&#xff0c;比如服务器、网络设备等。当设备出现问题时&#xff0c;它会及时通知我们&#xff0c;让我们可以采取措施来解决。同时&#xff0c;它还可以把收集到的数据转化成图表和报告&#xf…

ITL-Internet Technology Letters

文章目录 一、期刊简介二、征稿信息三、投稿须知四、咨询 一、期刊简介 Internet Technology Letters本期旨在涵盖所有用于提高物联网性能的新兴或现代学习算法。在此背景下&#xff0c;我们打算收集有关物联网学习进展的研究论文。强烈鼓励与机器学习、计算智能、概率学习、统…

树和图()

预备知识&#xff08;可以不看&#xff09;&#xff1a; 无向图可以理解为是特殊的有向图 1. 图的遍历&#xff08;因为树可以理解为是特殊的图&#xff0c;因此这里不考虑树的遍历&#xff0c;只考虑图的遍历&#xff09; 给定一个具体的图&#xff0c;便于分析 下面是树的结构…

Servlet——个人笔记

Servlet——个人笔记 文章目录 [toc]Servlet简介Servlet命名Servlet由来实现过程 Servlet 相对 CGI 的优势简要说说什么是CGI Servlet 在IDEA中开发流程Servlet注解方式配置WebServlet注解源码WebServlet注解使用 Servlet常见容器Servlet 生命周期简介测试 Servlet 方法init()…