Channel

Channel 接口

1、Javadoc 描述

(1)一个网络 Socket 的节点或一个能够进行 I/O 操作的组件,如:读、写、连接、绑定

(2)一个通道提供用户以下选项

(3)通道的当前状态,例如:是否打开?是否连接?

(4)通道的配置参数,例如:接收缓冲区的大小

(5)通道支持的 I/O 操作,例如:读、写、连接、绑定),以及 ChannelPipeline,它处理与通道相关的所有 I/O 事件和请求

(6)Netty 的所有 I/O 操作都是异步的,这意味着任何 I/O 调用将立即返回,不保证所请求的 I/O 操作在调用结束时已经完成;相反,将得到一个 ChannelFuture 实例,它将在请求的 I/O 操作成功、失败或取消时通知

(7)一个通道可以有一个父级,这取决于它是如何创建的。例如,一个被 ServerSocketChannel 接受的

SocketChannel,将在 parent() 返回 ServerSocketChannel 作为它的父级

(8)层次结构的语义取决于通道所属的传输实现。例如,可以写一个新的 Channel 实现,创建共享一个 Socket 连接的子 Channel,就像 BEEP 和 SSH 那样

(9)一些传输系统暴露一些特定于传输系统的额外操作,将通道向下转型到子类型来调用这些操作。例如,在旧 I/O 数据报传输中,组播加入 / 离开操作是由DatagramChannel 提供的

(10)一旦完成了通道的操作,就要调用 ChannelOutboundInvoker.close() 或 ChannelOutboundInvoker.close(ChannelPromise) 来释放所有资源,这可以确保所有的资源都以适当的方式被释放,例如,文件句柄

2、请求关闭通道,并在操作完成后通知 ChannelFuture,要么操作成功,要么出错

ChannelFuture close()

(1)在它被关闭后,不可能再重新使用它

(2)这将导致 ChannelPipeline 中包含的下一个 ChannelOutboundHandler.close(ChannelHandlerContext, ChannelPromise) 方法被调用

3、请求关闭通道,并在操作完成后通知 ChannelFuture,要么操作成功,要么出错

ChannelFuture close(ChannelPromise promise)

(1)在它被关闭后,不可能再重新使用它

(2)给定的 ChannelPromise 将被通知

(3)这将导致 ChannelPipeline 中包含的下一个 ChannelOutboundHandler.close(ChannelHandlerContext, ChannelPromise) 方法被调用

4、返回 ChannelFuture,当这个通道被关闭时,它将被通知

ChannelFuture closeFuture()

(1)这个方法总是返回同一个 ChannelFuture 实例

5、返回指定的 ChannelPipeline

ChannelPipeline pipeline()

6、请求从通道中读取数据到第一个入站缓冲区

Channel read()

(1)如果数据被读取,触发 ChannelInboundHandler.channelRead(ChannelHandlerContext, Object) 事件,并触发 channelReadComplete 事件,以便处理程序可以决定是否继续读取

(2)如果已经有一个悬而未决的读取操作,这个方法什么都不做,这将导致 ChannelPipeline 中的下一个 ChannelOutboundHandler.read(ChannelHandlerContext) 方法被调用

7、请求通过这个 ChannelHandlerContext 通过 ChannelPipeline 写一个消息

ChannelFuture write(Object msg)
ChannelFuture write(Object msg, ChannelPromise promise)

(1)这个方法不会请求实际的刷新,所以一旦需要请求刷新所有悬而未决的数据到实际的传输中,一定要调用 flush()

(2)ChannelPromise:特殊的 ChannelFuture,它是可写的

8、调用 write(Object) 和 flush() 的快捷方法

ChannelFuture writeAndFlush(Object msg)

9、调用 write(Object, ChannelPromise) 和 flush() 的快捷方法

ChannelFuture writeAndFlush(Object msg, ChannelPromise promise)

 

ChannelFuture 接口

1、Javadoc 描述

(1)异步通道 I/O 操作的结果

(2)Netty 的所有 I/O 操作都是异步的,这意味着任何 I/O 调用将立即返回,不保证所请求的 I/O 操作在调用结束时已经完成;相反,将得到一个 ChannelFuture 实例,它将在请求的 I/O 操作成功、失败或取消时通知

(3)ChannelFuture 要么未完成,要么已完成

(4)当 I/O 操作开始时,将创建一个新的 ChannelFuture 对象,新的 ChannelFuture 最初未完成,不会成功、失败、取消,因为 I/O 操作尚未完成

(5)如果 I/O 操作是成功 / 失败 / 取消,ChannelFuture 标记为已完成,并提供更具体的信息,

(6)注意:失败、取消也属于已完成状态

                                      +---------------------------+
                                      | Completed successfully    |
                                      +---------------------------+
                                 +---->      isDone() = true      |
 +--------------------------+    |    |   isSuccess() = true      |
 |        Uncompleted       |    |    +===========================+
 +--------------------------+    |    | Completed with failure    |
 |      isDone() = false    |    |    +---------------------------+
 |   isSuccess() = false    |----+---->      isDone() = true      |
 | isCancelled() = false    |    |    |       cause() = non-null  |
 |       cause() = null     |    |    +===========================+
 +--------------------------+    |    | Completed by cancellation |
                                 |    +---------------------------+
                                 +---->      isDone() = true      |
                                      | isCancelled() = true      |
                                      +---------------------------+

(7)提供各种方法,检查 I/O 操作是否已经完成,等待完成,并检索 I/O 操作的结果,还允许添加 ChannelFutureListeners,这样就可以在 I/O 操作完成时获得通知

(8)建议尽可能选择 addListener(GenericFutureListener),而不是 await(),以便在 I/O 操作完成后获得通知,并进行任何后续任务

(9)addListener(GenericFutureListener) 是非阻塞的,它只是将指定的 ChannelFutureListener 添加到 ChannelFuture 中,当与 ChannelFuture 相关的 I/O 操作完成时,I/O 线程将通知监听器,ChannelFutureListener 产生最好的性能和资源利用率,因为它完全不阻塞,但如果不习惯于事件驱动的编程,实现一个顺序逻辑可能会很棘手

(10)相比之下,await() 是一个阻塞性操作,一旦被调用,调用者的线程就会阻塞,直到操作完成。用await() 实现顺序逻辑比较容易,但调用者线程会不必要地阻塞,直到 I/O 操作完成,而且线程间通知的成本相对较高。此外,在一个特殊的情况下,有可能出现死锁

(11)不要在 ChannelHandler 中调用 await(),ChannelHandler 中的事件处理方法通常是由 I/O 线程调用的。如果 await() 被一个事件处理方法调用,而该方法是由 I/O 线程调用的,它所等待的 I/O 操作可能永远不会完成,因为 await() 会阻塞它所等待的 I/O 操作,这是一个死锁。

(12)确保不要在 I/O 线程中调用 await(),否则,将引发 BlockingOperationException,以防止死锁

(13)不要混淆 I/O 超时和 await 超时,Future.await(long)、Future.await(long, TimeUnit)、Future.awaitUninterruptibly(long)、Future.awaitUninterruptibly(long, TimeUnit) 指定的超时值,与I/O 超时完全没有关系,如果一个 I/O 操作超时,Future 将被标记为 completed with failure

2、将指定的 Listener 添加到 Future

ChannelFuture addListener(GenericFutureListener<? extends Future<? super Void>> listener)
ChannelFuture addListeners(GenericFutureListener<? extends Future<? super Void>>... listeners)

(1)Future 完成此操作时,将通知指定的 Listener

(2)如果此 Future 已完成,则会立即通知指定的 Listener

3、等待这个 Future,直到它完成,如果这个 Future 失败,则重新抛出失败的原因

ChannelFuture sync() throws InterruptedException
ChannelFuture syncUninterruptibly()

4、等待这个 Future 完成

ChannelFuture await() throws InterruptedException

5、等待这个 Future 完成,不被 interrupt,该方法捕获一个 InterruptedException,并静默地丢弃它

ChannelFuture awaitUninterruptibly()

 

处理结果

1、客户端调用建立连接的过程是异步非阻塞的

(1)Bootstrap 可以很容易地引导出一个用于客户端的 Channel

(2)AbstractBootstrap.bind() 方法在与无连接的传输方式(如 UDP)相结合时非常有用

(3)对于常规 TCP 连接,请使用 connect() 方法

2、同步处理

(1)在主线程内,调用 connect 方法,获取 ChannelFuture 对象,ChannelFuture 调用 sync(),获取 Channel,Channel 发送数据

(2)connect 为异步非阻塞方法,主线程调用后不会被阻塞,真正去执行 connect 操作为 NioEventLoop 的线程

(3)connect 后,通过 channelFuture.sync(),阻塞主线程,同步处理结果,等待连接真正建立后,再获取 Channel 并传递数据

(4)若不通过 sync() 方法阻塞主线程,等待连接真正建立,这时通过 channelFuture.channel() 获取的 Channel 对象,并不是真正与服务器建立连接的 Channel,也无法将信息正确的传输给服务器端

3、异步处理

(1)在主线程内,调用 connect 方法,获取 ChannelFuture 对象,ChannelFuture 调用 addListener,传入 ChannelFutureListener(回调对象)

(2)回调方法:operationComplete(即包含 sync() 之后的处理),future 为调用 addListener 的 ChannelFuture

void operationComplete(F future) throws Exception

(3)在 NioEventLoop 的线程内,执行完 connect,获取到 ChannelFuture 时,使用 ChannelFuture 调用 operationComplete

 

关闭后的处理

1、close() 是一个异步非阻塞方法

(1)调用 channel.close(),关闭 Channel

(2)真正关闭操作不是在调用 close() 的线程中执行,而是在 NioEventLoop 的线程中执行真正的关闭操作

2、同步处理

(1)调用 channel.close(),调用 channel.closeFuture(),获取 ChannelFuture 对象,ChannelFuture 调用 sync()

(2)close 后,通过 channelFuture.sync(),阻塞主线程,等待真正关闭连接后,再处理

3、异步处理

(1)调用 channel.close(),获取 ChannelFuture 对象,ChannelFuture 调用 addListener,传入 ChannelFutureListener(回调对象)

(2)回调方法:operationComplete(即包含 sync() 之后的处理),future 为调用 addListener 的 ChannelFuture

void operationComplete(F future) throws Exception

(3)在 NioEventLoop 的线程内,执行完 close,获取到 ChannelFuture 时,使用 ChannelFuture 调用 operationComplete

4、关闭 EventLoopGroup

(1)只关闭 Channel,因为 EventLoopGroup 存在其他线程,所以 Java 进程不会关闭

(2)在关闭处理完成后,调用 shutdownGracefully 关闭 EventLoopGroup

(3)若关闭,客户端、服务端两者对应的 EventLoopGroup 都要关闭

posted @   半条咸鱼  阅读(568)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示