Netty 入门实例

文章目录

  • 1. 概述
  • 2. 代码实例
    • 2.1 服务端
    • 2.2 客户端
    • 2.3 运行截图
  • 3. 整体结构
  • 4. 重要组件
    • 4.1 EventLoopGroup、EventLoop
    • 4.2 Handler & Pipeline
    • 4.3 ByteBuf
  • 参考文献

1. 概述

Netty 是一款用于高效开发网络应用的 NIO 网络框架,它大大简化了网络应用的开发过程。

Netty 相比 JDK NIO 的优势:

● 易用性:Netty 在 NIO 基础上进行了更高层次的封装,屏蔽了 NIO 的复杂性,大大降低了开发者的上手难度;
● 稳定性:Netty 修复和完善了 JDK NIO 较多已知问题,例:select 空转导致 CPU 消耗 100%,TCP 断线重连,keep-alive 检测等;
● 可扩展性: 可定制化的线程模型,用户可以通过启动的配置参数选择 Reactor 线程模型;另一个是可扩展的事件驱动模型,将框架层和业务层的关注点分离,开发者只需要关注 ChannelHandler

Netty 比 JDK NIO 更低的资源消耗:

● 对象池复用技术。 Netty 通过复用对象,避免频繁创建和销毁带来的开销;
● 零拷贝技术。 除了操作系统级别的零拷贝技术外,Netty 提供了更多面向用户态的零拷贝技术,例如 Netty 在 I/O 读写时直接使用 DirectBuffer,从而避免了数据在堆内存和堆外内存之间的拷贝;

2. 代码实例

2.1 服务端


import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;import java.nio.charset.CharacterCodingException;
import java.nio.charset.StandardCharsets;/*** Netty服务端示例01*/
public class NettyServer01 {/*** 主函数,服务器的入口点* @param args 命令行参数*/public static void main(String[] args) {// 创建BossGroup和WorkerGroup,分别处理连接接受和数据读写NioEventLoopGroup bossEventLoopGroup = new NioEventLoopGroup(2);NioEventLoopGroup workerEventLoopGroup = new NioEventLoopGroup(8);new ServerBootstrap() // 初始化ServerBootstrap.group(bossEventLoopGroup, workerEventLoopGroup) // 设置EventLoopGroup.channel(NioServerSocketChannel.class) // 指定服务器通道类.childHandler(new ChannelInitializer<NioSocketChannel>() { // 设置通道初始化器/*** 初始化通道,添加处理器到通道的管道中* @param ch 当前初始化的通道*/protected void initChannel(NioSocketChannel ch) {// 添加多个处理器,分别处理入站和出站事件ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {/*** 处理入站数据* @param ctx 通道上下文* @param msg 接收到的消息对象*/@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) {ByteBuf byteBuf = inbound((ByteBuf) msg, "1");ctx.fireChannelRead(byteBuf);}});ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws CharacterCodingException {ByteBuf byteBuf = inbound((ByteBuf) msg, "2");ctx.fireChannelRead(byteBuf);}});ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {/*** 处理入站数据,将处理后的数据写回通道* @param ctx 通道上下文* @param msg 接收到的消息对象*/@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) {ByteBuf byteBuf = inbound((ByteBuf) msg, "3");ctx.channel().write(byteBuf);}});ch.pipeline().addLast(new ChannelOutboundHandlerAdapter() {/*** 处理出站数据,在数据写出前进行加工* @param ctx 通道上下文* @param msg 要写出的消息对象* @param promise 写操作的承诺*/@Overridepublic void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {ByteBuf byteBuf = outbound((ByteBuf) msg, "4");ctx.writeAndFlush(msg);ctx.write(byteBuf, promise);}});ch.pipeline().addLast(new ChannelOutboundHandlerAdapter() {@Overridepublic void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {ByteBuf byteBuf = outbound((ByteBuf) msg, "5");ctx.write(byteBuf, promise);}});ch.pipeline().addLast(new ChannelOutboundHandlerAdapter() {@Overridepublic void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {ByteBuf byteBuf = outbound((ByteBuf) msg, "6");ctx.write(byteBuf, promise);}});}}).bind(8080); // 绑定端口并启动服务器}/*** 对出站数据进行处理* @param msg 待处理的ByteBuf对象* @param no 数据标识号* @return 处理后的ByteBuf对象*/private static ByteBuf outbound(ByteBuf msg, String no) {ByteBuf byteBuf = msg;String output = byteBufToString(byteBuf);System.out.printf("\n\noutbound%s output: %s", no, output);stringWriteToByteBuf(byteBuf, String.format("\noutbound%s 已处理", no));return byteBuf;}/*** 对入站数据进行处理* @param msg 待处理的ByteBuf对象* @param no 数据标识号* @return 处理后的ByteBuf对象*/private static ByteBuf inbound(ByteBuf msg, String no) {String input = byteBufToString(msg);System.out.printf("\n\ninbound%s input: %s\n", no, input);stringWriteToByteBuf(msg, String.format("\ninbound%s 已处理", no));return msg;}/*** 将ByteBuf对象转换为字符串* @param msg 待转换的ByteBuf对象* @return 字符串表示的数据*/private static String byteBufToString(ByteBuf msg) {return msg.toString(StandardCharsets.UTF_8);}/*** 将字符串写入ByteBuf对象* @param byteBuf 待写入的ByteBuf对象* @param msg 要写入的字符串数据*/private static void stringWriteToByteBuf(ByteBuf byteBuf, String msg) {byteBuf.writeBytes(msg.getBytes(StandardCharsets.UTF_8));}
}

2.2 客户端

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringEncoder;import java.nio.charset.StandardCharsets;public class NettyClient01 {public static void main(String[] args) {new Bootstrap().group(new NioEventLoopGroup()).channel(NioSocketChannel.class).handler(new ChannelInitializer<Channel>() {@Overrideprotected void initChannel(Channel ch) {ch.pipeline().addLast(new StringEncoder());ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) {System.out.println(((ByteBuf) msg).toString(StandardCharsets.UTF_8));}});}}).connect("127.0.0.1", 8080).addListener((ChannelFutureListener) future -> {future.channel().writeAndFlush("hello,world");});}
}

2.3 运行截图

服务端截图:

在这里插入图片描述

客户端截图:
在这里插入图片描述

3. 整体结构

● Boss EventLoopGroup: 负责监听网络连接事件,把新网络连接的Channel 注册到 Worker EventLoopGroup
● Worker EventLoopGroup: 分配一个 EventLoop 负责处理该 Channel 的读写事件,每个 EventLoop 都是单线程的,所以该连接线程安全的,通过 Selector 进行事件循环
● 客户端发起 I/O 读写事件时,服务端 EventLoop 会进行数据的读取,然后通过 Pipeline 触发各种监听器进行数据的加工处理。客户端数据会被传递到 ChannelPipeline 的第一个 ChannelInboundHandler 中,数据处理完成后,将加工完成的数据传递给下一个 ChannelInboundHandler。当数据写回客户端时,会将处理结果在 ChannelPipeline 的 ChannelOutboundHandler 中传播,最后到达客户端。

在这里插入图片描述

4. 重要组件

4.1 EventLoopGroup、EventLoop

EventLoop本质上是一个单线程执行器,维护了一个 Selector,里面有run方法处理Channel上源源不断的io事件。EventLoop继承了ScheduledExecutorService、和自己的OrderedEventExecutor,OrderedEventExecutor 提供了inEventLoop(java.lang.Thread thread)、EventExecutorGroup parent()、EventExecutor next() 等方法。

EventLoopGroup 是一组 EventLoop,Channel一般会调用 EventLoopGroup 的 register 方法绑定其中一个EventLoop,后续这个Channel上 的io都由这个EventLoop处理,EventLoop又是单线程的,保证了单个Channel io 事件处理的线程安全性。

4.2 Handler & Pipeline

ChannelHandler 用来处理 Channel 上的各种事件,分为入站、出站两种。所有 ChannelHandler 被连成一串,就是 Pipeline
● 入站处理器通常是 ChannelInboundHandlerAdapter 的子类,主要用来读取客户端数据,写回结果
● 出站处理器通常是 ChannelOutboundHandlerAdapter 的子类,主要对写回结果进行加工

ChannelInboundHandlerAdapter 是按照 addLast 的顺序执行的,而 ChannelOutboundHandlerAdapter 是按照 addLast 的逆序执行的。ChannelPipeline 的实现是一个 ChannelHandlerContext(包装了 ChannelHandler) 组成的双向链表

4.3 ByteBuf

传送

参考文献

  • 黑马 Netty教程
  • 拉钩教育 Netty 核心原理剖析与 RPC 实践 若地老师
    在这里插入图片描述

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

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

相关文章

MySQL查询语句语法使用

目录 一、基本查询二、条件查询2.1 简单条件表达式2.2 逻辑表达式2.3 模糊查询 (LIKE)2.4 范围查询 (BETWEEN ... AND ...)2.5 列表查询 (IN)2.6 空值查询 (IS NULL 或 IS NOT NULL) 三、排序查询3.1 基本语法3.2 单列排序3.2 多列排序3.3 使用表达式排序 四、分组查询聚合函数…

mysql的安装和连接

一.数据库相关概 念 1.数据库 存储数据的仓库,数据是有组织的进行存储,简称DB。 2.数据库管理系统 操纵和管理数据库的大型软件,简称DBM。 3.SQL 操作关系型数据库的编程语言,定义了一套操作关系型数据库统一标准。简称SQL。 二.市面上流行的数据库 1.ORACLE 2.MySQL …

如何搭建一个成功的短剧制作平台

要搭建一个成功的短剧制作平台&#xff0c;需要考虑多个方面&#xff0c;包括目标定位、技术选择、内容管理、用户体验等。 1、明确目标和定位&#xff1a; 确定你的目标受众是谁&#xff0c;他们的年龄、兴趣、消费习惯等。 明确短剧制作平台的主要定位&#xff0c;是提供原创…

新能源燃气灶用的是什么燃料?无需燃料,电生明火

新能源燃气灶广义的讲就是用电生明火的烹饪灶具&#xff0c;如&#xff1a;电焰灶、电燃灶或电火灶&#xff0c;无需任何燃料和氧气助燃&#xff1b;而狭义上讲是采用出电能以外的一切新燃料烹饪灶具&#xff0c;如&#xff1a;高功率燃气灶、生物合成油灶等。在厨房革命的浪潮…

01--MySQL数据库概述

目录 第1章 MySQL数据库概述 1.1 基本概念 1.2 MySQL数据库管理系统 1.3 表的关系 第2章 MySQL卸载、安装、登录 第3章 客户端使用演示 3.1 命令行客户端 3.1.1 数据库 3.1.2 数据表 3.1.3 导入数据 3.1.4 导出数据 3.2 可视化客户端 第4章 SQL语句 4.1 SQL的分类…

Linux中的文本编辑器vi与vim

摘要&#xff1a; 本文将深入探讨VI和VIM编辑器的基本概念、特点、使用方法以及它们在Linux环境中的重要性。通过对这两款强大的文本编辑器的详细分析&#xff0c;读者将能够更全面地理解它们的功能&#xff0c;并掌握如何有效地使用它们进行日常的文本编辑和处理任务。 引言&…

【Mac】FxFactory 8 Pro for Mac(视觉特效处理包)及同类型软件介绍

软件介绍 FxFactory Pro 是一款功能强大的插件管理和创作工具&#xff0c;专为视频编辑器和特效艺术家设计&#xff0c;适用于 macOS 系统。它集成了大量的视频特效插件&#xff0c;并与多种主流视频编辑软件无缝兼容&#xff0c;如 Final Cut Pro、Premiere Pro、After Effec…

vue项目首页优化问题(前后端都要优化)

2.1 config/index.js 开启productionGzip 将其productionGzip 配置成true 2.2 配置Gzip的 插件配置 打开webpack.prod.config.js 配置一下这段代码 代码如下 if (config.build.productionGzip) { const CompressionWebpackPlugin require(‘compression-webpack-plugin’)…

kafka(五)spring-kafka(2)详解与demo

一、简单的收发消息demo 父工程pom&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation&qu…

谷歌手机刷机教学

注意&#xff1a;手机已经解开了oem锁和bl 1、adb基础命令 连接设备adb devices&#xff1a;列出当前连接的所有设备。 adb connect <设备IP>&#xff1a;通过IP地址连接设备&#xff08;用于无线连接&#xff09;。 设备信息adb shell getprop&#xff1a;获取设备的所…

Docker部署MySQL8.3.0(保姆级图文教程)

系列文章目录 Docker部署Nginx1.21.5&#xff08;保姆级图文教程&#xff09; Docker部署MySQL8.3.0&#xff08;保姆级图文教程&#xff09; 文章目录 一、环境二、拉取镜像2.1 查找 Docker Hub 上的 MySQL 镜像2.2 拉取MySQL镜像2.3 查看MySQL镜像 三、在宿主机创建目录3.1 创…

无痛接入图像生成风格迁移能力:GAN生成对抗网络

AI应用开发相关目录 本专栏包括AI应用开发相关内容分享&#xff0c;包括不限于AI算法部署实施细节、AI应用后端分析服务相关概念及开发技巧、AI应用后端应用服务相关概念及开发技巧、AI应用前端实现路径及开发技巧 适用于具备一定算法及Python使用基础的人群 AI应用开发流程概…

【一】【算法】经典树状数组和并查集,详细解析,初步认识,【模板】树状数组 1,树状数组并查集

【模板】树状数组 1 题目描述 如题&#xff0c;已知一个数列&#xff0c;你需要进行下面两种操作&#xff1a; 将某一个数加上 x x x 求出某区间每一个数的和 输入格式 第一行包含两个正整数 n , m n,m n,m&#xff0c;分别表示该数列数字的个数和操作的总个数。 第二…

java: Annotation processing is not supported for module cycles.

java: Annotation processing is not supported for module cycles. 查了半天是造成了循环依赖 解决步骤 1.打开project structure 2.找到循环依赖的两个或多个模块&#xff0c;在dependencies中找到对应的模块并删除 仅记录我遇到这个问题的解决方法&#xff0c;并不适合所…

七层和四层的区别

OSI七层模型的结构如下&#xff1a; 物理层&#xff08;Physical Layer&#xff09;&#xff1a;负责传输原始比特流&#xff0c;实现数据在物理媒介上的传输&#xff1b; 数据链路层&#xff08;Data Link Layer&#xff09;&#xff1a;负责在相邻节点之间传输数据帧&#…

Git简单使用和理解

workspace: 本地的工作目录。 index/stage&#xff1a;暂存区域&#xff0c;临时保存本地改动。 local repository: 本地仓库&#xff0c;只想最后一次提交HEAD。 remote repository&#xff1a;远程仓库。 对于Git,首先应该明白第一git是一种分布式版本控制系统&#xff0c;最…

后仿真中 module path polarity 问题

目录 一 未知极性 二 正极性 三 负极性 不知道大家有没有遇到这个问题:什么?我们知道的module path delay 指的是定义在specify...endspecify block 中的语句,指示输入-输出的延迟信息。 这里的module path 竟然还有极性问题,今天,来学习一下。 模块路径的极性是一…

用RNN构建人名分类器

目录 项目综述1.导入必备的工具包2.处理数据&#xff0c;满足训练要求2.1 统计常用的字符2.2 进行规范化处理,去除重音符号2.3 将文件读取到内存中2.4 构建人名国家和具体人名的对应关系2.5 one-hot编码 3.构建RNN模型3.1 构建传统RNN模型3.2 构建传统LSTM模型3.3 构建传统GRU模…

永久免费设备日志采集工具

免费试用下载: Gitee下载 最新版本 优势: A. 开箱即用. 解压直接运行.不需额外安装. B. 批管理设备. 设备配置均在后台管理. C. 无人值守 客户端自启动,自更新. D. 稳定安全. 架构简单,内存占用小,通过授权访问.

openeuler一个服务异常占用cpu的排查过程

1 环境 硬件环境&#xff1a;LS1046A arm64 系统环境&#xff1a;openEuler release 22.03 (LTS-SP1) Linux kernel 4.19.26 2 问题说明 我的硬件平台需要适配一下 openEuler release 22.03 (LTS-SP1) 但是目前只能使用原来硬件平台的内核&#xff0c;在适配的过程中…