【Netty篇】Channel 详解

在这里插入图片描述

🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方式,可以多多支持一下,感谢🤗!

🌟了解 Java的 NIO 请看 : NIO,看完你就懂了!

其他优质专栏: 【🎇SpringBoot】【🎉多线程】【🎨Redis】【✨设计模式专栏已完结)】…等

如果喜欢作者的讲解方式,可以点赞收藏加关注,你的支持就是我的动力
✨更多文章请看个人主页: 码熔burning

各位观众老爷,今天咱们来聊聊 Netty 里的“管道工”—— Channel。幽默风趣的讲解方式,让您听得懂,记得住!🤣

看之前可以先看看Netty的入门:【Netty篇】幽默的讲解带你入门 Netty !建议收藏

一、Channel:Netty 的“水管工”

想象一下,Netty 是一个大型的自来水厂,负责把数据(水)从一个地方输送到另一个地方。那么,Channel 就是这个水厂里的“管道工”,负责:

  • 连接水龙头(Socket): Channel 负责建立和维护客户端和服务器之间的连接,就像管道工连接水龙头一样。🚰
  • 输送水流(数据): Channel 负责在连接上流动数据,就像管道输送水一样。🌊
  • 处理漏水(异常): Channel 负责处理连接上的各种异常情况,比如连接断开、数据错误等等,就像管道工修理漏水一样。🔧

简单来说,Channel 就是 Netty 中网络操作的核心抽象,它代表了一个开放的连接,可以进行读写操作。

Channel 在 Netty 中扮演的角色

Channel 在 Netty 中扮演着至关重要的角色,它就像一个舞台,所有的网络事件都在这个舞台上发生。🎭

  • 事件驱动的核心: Netty 是一个事件驱动的框架,而 Channel 就是事件的载体。所有的网络事件,比如连接建立、数据读取、数据写入、连接关闭等等,都会通过 Channel传递给相应的处理器进行处理。
  • 连接的代表: Channel 代表了一个客户端和服务器之间的连接。通过 Channel,我们可以获取连接的各种信息,比如本地地址、远程地址、连接状态等等。
  • 数据传输的通道: Channel 是数据传输的通道。通过 Channel,我们可以读取客户端发送的数据,也可以向客户端发送数据。

Channel 的主要方法

Channel 提供了很多方法,但最常用的几个是:

  • read() 从 Channel 中读取数据。📖
  • write(Object msg) 向 Channel 中写入数据。✍️
  • flush() 将缓冲区中的数据刷新到 Channel 中,真正发送出去。💨
  • writeAndFlush(Object msg) 相当于 write(msg) + flush(),一次性完成写入和刷新操作。🚀
  • close() 关闭 Channel,断开连接。🚪
  • pipeline() 获取 Channel 关联的 ChannelPipeline,用于添加和管理 ChannelHandler。🔗
  • attr(AttributeKey<T> key) 获取 Channel 的属性,可以用来存储一些自定义的数据。🏷️

二、ChannelFuture:异步操作的“承诺书”

在 Netty 中,很多操作都是异步的,比如连接建立、数据写入、连接关闭等等。这意味着,我们调用这些方法后,并不能立即知道操作是否成功。这时候,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)
    .sync()
    .channel()
    .writeAndFlush(new Date() + ": hello world!");

现在的话我要把它拆开来

ChannelFuture channelFuture = new Bootstrap()
    .group(new NioEventLoopGroup())
    .channel(NioSocketChannel.class)
    .handler(new ChannelInitializer<Channel>() {
        
        protected void initChannel(Channel ch) {
            ch.pipeline().addLast(new StringEncoder());
        }
    })
    .connect("127.0.0.1", 8080);      // 1

channelFuture.sync().channel().writeAndFlush(new Date() + ": hello world!");

调用connect()方法建立连接也就是我标了 1 处的地方返回的是 ChannelFuture 对象,它的作用是利用 channel() 方法来获取 Channel 对象

注意 connect 方法是异步的,意味着不等连接建立,方法执行就返回了。因此 channelFuture 对象中不能【立刻】获得到正确的 Channel 对象

当然,这不具有说服力,上代码:

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.sync(); // 2
System.out.println(channelFuture.channel()); // 3

运行结果
在这里插入图片描述

● 执行到 1 时,连接未建立,打印 [id: 0x00d13c8e]
● 执行到 2 时,sync 方法是同步等待连接建立完成
● 执行到 3 时,连接肯定建立了,打印[id: 0x00d13c8e, L:/127.0.0.1:52223 - R:/127.0.0.1:8080]

除了用 sync 方法可以让异步操作同步以外,还可以使用回调的方式:

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
});

运行结果:

在这里插入图片描述
● 执行到 1 时,连接未建立,打印[id: 0xafd43b44]
● ChannelFutureListener 会在连接建立时被调用(其中 operationComplete 方法),因此执行到 2 时,连接肯定建立了,打印 [id: 0xafd43b44, L:/127.0.0.1:52662 - R:/127.0.0.1:8080]

三、CloseFuture:连接关闭的“倒计时”

CloseFuture 是 ChannelFuture 的一个特殊类型,它代表了 Channel 关闭的未来结果。我们可以通过 CloseFuture 来监听 Channel 的关闭状态,并在 Channel 关闭后执行一些清理操作。⏳

代码示例:使用 CloseFuture 监听连接关闭

Channel channel = ...; // 获取 Channel 对象

// 关闭 Channel
ChannelFuture closeFuture = channel.close();

// 监听连接关闭状态
closeFuture.addListener(new ChannelFutureListener() {
    @Override
    public void operationComplete(ChannelFuture future) throws Exception {
        if (future.isSuccess()) {
            System.out.println("连接已关闭!");
            // 👋
        } else {
            System.err.println("连接关闭失败!");
            future.cause().printStackTrace(); // 打印异常信息
            // 💔
        }
    }
});

在这个例子中,我们使用 close() 方法关闭 Channel,并获取了一个 CloseFuture 对象。然后,我们通过 addListener() 方法添加了一个 ChannelFutureListener,用于监听连接关闭状态。当连接关闭后,operationComplete() 方法会被调用,我们可以在这个方法中执行一些清理操作,比如释放资源等等。

四、总结

  • Channel 是 Netty 中网络操作的核心抽象,代表了一个开放的连接。
  • Channel 负责建立和维护连接,输送数据,处理异常。
  • ChannelFuture 代表了一个异步操作的未来结果,可以用来监听操作的完成状态。
  • CloseFuture 是 ChannelFuture 的一个特殊类型,代表了 Channel 关闭的未来结果,可以用来监听连接关闭状态。

希望通过我这幽默风趣的讲解,您对 Netty 的 Channel 有了更深入的了解。记住,Channel 就是 Netty 的“管道工”,负责连接、输送和维护数据!下次面试的时候,您就可以自信地说:“Channel?那玩意儿我熟!😎”

要了解Netty的EventLoop请看:【Netty篇】EventLoopGroup 与 EventLoop 详解

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值