🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方式,可以多多支持一下,感谢🤗!
🌟了解 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 详解