【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 来监听操作的完成状态,并在操作完成后执行一些回调操作。📜

请看一下客户端代码

java 复制代码
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!");

现在的话我要把它拆开来

dart 复制代码
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);      // 1

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

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

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

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

java 复制代码
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 方法可以让异步操作同步以外,还可以使用回调的方式:

java 复制代码
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 监听连接关闭

java 复制代码
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 详解

相关推荐
9527出列3 天前
探索服务端启动流程
netty·源码阅读
深圳蔓延科技4 天前
NioEventLoopGroup 完全指南
netty
深圳蔓延科技5 天前
如何使用 Netty 实现 NIO 方式发送 HTTP 请求
netty
码luffyliu7 天前
Java NIO 核心原理与秋招高频面试题解析
java·nio
带只拖鞋去流浪7 天前
Java文件读写(IO、NIO)
java·开发语言·nio
liangsheng_g11 天前
Kafka服务端NIO操作原理解析
后端·kafka·nio
leo__52011 天前
Java的NIO体系详解
java·python·nio
Derek_Smart12 天前
Netty 客户端与服务端选型分析:下位机连接场景
spring boot·后端·netty
静谧之心13 天前
Go 工程化全景:从目录结构到生命周期的完整服务框架
开发语言·golang·channel·工程化·goroutine
Derek_Smart14 天前
工业级TCP客户端高可靠连接架构设计与Netty优化实践
java·性能优化·netty