首页 > 其他分享 >netty入门-4 Channel与ChannelFuture

netty入门-4 Channel与ChannelFuture

时间:2024-07-23 23:00:25浏览次数:10  
标签:netty 异步 ChannelFuture Channel new 方法 channel

Channel

基本类似于NIO中的Channel概念。作为读写数据的通道。
常见方法

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

这些方法其中大多与NIO中的Channel一致。使用起来大同小异。

这里closeFuture是一个异步处理关闭结果的类。
如果我们直接使用close()方法关闭通道,它会异步的去进行关闭,直接执行后面的代码。
所以如果有操作希望在通道完全关闭后再进行就需要用这个closeFuture了。下面会介绍怎么用。

write方法,不一定立即发出消息。因为netty有一个缓冲机制,一般会等到消息积累一定大小再发送。所以writeAndFlush()方法的意义在于,不仅写到缓冲区,还要立即通过网络发送出去。

ChannelFuture

这个 ChannelFuture 是与Channel息息相关的类。
同时对于Future,学过一些并发编程的应该了解,是我们用来获取异步处理结果的类(同步阻塞等待)。
而这里的 ChannelFuture 类似于Future,它的目的是阻塞等待,或者添加异步回调来处理结果。
使用方法见下。
先看我们这段示例代码
在这里插入图片描述
我们观察截图中的代码。
可以看到用Bootstrap创建客户端时,链式调用到connect方法时返回的就是一个ChannelFuture对象。接下来的sync()channel方法自然就是ChannelFuture的方法了。顾名思义,sync()是同步等待结果,channel()是获取对应Channel。然后我们用拿到的Channel去做读写操作。

那么我们connect()方法为什么不能直接拿到Channel,而是要加这么一层ChannelFuture呢?
因为connect()是网络操作,需要一定时间才能完成连接的建立,完成后才能返回对应连接的ChannelNetty所有操作都是异步的)。所以这个ChannelFuture就是用来等待连接结果的,就是一个异步结果的接收类,当connect()操作没完成时去获取Channel是获取不到的,所以调用sync等待异步操作connect()完成再调用channel()获取Channel

注意这里使用ChannelFuturesync的作用是让我们得线程对异步操作同步等待。
本段开头提到还有另一种方法处理异步结果,就是设置回调。即调用addListener方法给ChannelFuture添加一个监听器,并写好我们希望异步操作结束后进行什么操作,在异步操作结束后会触发监听器中我们写好的回调函数。
例子如下:

ChannelFuture channelFuture = new Bootstrap()
    .group(new NioEventLoopGroup())
    .channel(NioSocketChannel.class)
    .handler(new ChannelInitializer<Channel>() {
        @Override
        protected void initChannel(Channel ch) {
            ch.pipeline().addLast(new StringEncoder());
        }
    })
    .connect("127.0.0.1", 8080);
System.out.println(channelFuture.channel()); // 1
channelFuture.addListener((ChannelFutureListener) future -> {
    System.out.println(future.channel()); // 2
});

这里的lambda表达式实际上是重写的ChannelFutureListener类中的operationComplete方法,这个方法会在异步操作完成后被调用,而它由我们重写,所以我们通过这种回调的方式来进行异步方法结果的处理。(具体怎么调用监听器里的方法不太清楚,需要看源码,估计实现应该不难,就是在操作结束后调一个方法。这里仅学习用法。后续我再去学习netty的源码)

同时Netty中除了connect的其他IO操作如writebindread等操作也是异步的,也可以用ChannelFuture来处理。

CloseFuture

ChannelFuture处理connectwrite等操作。
CloseFuture则是特殊的ChannelFuture。专门处理close操作

示例程序

@Slf4j
public class CloseFutureClient {
    public static void main(String[] args) throws InterruptedException {
        NioEventLoopGroup group new NioEventLoopGroup();
        ChannelFuture channelFuture = new Bootstrap()
                .group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    @Override // 在连接建立后被调用
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG));
                        ch.pipeline().addLast(new StringEncoder());
                    }
                })
                .connect(new InetSocketAddress("localhost", 8080));
        Channel channel = channelFuture.sync().channel();
        log.debug("{}", channel);
        new Thread(()->{
            Scanner scanner = new Scanner(System.in);
            while (true) {
                String line = scanner.nextLine();
                if ("q".equals(line)) {
                    channel.close(); // close 异步操作 1s 之后
//                    log.debug("处理关闭之后的操作"); //此处不能做close操作完成后的处理,因为close是异步的,close没完成就会直接执行后面代码
                    break;
                }
                channel.writeAndFlush(line);
            }
        }, "input").start();

        // 获取 CloseFuture 对象, 1) 同步处理关闭, 2) 异步处理关闭
        ChannelFuture closeFuture = channel.closeFuture();
        /*log.debug("waiting close...");
        closeFuture.sync();
        log.debug("处理关闭之后的操作");*/
        closeFuture.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                log.debug("处理关闭之后的操作");
                group.shutdownGracefully();
            }
        });
    }
}

结语

老师这部分是Channel与ChannelFuture一起讲解使用,仅仅讲述了最基本的方法。

对于ChannelFuture的状态,偏内部机制的部分没有讲解。
且在紧接着的下部分讲解Future与Promise时也没有说到。

所以我打算这篇先按课程中的讲解,把最基本的使用摆上来。在下一篇对比分析Netty的Future与Promise时再考虑是否扩展偏底层的部分(我是初学者,扩展还需要自己看书或者找文章看,虽然已经看过了,但是写出来不免还是要费些时间精力的)。

感谢阅读,欢迎批评指正。

标签:netty,异步,ChannelFuture,Channel,new,方法,channel
From: https://blog.csdn.net/qq_42939279/article/details/140647087

相关文章

  • UE MultiLineTraceByChannel函数返回只有一个对象的问题
    问题描述MultiLineTraceByChannel,看函数名字是返回射线检测到的所有对象,实际使用过程中,发现返回的数组中只又一个对象。MultiLineTracebyChannel可以看下官方的文档解释:此指南说明如何使用MultiLineTracebyChannel蓝图节点返回在Visilibity通道上响应的所有Acto......
  • Java NIO SocketChannel
    JavaNIOSocketChannel用于将通道与TCP(传输控制协议)网络套接字连接。它相当于网络编程中使用的Java网络套接字(Socket)。JavaNIO中有两种可用于创建SocketChannel的方法:当传入连接到达ServerSocketChannel时,可以创建它。打开一个SocketChannel,并在网络上与服务器连接。......
  • golang channel 的众多应用场景123
    目录1.应用场景2.应用场景示例2.1并发控制2.2管道|范围迭代|数据传输2.3数据传递->生产者-消费者模型2.4互斥同步2.5信号通知2.6定时器我们知道go中有个很重要的数据结构叫做channel-通道,通过其特性,我们可以完成很多功能,自然就对应到很多应用场景了。1.应用场景......
  • 易优cms网站field 功能:获取channelartlist标签里的字段值,field标签只能在channelartli
    【基础用法】名称:field功能:获取channelartlist标签里的字段值,field标签只能在channelartlist标签里使用。语法:{eyou:channelartlisttypeid='栏目ID'type='son'row='20'}<ahref='{eyou:fieldname='typeurl'/}'>{eyou:fieldname='typenam......
  • YOLOv10改进 | 独家创新- 注意力篇 | YOLOv10引入结合SimAM和Channel Attention形成全
    1.CSimAM介绍     CSimAM(ChannelSimAM)注意力机制结合了SimAM和通道注意力机制(ChannelAttention),在图像特征提取上展现出比单独使用SimAM更为优异的性能。以下是详细描述:     SimAM注意力机制     SimAM(SimilarityAttentionMechanism)通过计......
  • go并发模式 o-channel
    packagemainimport("fmt""time")funcmain(){varorfunc(channels...<-chaninterface{})<-chaninterface{}or=func(channels...<-chaninterface{})<-chaninterface{}{switchlen(channels)......
  • go并发模式 or-do-channel + bridge
    packagemainimport("context""fmt")//orDonefuncorDone(ctxcontext.Context,value<-chanint)<-chanint{ordoneStream:=make(chanint)gofunc(){deferclose(ordoneStream)for{......
  • go并发模式 tee-channel
    packagemainimport("context""fmt""time")functeeChannel(ctxcontext.Context,value<-chanint)(<-chanint,<-chanint){ch1:=make(chanint)ch2:=make(chanint)gofunc(){......
  • Hadoop-17 Flume 介绍与环境配置 实机云服务器测试 分布式日志信息收集 海量数据 实时
    章节内容上一节我们完成了:HiveServer2的介绍和配置安装修改core-sizehdfs-site实现集群的启动Beeline简单上手HCatalog简单上手背景介绍这里是三台公网云服务器,每台2C4G,搭建一个Hadoop的学习环境,供我学习。之前已经在VM虚拟机上搭建过一次,但是没留下笔记,这次......
  • Golang channel底层是如何实现的?(深度好文)
    Hi你好,我是k哥。大厂搬砖6年的后端程序员。我们知道,Go语言为了方便使用者,提供了简单、安全的协程数据同步和通信机制,channel。那我们知道channel底层是如何实现的吗?今天k哥就来聊聊channel的底层实现原理。同时,为了验证我们是否掌握了channel的实现原理,本文也收集了channel的高......