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

5.2.2.Channel

Channel 的基本概念

在 Netty 中,Channel 是表示网络传输的开放连接的抽象。它提供了对不同种类网络传输的统一视图,比如 TCP 和 UDP。

Channel 的生命周期

Channel 的生命周期包括创建、激活、连接、读取、写入和关闭等阶段。Netty 中的 Channel 具有状态,根据不同的事件触发状态转换。

Channel channel = ...; // 获取 Channel 实例// 检查 Channel 是否打开
if (channel.isOpen()) {// 进行数据读取操作channel.read();
}// 关闭 Channel
channel.close();

Channel 的异步 I/O

Netty 中的 Channel 支持异步的 I/O 操作,这意味着可以在不阻塞线程的情况下进行网络通信。下面是一个简单的读取操作示例:

// 从 Channel 中读取数据
channel.read(new ChannelHandler() {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) {// 处理读取到的数据ByteBuf buf = (ByteBuf) msg;System.out.println(buf.toString(Charset.defaultCharset()));buf.release(); // 释放资源}
});

ChannelHandler 和 ChannelPipeline

ChannelHandler 用于处理入站和出站的事件,而 ChannelPipeline 是一系列 ChannelHandler 的链,负责处理 Channel 传递的事件。

// 创建一个 ChannelInitializer 用于初始化 ChannelPipeline
ChannelInitializer<SocketChannel> initializer = new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) {ChannelPipeline pipeline = ch.pipeline();// 添加自定义的 ChannelHandler 到 ChannelPipeline 中pipeline.addLast("handler", new MyChannelHandler());}
};// 在 ServerBootstrap 中应用 ChannelInitializer
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(eventLoopGroup).channel(NioServerSocketChannel.class).childHandler(initializer); 

channel的主要作用

  • close():主要用来关闭channel
  • **closeFuture():**用来处理channel的关闭
    • sync方法作用是同步等待channel的关闭
    • addListener方法是异步等待channel关闭
  • **pipeline():**方法添加处理器
  • **write():**方法是将数据写入
  • **writeAndFlush():**方法是将数据写入并刷出

例如刚刚的客户端代码

		// 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);}
5.2.2.1.连接问题sync
			// 1.创建启动器try {ChannelFuture channelFuture = new Bootstrap().group(new NioEventLoopGroup()).channel(NioSocketChannel.class).handler(new ChannelInitializer<NioSocketChannel>() {@Overrideprotected void initChannel(NioSocketChannel ch) throws Exception {ch.pipeline().addLast(new StringEncoder());}})// 7.连接到服务器// connect方法是异步的,返回一个ChannelFuture(异步调用 就是不关心结果,直接返回)// main线程发起了调用,真正执行了connect是另外一个线程 nio线程.connect(new InetSocketAddress("localhost", 8080));// 7.1.同步等待连接成功 如果不调用sync()方法,main线程会继续往下执行,不会等待connect()方法的执行结果channelFuture.sync();// 7.2.获取连接对象 如果没有调用sync()方法,这里的channel此时还没有真正建立起连接Channel channel = channelFuture.channel(); // 连接对象logger.error("channel: {}", channel);// 8.向服务器发送数据channel.writeAndFlush("hello, world");} catch (Exception e) {throw new RuntimeException(e);}

image-20240226071218470

image-20240226071322706

5.2.2.2.处理结果

带有Future Promise 的类型,都是和异步方法配套使用的,用来正确处理结果的

  • 调用channelFuture.sync()处理同步结果,sync()主要是阻塞当前线程,直到nio线程连接建立完毕

  • 使用addListener(new ChannelFutureListener() )

    • 	// 使用addListener(回调对象)方法,可以在ChannelFuture执行完成后,再执行一些操作channelFuture.addListener(new ChannelFutureListener() {// 在NIO线程连接建立好后,会调用operationComplete方法@Overridepublic void operationComplete(ChannelFuture channelFuture) throws Exception {if (channelFuture.isSuccess()) {// 7.2.获取连接对象 如果没有调用sync()方法,这里的channel就会是nullChannel channel = channelFuture.channel(); // 连接对象logger.error("channel: {}", channel);// 8.向服务器发送数据channel.writeAndFlush("hello, world");} else {// 7.3.连接失败Throwable cause = channelFuture.cause();logger.error("connect failed: {}", cause);}}});
      
5.2.2.3.处理关闭

小需求 : 客户端 不断接收用于输入的信息,然后发送给客户端,当用户端输入q 退出 关闭channel

/**** @author 13723* @version 1.0* 2024/2/27 21:46*/
public class CloseFutureClient {private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());public static void main(String[] args) throws InterruptedException {ChannelFuture channelFuture = new Bootstrap().group(new NioEventLoopGroup()).channel(NioSocketChannel.class).handler(new ChannelInitializer<NioSocketChannel>() {@Overrideprotected void initChannel(NioSocketChannel ch) throws Exception {ch.pipeline().addLast(new StringEncoder());}}).connect(new InetSocketAddress("localhost", 8080));// 客户端 不断接收用于输入的信息,然后发送给客户端,当用户端输入q 退出// 建立建立Channel channel = channelFuture.sync().channel();logger.error("channel: {} ",channel);// 接收用户输入的需求new Thread(()->{Scanner scanner = new Scanner(System.in);while (true){String s = scanner.nextLine();if ("q".equals(s)){// 退出 关闭channel// 1s 后才真正的关闭channel.close();// 退出循环logger.error("处理关闭之后的操作!");break;}// 向服务器 发送数据channel.writeAndFlush(s);}},"input").start();}
}

在这里插入图片描述

在这里插入图片描述

  • 解决

    • 使用CloseFuture.sync()

      		// 关闭Channel// 获取closeFuture对象 1.同步受理关闭 2.异步处理关闭ChannelFuture closeFuture = channel.closeFuture();logger.error("wait close... ");closeFuture.sync();logger.error("处理关闭之后的操作!");
      

      在这里插入图片描述

    • 使用addListener(new ChannelFutureListener())

      		closeFuture.addListener(new ChannelFutureListener() {@Overridepublic void operationComplete(ChannelFuture channelFuture) throws Exception {logger.error("处理关闭之后的操作!");}});
      

      在这里插入图片描述

`

此时关闭,会会发现客户端并没有结束,因为线程虽然结束,但是NioEventLoopGroup 里面可能还有线程,这是时关闭,需要调

**shutdownGracefully()**方法

// 将NioEventLoopGroup提出来  
NioEventLoopGroup group = new NioEventLoopGroup();
ChannelFuture channelFuture = new Bootstrap().group(group)
.........// 然后在处理善后中调用 
@Override
public void operationComplete(ChannelFuture channelFuture) throws Exception {logger.error("处理关闭之后的操作!");// 需要保证整个全部关闭group.shutdownGracefully();
}

在这里插入图片描述

5.2.2.4.为什么使用异步

思考下面这样的场景,4个医生给人看病,每个病人花费20分钟,而且医生看病的过程中,是以病人为单位的,一个病人看完了,才能看下一个病人,假设病人源源不断来,可以计算一天4个医生工作8小时,处理病人总数 4 * 8 * 3 = 96

在这里插入图片描述

经研究 发现 看病可以分为 四个步骤 经拆分后每个步骤仅需要五分钟

在这里插入图片描述

因此 可以做如下优化,只有一开始, 医生 2 3 4 需要分别等待 5 10 15分钟开能开始执行工作,但是只要后续病人源源不断的来,他们就能满负荷工作,并且处理病人的能力提高 到了, 4 * 8 * 12 整个效率 是原先的 4 倍

(满负载情况下)第一个医生 只挂号,一个号五分钟,那么 一个小时 可以处理 12个,之前一个医生从头到尾只能看一个病人,那么一个小时只能看3个

在这里插入图片描述

  • 单线程没法异步提高效率,必须配合多线程,多核心cpu才能发挥异步的优势
  • 异步并没有缩短响应时间,反而有所增加(提高的是吞吐量,单位时间内能够处理请求的速度)
  • 合理任务的拆分,也是利用异步的关键

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

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

相关文章

QT C++实战:实现用户登录页面及多个界面跳转

主要思路 一个登录界面&#xff0c;以管理员Or普通用户登录管理员&#xff1a;一个管理员的操作界面&#xff0c;可以把数据录入到数据库中。有返回登陆按钮&#xff0c;可以选择重新登陆&#xff08;管理员Or普通用户普通用户&#xff1a;一个主界面&#xff0c;负责展示视频…

vue组件中data为什么必须是一个函数

查看本专栏目录 关于作者 还是大剑师兰特&#xff1a;曾是美国某知名大学计算机专业研究生&#xff0c;现为航空航海领域高级前端工程师&#xff1b;CSDN知名博主&#xff0c;GIS领域优质创作者&#xff0c;深耕openlayers、leaflet、mapbox、cesium&#xff0c;canvas&#x…

Spring与SpringBoot入门

Spring入门 要使用Spring最起码需要引入两个依赖: <!-- Spring Core&#xff08;核心&#xff09; --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>5.3.20</version>…

密码学系列(四)——对称密码2

一、RC4 RC4&#xff08;Rivest Cipher 4&#xff09;是一种对称流密码算法&#xff0c;由Ron Rivest于1987年设计。它以其简单性和高速性而闻名&#xff0c;并广泛应用于网络通信和安全协议中。下面是对RC4的详细介绍&#xff1a; 密钥长度&#xff1a; RC4的密钥长度可变&am…

GPT 的基础 - T(Transformer)

我们知道GPT的含义是&#xff1a; Generative - 生成下一个词 Pre-trained - 文本预训练 Transformer - 基于Transformer架构 我们看到Transformer模型是GPT的基础&#xff0c;这篇博客梳理了一下Transformer的知识点。 BERT: 用于语言理解。&#xff08;Transformer的Encoder…

九州金榜|父亲在教育中的作用及重要性

随着社会进步&#xff0c;对比以前教育&#xff0c;现在父亲在教育中的作用越来越明显&#xff0c;孩子的教育离不开父亲&#xff0c;父亲在孩子教育中有什么作用&#xff1f;重要性又是什么呢&#xff1f;下面九州金榜家庭教育就带大家一起分析一下作为父亲&#xff0c;在孩子…

VUE3搭载到服务器

1.搭建服务器 使用 Windows 自带的 IIS 作为服务器。 步骤如下&#xff1a;https://blog.csdn.net/qq_62464995/article/details/130140673 同时&#xff0c;上面的步骤中&#xff0c;还使用了 cpolar 将 IIS 本地网址映射到公共网址。 注&#xff1a; cpolar客户端&#xf…

Ant for Blazor做单个表的增删查改

Ant for Blazor做单个表的增删查改 2024年02月27日花了一天时间弄出来了&#xff0c;基本弄好了&#xff0c;vs2022blazor servernet8,引用的AntDesign版本是0.17.4 代码里的model和repository是用自己牛腩代码生成器生成的东西&#xff0c;sqlsugar的&#xff0c;记得在prog…

括号生成(力扣题目22)

题目描述&#xff1a; 数字 n 代表生成括号的对数&#xff0c;请你设计一个函数&#xff0c;用于能够生成所有可能的并且 有效的 括号组合。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;["((()))","(()())","(())()&q…

Modern C++ std::any的实现原理

1. 前言 std::any 是 C17 中引入的一个新特性&#xff0c;它是一个类型安全的容器&#xff0c;可以在其中存储任何类型(但此类型必须可拷贝构造)的值&#xff0c;包括基本类型、自定义类型、指针等。相比于void* 指针&#xff0c;std::any 更为类型安全&#xff0c;可以避免由…

NC65 rest接口 开发 NC65接口开发

一、在对应模块META-INF下编写 xxx.rest 文件,也要放在Home里对应的目录下。 二、开发接口&#xff0c;继承extends AbstractUAPRestResource&#xff0c;&#xff08;有的项目会继承别的方法如&#xff1a;AbstractNCCRestResource&#xff0c;MTFRestResource&#xff1b;有…

使用 kubeadm 部署k8s集群

一、所有节点系统初始化 1、常规初始化 2、内核版本升级以及内核限制文件参数修改 还可以考虑将旧版本的内核卸载 二、准备nginx负载均衡器和keepalived nginx四层代理&#xff1a; keepalived配置&#xff1a; nginx检测脚本&#xff1a; 三、所有节点部署docker&#xff0c…

SQL函数学习记录

聚合函数 函数是编程语言的基础之一&#xff0c;在对数字的运算中&#xff0c;我们用的最多的就是聚合函数&#xff0c;本篇接下来就详细阐述下SQL中聚合函数的运用。 什么是聚合函数&#xff08;aggregate function&#xff09;&#xff1f; 聚合函数指的是对一组值执行计算…

2023秋季飞书未来无限大会--随笔

这个时代的飞书 数字时代 工作协同平台 AI时代 帮助企业和个人用好AI 企业如何引用大模型能力&#xff1f; 智慧体— 接近人&#xff0c;有进步空间智能伙伴 用时代的科技打造爱不释手的好产品 移动互联网 – 改变信息分发方式 大模型 –自然的人机交互方式 业务协同 …

如何使用便签快速分类工作待办事项

在日常工作和生活中&#xff0c;我们经常需要处理各种各样的待办事项。而有效地分类这些任务&#xff0c;可以帮助我们更好地管理时间和提高工作效率。使用便签是一种简单而实用的方法&#xff0c;下面将介绍如何利用好用便签来快速分类工作待办事项。 首先&#xff0c;你可以…

【数据结构和算法初阶(C语言)】链表-单链表(手撕详讲单链表增删查改)

目录 1.前言&#xff1a;顺序表回顾&#xff1a; 1.1顺序表的优缺点 2.主角----链表 2.1链表的概念 2.2定义一个单链表的具体实现代码方式 3.单链表对数据的管理----增删查改 3.1单链表的创建 3.2单链表的遍历实现 3.2.1利用遍历实现一个打印我们链表内容的函数的函数…

【前端素材】推荐优质后台管理系统Salreo平台模板(附源码)

一、需求分析 当我们从多个层次来详细分析后台管理系统时&#xff0c;可以将其功能和定义进一步细分&#xff0c;以便更好地理解其在不同方面的作用和实际运作。 1. 结构层次 在结构层次上&#xff0c;后台管理系统可以分为以下几个部分&#xff1a; a. 辅助功能模块&#…

Mycat核心教程--ZooKeeper集群搭建【三】

Mycat核心教程--ZooKeeper集群搭建 八、 ZooKeeper集群搭建8.1.ZooKeeper简介8.2.数据复制的好处8.3.Zookeeper设计目的8.4.zookeeper集群包括3种角色8.4.1.Leader角色8.4.2.Follower 角色8.4.3.Observer 角色 8.5.zookeeper集群工作流程8.6.zookeeper集群节点数量为奇数&#…

JS进阶——深入对象

版权声明 本文章来源于B站上的某马课程&#xff0c;由本人整理&#xff0c;仅供学习交流使用。如涉及侵权问题&#xff0c;请立即与本人联系&#xff0c;本人将积极配合删除相关内容。感谢理解和支持&#xff0c;本人致力于维护原创作品的权益&#xff0c;共同营造一个尊重知识…

liunx操作系统 进程的基本概念

进程的基本概念 计算机结构体系冯诺依曼 操作系统的管理进程进程的特性标识符系统的调用 创建新的进程 进程的状态进程队列进程的状态在liunx查看进程状态、 计算机结构体系 冯诺依曼 在没有存储器之前&#xff0c;所有的信息都是直接进入CPU&#xff0c;这样效率很差&#xf…