从零开始学习Netty - 学习笔记 -Netty入门-EventLoop

5.Neety入门

什么是Netty

Netty是一个基于Java NIO的异步事件驱动的网络应用框架。它被广泛用于开发高性能高可靠性的网络通信程序,特别是服务器端和客户端程序。Netty提供了简洁而强大的API,使得开发者能够轻松地构建各种网络应用,包括实时通信系统、游戏服务器、分布式系统等。

Netty的主要特点包括:

  1. 异步和事件驱动Netty基于事件驱动模型,使用异步的方式处理网络IO操作,可以处理大量的并发连接而不需要大量的线程。
  2. 高性能:Netty采用了高效的NIO模型,以及优化的数据结构和算法,能够实现出色的性能表现。
  3. 可定制性:Netty提供了丰富的组件和可定制的API,使得开发者可以根据自己的需求对网络通信进行灵活的定制和扩展。
  4. 多协议支持:Netty支持多种常见的网络协议,包括HTTPWebSocketTCPUDP等,使得开发者可以轻松地实现各种类型的网络应用。

Netty的地位

以下是一些使用Netty框架的知名项目和框架:

  1. Apache Kafka:Kafka是一个分布式流处理平台,它使用Netty来处理网络通信,实现高效的消息传输。
  2. Elasticsearch:Elasticsearch是一个分布式搜索引擎,它使用Netty作为其节点之间通信的底层框架。
  3. gRPC:gRPC是一个高性能的远程过程调用框架,它使用Netty来实现底层的网络通信。
  4. Apache Dubbo:Dubbo是一个高性能的分布式服务框架,它使用Netty作为其网络通信的实现方式。
  5. RocketMQ:RocketMQ是一个开源的分布式消息队列,它使用Netty来实现消息的传输和通信。
  6. Spring 5:Spring 5 引入了对反应式编程的支持,使得开发人员可以更轻松地构建异步和非阻塞的应用程序,而 Netty 作为其底层的网络通信实现之一。Flux API完全抛弃Tomcat 使用Netty作为服务端
  7. Zookeeper:Zookeeper 是一个开源的分布式协调服务,用于管理和协调分布式系统中的各种信息,比如配置管理、命名服务、分布式锁等。

Netty的优势

Netty相对于Java NIO具有以下优势:

  1. 简化的编程模型:Netty提供了更高级别的抽象,使得开发者可以更轻松地编写网络应用程序。Netty隐藏了许多底层细节,提供了易于理解和使用的API,使得开发者能够更专注于业务逻辑的实现。
  2. 丰富的功能和组件:Netty提供了许多预置的编解码器、处理器和插件,涵盖了各种常见的网络通信场景,例如HTTP、WebSocket、UDP等。开发者可以直接使用这些组件,而无需重复实现相同的功能,大大加速了开发过程。
  3. 高性能和可靠性:Netty在底层实现了高效的事件驱动模型和异步IO机制,能够实现更高的吞吐量和更低的延迟。开发者可以借助Netty的优秀性能,构建高性能、高可靠性的网络应用程序。
  4. 可扩展性和灵活性:Netty的组件化设计使得它具有很好的可扩展性和灵活性。开发者可以根据自己的需求选择合适的组件和插件,或者自行扩展和定制特定的功能,从而更好地满足业务需求。
  5. 文档和社区支持:Netty拥有丰富的文档和活跃的社区支持,提供了大量的教程、示例代码和问题解答,帮助开发者快速上手并解决问题。开发者可以通过文档和社区获取到丰富的资源和支持,加速开发过程。

5.1.Hello World

5.1.1.目标

开发一个简单的服务器端 和 客户端

  • 客户端向服务器端发送 Hello,World
  • 服务器仅接收,不返回
implementation 'io.netty:netty-codec-http:4.1.106.Final'
5.1.2.服务器端的代码实现
public class HelloServer {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());public static void main(String[] args) {// ServerBootstrap 是一个启动 NIO 服务的辅助启动类// 1.负责组装Netty组装组件,启动服务器new ServerBootstrap()// 2。配置两个NioEventLoopGroup,一个用于接收客户端连接,另一个用于处理客户端读写// NioEventLoopGroup 是一个处理I/O操作的多线程事件循环 NioEventLoopGroup(selector,thread)(包含 选择器 和 线程 ).group(new NioEventLoopGroup())// 3.Netty 支持多种协议,这里是 NIO 的实现 还有OIO BIO ,EPOLL 等.channel(NioServerSocketChannel.class)// 4.配置ServerSocketChannel的选项 将来处理褚时间的一个分工,决定了worker(child)能执行哪些操作(handler).childHandler(// 5.channel代表和客户进行数据读写的通道 Initializer代表初始化器 负责添加别的handlernew ChannelInitializer<NioSocketChannel>() {@Overrideprotected void initChannel(NioSocketChannel ch) throws Exception {// 6.添加具体的handler// 6.1.添加StringDecoder解码器 数据传输过来的时候,会先经过这个解码器(数据传输的时候都是ByteBuf) 解码成Stringch.pipeline().addLast(new StringDecoder());// 6.2.添加ChannelInboundHandlerAdapter处理器(自定义的业务处理器)ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {// 读时间处理器logger.info("server receive msg: {}", msg);}});}// 7.绑定的监听端口}).bind(8080);}
}
5.1.3.客户端代码实现
public class HelloClient {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());public static void main(String[] args) {// 1.创建启动器try {new Bootstrap()// 2.指定线程模型 一个用于接收客户端连接,另一个用于处理客户端读写.group(new NioEventLoopGroup())// 3.选择客户端的Channel的实现.channel(NioSocketChannel.class)// 4.添加处理器.handler(new ChannelInitializer<NioSocketChannel>() {// 5.初始化处理器@Overrideprotected void initChannel(NioSocketChannel ch) throws Exception {// 6.添加具体的handler 客户端是需要一个编码器ch.pipeline().addLast(new StringEncoder());}})// 7.连接到服务器.connect(new InetSocketAddress("localhost", 8080)).sync().channel()// 8.向服务器发送数据.writeAndFlush("hello, world");} catch (InterruptedException e) {throw new RuntimeException(e);}}
}

image-20240224183231973

image-20240224183319052

image-20240224185022249

5.2.组件

5.2.1.EventLoop

事件循环对象

EventLoop本质是一个单线程执行器(同时维护了一个Selector)里面 run方法处理Channel上远远不断的事件

  • 继承关系

    • 一条线是继承ScheduledExecutorService 因此包含了线程池中所有方法

      • public interface EventLoop extends EventLoopGroup public interface EventLoopGroup extends EventExecutorGroup public interface EventExecutorGroup extends ScheduledExecutorService, Iterable<EventExecutor>
        
    • 另一条线继承了netty自己的OrderedEventExecutor

      • public interface EventLoop extends OrderedEventExecutorpublic interface OrderedEventExecutor extends EventExecutor public interface EventExecutor extends EventExecutorGroup public interface EventExecutorGroup extends ScheduledExecutorService, Iterable<EventExecutor> 
        
        • boolean inEventLoop(Thread var1); 用于判断一个线程是否属于EventLoop
        • EventExecutorGroup parent(); 用于判断自己属于哪一个EventLoopGroup

事件循环组

EventLoopGroup是一组EventLoopChannel一般会调用EventLoopGroupregister方法来绑定其中一个EventLoop,后续这个Channel上的IO事件都由此EventLoop来处理(保证了io事件处理时的线程安全)

  • 继承Netty自己的EventLoopGrouy
    • 实现了Iterable接口提供遍历EventLoop的能力
    • next()方法 用于获取集合中的下一个EventLoop
5.2.1.1. 普通-定时任务
/*** @author 13723* @version 1.0* 2024/2/24 19:34*/
public class TestEventLoop {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());public static void main(String[] args) {// 1.创建事件循环粗// NioEventLoopGroup 比较全面,因为可以向他提交 IO事件  普通任务 定时任务// DefaultEventLoop 主要处理普通任务  和 定时任务// 如果不传线程 那么会自动分配// private static final int DEFAULT_EVENT_LOOP_THREADS =//                                            Math.max(1,
//                                                             SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2)
//                                                  );  1 和你当前 cpu核心数 * 2进行比较 选最大哪个// protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {// 	super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);// }EventLoopGroup group = new NioEventLoopGroup(2);// 2,获取下一个事件的循环对象(本身就设置了两个)logger.error("获取下一个事件的循环对象:{}", group.next());logger.error("获取下一个事件的循环对象:{}", group.next());logger.error("获取下一个事件的循环对象:{}", group.next());// 3.执行普通任务group.next().submit(()->{// 会将任务提交事件组中的某一个事件对象去执行// 类似于线程池的submit,只不过这个是提交到事件循环组中logger.error("普通任务");},"t1");// 4.执行定时任务 让你延迟执行一度任务 或者 周期性执行任务// 参数1.任务 2.延迟时间 3.间隔时间 4.时间单位// 每隔1s打印一次 定时任务group.next().scheduleAtFixedRate(()->{logger.error("定时任务");},0,1, TimeUnit.SECONDS);}}

image-20240224194548086

image-20240224195027567

image-20240224195421157

5.2.1.2. IO任务

依次轮流分配,因为分配给EnventLoopGroup是两个线程
所以 每次Channel进来的时候,会依次和 对应的EventLoop进行绑定,这样下次就是再执行对应的Channel是 还是由绑定的EventLoop去执行

image-20240224222100757

5.2.1.2.1.服务端
/*** @author 13723* @version 1.0* 2024/2/24 18:23*/
public class EventLoopClient {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());public static void main(String[] args) {// 1.创建启动器try {Channel channel = new Bootstrap()// netty职责进行划分 boos 和 worker// .group(new NioEventLoopGroup())// 第一个参数就是Boos 只负责处理ServerSocketChannel Accept事件// 第二个参数是worker 负责处理读SocketChannel 读写事件.group(new NioEventLoopGroup(),new NioEventLoopGroup(2))// 3.选择客户端的Channel的实现.channel(NioSocketChannel.class)// 4.添加处理器.handler(new ChannelInitializer<NioSocketChannel>() {// 5.初始化处理器@Overrideprotected void initChannel(NioSocketChannel ch) throws Exception {// 6.添加具体的handler 客户端是需要一个编码器ch.pipeline().addLast(new StringEncoder());}})// 7.连接到服务器.connect(new InetSocketAddress("localhost", 8080)).sync() // 阻塞方法 知道连接建立.channel();// 代表客户端和服务端的连接// TODO 在这里通过DEBUG 模式 发送多次数据System.out.println("发送数据 结束!");} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
5.2.1.2.2.客户端
/*** @author 13723* @version 1.0* 2024/2/24 18:23*/
public class EventLoopClient {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());public static void main(String[] args) {// 1.创建启动器try {Channel channel = new Bootstrap()// 2.指定线程模型 一个用于接收客户端连接,另一个用于处理客户端读写.group(new NioEventLoopGroup())// 3.选择客户端的Channel的实现.channel(NioSocketChannel.class)// 4.添加处理器.handler(new ChannelInitializer<NioSocketChannel>() {// 5.初始化处理器@Overrideprotected void initChannel(NioSocketChannel ch) throws Exception {// 6.添加具体的handler 客户端是需要一个编码器ch.pipeline().addLast(new StringEncoder());}})// 7.连接到服务器.connect(new InetSocketAddress("localhost", 8080)).sync() // 阻塞方法 知道连接建立.channel();// 代表客户端和服务端的连接// TODO 在这里通过DEBUG 模式 发送多次数据System.out.println("发送数据 结束!");} catch (InterruptedException e) {throw new RuntimeException(e);}}
}

image-20240224211416150

image-20240224211829122

image-20240224212048066

上面是没有进行职责划分时场景,下面对职责进行划分了

// netty职责进行划分 boos 和 worker
// .group(new NioEventLoopGroup())
// 第一个参数就是Boos 只负责处理ServerSocketChannel Accept事件
// 第二个参数是worker 负责处理读SocketChannel 读写事件
.group(new NioEventLoopGroup(),new NioEventLoopGroup(2))

如果单个handler执行时间过长 可以再单独划分出来一个EventLoopGoop去处理,这样就不会影响其他IO线程

public class EventLoopServer {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());public static void main(String[] args) {// 细分2:创建一个独立的EventLoopGroup// 1.创建一个独立的EventLoopGroup 用于处理耗时较长的handlerEventLoopGroup group = new DefaultEventLoop(2);new ServerBootstrap()// 细分1// netty职责进行划分 boos 和 worker// .group(new NioEventLoopGroup())// 第一个参数就是Boos 只负责处理ServerSocketChannel Accept事件// 第二个参数是worker 负责处理读SocketChannel 读写事件  将来的worker线程有两个.group(new NioEventLoopGroup(),new NioEventLoopGroup(2)).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<NioSocketChannel>(){@Overrideprotected void initChannel(NioSocketChannel ch) throws Exception {ch.pipeline().addLast("handler1",new ChannelInboundHandlerAdapter(){/*** 读事件* @param ctx 上下文* @param msg 读到的消息 ByteBuf事件* @throws Exception 异常*/@Overridepublic void channelRead(io.netty.channel.ChannelHandlerContext ctx, Object msg) throws Exception {ByteBuf buf = (ByteBuf) msg;String message = buf.toString(Charset.defaultCharset());logger.error("接收到消息:{}",message);// 处理完毕之后 交给交给handler2进行处理// 将消息传递给下一个handlerctx.fireChannelRead(msg);}// TODO 注意 这里处理较长时间的handler 会导致boos线程组的线程被阻塞 从而影响新的连接的接入 								所以下面分配了,一个独立的EventLoopGroup 用于处理耗时较长的handler}).addLast(group,"handler2",new ChannelInboundHandlerAdapter(){/*** 读事件* @param ctx 上下文* @param msg 读到的消息 ByteBuf事件* @throws Exception 异常*/@Overridepublic void channelRead(io.netty.channel.ChannelHandlerContext ctx, Object msg) throws Exception {ByteBuf buf = (ByteBuf) msg;String message = buf.toString(Charset.defaultCharset());logger.error("接收到消息:{}",message);}});}}).bind(8080);}}

image-20240224221456942

image-20240224221818918

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

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

相关文章

LiveQing视频点播流媒体RTMP推流服务功能-支持配置开启 HTTPS 服务什么时候需要开启HTTPS服务

LiveQing视频点播流媒体RTMP推流服务功能支持配置开启 HTTPS 服务什么时候需要开启HTTPS服务 1、配置开启HTTPS1.1、准备https证书1.1.1、选择Nginx类型证书下载 1.2、配置 开启 HTTPS1.2.1 web页面配置1.2.2 配置文件配置 2、验证HTTPS服务3、为什么要开启HTTPS3.1、安全性要求…

Mysql运维篇(四) MHA

大佬博文 https://www.cnblogs.com/gomysql/p/3675429.html MySQL 高可用&#xff08;MHA&#xff09; - 知乎 一、MHA简介&#xff1a; MHA&#xff08;Master High Availability&#xff09;目前在MySQL高可用方面是一个相对成熟的解决方案&#xff0c;它由日本DeNA公司y…

freeswitch 权威指南 --- 高级篇

官网文档&#xff1a;https://developer.signalwire.com/freeswitch/FreeSWITCH-Explained/ 关于 freeswitch 的公开教程&#xff1a;https://zhuanlan.zhihu.com/p/451981734 内容来自 《FreeSWITCH 权威指南》&#xff1a;目录&#xff1a;https://juejin.cn/post/702058079…

人力资源管理信息化系统如何支持企业开展管理诊断

人力资源顾问有限公司致力于帮助企业开展人力资源管理方面的各项提升改进工作&#xff0c;在长期的咨询工作中&#xff0c;最常听到企业提到的问题莫过于管理诊断方面的问题&#xff0c;事实上&#xff0c;很多企业在日常工作中&#xff0c;都意识到企业内部存在管理方面的问题…

vue3+js 实现记住密码功能

常见的几种实现方式 1 基于spring security 的remember me 功能 ​​​​​​​ localStorage 除非主动清除localStorage 里的信息 &#xff0c;不然永远存在&#xff0c;关闭浏览器之后下次启动仍然存在 存放数据大小一般为5M 不与服务器进行交互通信 cookies 可以…

第11章 互连网络体系结构

之前&#xff0c;我们尚未讨论如何可靠、快速地将消息从一个节点发送到另一个节点。本章目的是讨论多个处理器互连的结构。互连网络最重要的两个性能指标是延迟和带宽。 基于共享存储多处理器的几个通信特性&#xff0c;与诸如局域网或因特网等其他网络系统相比&#xff0c;共…

react hook使用UEditor引入秀米图文排版

里面坑比较多&#xff0c;细节也比较多 以下使用的是react 18 ice3.0&#xff0c;使用其他react脚手架的配置基本相同&#xff0c;例如umi4 1.下载UEditor 进入UEditor仓库&#xff0c;找到版本v1.4.3.3&#xff0c;点击进去 接着下载ueditor1_4_3_3-utf8-jsp.zip版本 下载好…

CentOS 7 定时任务 + Shell 脚本自动备份 MySQL 数据库(一次 Halo 建站数据库丢失的教训)

文章目录 前置条件创建备份脚本设置 Cron 任务测试备份脚本备份安全和维护一键恢复自动清除备份文件常见问题总结 TIP&#xff1a; 原文链接阅读体验更佳&#xff1a;CentOS 7 自动备份 MySQL 数据库 最近抽空简单搭了一个博客&#xff0c;目前内容较少&#xff0c;后续陆续发…

Supermaven惊艳亮相:300,000个Tokens的超大上下文窗口,能否超越Copilot成为代码补全新王者?

当我看到GitHub宣布Copilot的年经常性收入突破1亿美元时&#xff0c;我意识到代码补全技术已经迈入了新的时代。 大型模型的崛起使得这些工具变得更加智能和实用&#xff0c;吸引了越来越多的开发者加入AI编码的行列。 在这个背景下&#xff0c;Supermaven发布了。这是第一个…

TikTok直播网络不稳定是什么原因

在当今社交媒体平台中&#xff0c;TikTok以其独特的视频内容和社交互动功能而备受欢迎。然而&#xff0c;尽管TikTok为用户提供了直播功能&#xff0c;但一些用户可能会遇到TikTok直播网络不稳定的问题。那么&#xff0c;TikTok直播网络不稳定的原因是什么呢&#xff1f;以下是…

(每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第11章 项目成本管理(五)

博主2023年11月通过了信息系统项目管理的考试&#xff0c;考试过程中发现考试的内容全部是教材中的内容&#xff0c;非常符合我学习的思路&#xff0c;因此博主想通过该平台把自己学习过程中的经验和教材博主认为重要的知识点分享给大家&#xff0c;希望更多的人能够通过考试&a…

关于Arrays类中asList(T... a)泛型参数辨析

前提 我们需要知道两点 &#xff08;1&#xff09;T指的是泛型类型&#xff0c;它只能是引用类型&#xff0c;何为引用类型&#xff1f;在java中除了基本数据类型&#xff08;如byte、short、int、long、float、double、boolean、char&#xff09;之外的所有类型都是引用类型…

车载电子测试学习内容

搜集了一些车载测试的学习内容&#xff0c;大家可以参考。

从ChatGPT到Sora,来了解大模型训练中的存储

1 从chatGPT到Sora 2022年底&#xff0c;OpenAI推出人工智能聊天机器人ChatGPT&#xff0c;开启了大模型领域的“竞速跑”模式。2024年2月15日&#xff0c;随着视频生成模型Sora的横空出世&#xff0c;OpenAI再度掀起热潮。 Sora将视频生成内容拉到了一个全新的高度&#xff0c…

osmnx笔记:从OpenStreetMap中提取点和边的shp文件(FMM文件准备内容)

1 导入库 import osmnx as ox import time from shapely.geometry import Polygon import os import numpy as np 2 提取Openstreetmap 的graph Gox.graph_from_place(Huangpu,Shanghai,China,network_typedrive,simplifyTrue) ox.plot_graph(G) 3 提取graph中的点和边 gdf…

冯诺依曼体系结构 计算机组成的金字塔

01 冯诺依曼体系结构&#xff1a;计算机组成的金字塔 学习计算机组成原理&#xff0c;到底是在学些什么呢&#xff1f;这个事儿&#xff0c;一两句话还真说不清楚。不过没关系&#xff0c;我们先从“装电脑”这个看起来没有什么技术含量的事情说起&#xff0c;来弄清楚计算机到…

4 种策略让 MySQL 和 Redis 数据保持一致

先阐明一下 MySQL 和 Redis 的关系&#xff1a;MySQL 是数据库&#xff0c;用来持久化数据&#xff0c;一定程度上保证数据的可靠性&#xff1b;Redis 是用来当缓存&#xff0c;用来提升数据访问的性能。 关于如何保证 MySQL 和 Redis 中的数据一致&#xff08;即缓存一致性问…

2_怎么看原理图之协议类接口之UART笔记

通信双方先约定通信速率&#xff0c;如波特率115200 一开始时&#xff0c;2440这边维持高电平 1> 开始发送时&#xff0c;由2440将&#xff08;RxD0&#xff09;高电平拉低&#xff0c;并持续一个T的时间&#xff08;为了让PC机可以反应过来&#xff09;&#xff0c;T1/波…

汇编语言movs指令学习

字符串传送指令(Move String Instruction) movs 该指令是把指针DS:SI所指向的字节、字或双字传送给指针ES:DI所指向内存单元&#xff0c;并根据标志位DF对寄存器DI和SI作相应增减。该指令的执行不影响任何标志位。 记不清这指令是8086就有的&#xff0c;还是386以后新加的&…

C# OpenVINO PaddleSeg实时人像抠图PP-MattingV2

目录 效果 项目 代码 下载 C# OpenVINO 百度PaddleSeg实时人像抠图PP-MattingV2 效果 项目 代码 using OpenCvSharp; using Sdcb.OpenVINO; using System; using System.Diagnostics; using System.Drawing; using System.Security.Cryptography; using System.Text; us…