Netty3 源码分析 - ChannelFuture

ChannelFuture抽象的是Channel中异步IO操作的结果。在Netty中,所有的IO操作是异步的,意味着任何IO调用会立刻返回,而不是等到操作真正的执行完成。相反,会返回一个ChannelFuture 对象,在IO完成之后通过其得到结果状态。ChannelFuture 要么完成要么未完成,当IO操作开始执行会创建一个新的future对象,初始状态时uncompleted (不是成功,失败,也不是取消)因为IO操作还木有完成,一旦IO操作完成(成功,失败,或者被取消).这个CHannelFuture对象会被标记为completed ,并且有具体的信息,要注意的是即使失败或取消也属于完成状态。如下图:

有很多方法可以供我们检查IO操作是否完成,等待完成,提携IO操作的结果,并且可以增加ChannelFutureListeners  ,在IO操作完成的时候获得通知,这是观察者模式。建议的方式是利用 addListener(ChannelFutureListener) 而不是 await() 来等待IO操作的完成,addListener(ChannelFutureListener) 是非阻塞的只是为这个ChannelFuture增加了一个ChannelFutureListener,而且在与这个future关联的IO操作完成后,IO线程会通知这些观察者。因为非阻塞, ChannelFutureListener可以获得最后的性能和资源利用率,但是如果你不熟悉事件驱动编程(event-driven
programming)的话,会发现实现一个时序逻辑(a sequential logic )会很棘手。与之相反的是,await() 是阻塞的操作,用await() 实现一个时序逻辑简单些,但是调用线程会毫无必要的阻塞在那里,直达IO操作完成,而且在线程间通信( inter-thread notification)的代价非常大。而且会有发生死锁的情况。

ChannelHandler 中的事件处理方法通常会被IO线程调用,除非pipeline中有个ExecutionHandler 。如果await() 方法被事件处理方法调用,它等待的IO操作可能永远不会完成,所以await() 方法会阻塞它所等待的IO操作,这是一个死锁。所以不要在ChannelHandler中调用await()。

// BAD - NEVER DO THIS

@Override

public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {

if (e.getMessage() instanceof GoodByeMessage) {

ChannelFuture future = e.getChannel().close();

future.awaitUninterruptibly();

// Perform post-closure operation

// ...

}

}

// GOOD

@Override

public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {

if (e.getMessage() instanceof GoodByeMessage) {

ChannelFuture future = e.getChannel().close();

future.addListener(new ChannelFutureListener() {

public void operationComplete(ChannelFuture future) {

// Perform post-closure operation

// ...

}

});

}

}

虽然上面说到了await()方法的弊端,但是也有场景适合它,此时就要确保不会再IO线程中调用它,否则为了防止死锁会抛出 IllegalStateException 。

Do not confuse I/O timeout and await timeout

The timeout value you specify with 为方法await(long), await(long, TimeUnit), awaitUninterruptibly(long), 或者awaitUninterruptibly(long, TimeUnit)指定的超时时间值和IO超时没有任何关系。如果IO操作超时,这个future的状态时 ‘completed with
failure,‘ 比如,连接超时这个选项应该为传输层设置而不是为这个future设置:

// BAD - NEVER DO THIS

ClientBootstrap b = ...;

ChannelFuture f = b.connect(...);

f.awaitUninterruptibly(10, TimeUnit.SECONDS);

if (f.isCancelled()) {

// Connection attempt cancelled by user

} else if (!f.isSuccess()) {

// You might get a NullPointerException here because the future

// might not be completed yet.

f.getCause().printStackTrace();

} else {

// Connection established successfully

}

// GOOD

ClientBootstrap b = ...;

// Configure the connect timeout option.

b.setOption("connectTimeoutMillis", 10000);

ChannelFuture f = b.connect(...);

f.awaitUninterruptibly();

// Now we are sure the future is completed.

assert f.isDone();

if (f.isCancelled()) {

// Connection attempt cancelled by user

} else if (!f.isSuccess()) {

f.getCause().printStackTrace();

} else {

// Connection established successfully

}

详细的源码注释看这里github

时间: 2024-10-29 19:08:16

Netty3 源码分析 - ChannelFuture的相关文章

Netty3 源码分析 - ChannelUpstreamHandler

Netty3 源码分析 - ChannelUpstreamHandler ChannelUpstreamHandler处理上行的通道事件,并且在流水线中传送事件.这个接口最常用的场景是拦截IO工作现场产生的事件,传输消息或者执行相关的业务逻辑.在大部分情况下,我们是使用SimpleChannelUpstreamHandler 来实现一个具体的upstream handler,因为它为每个事件类型提供了单个的处理方法.大多数情况下ChannelUpstreamHandler 是向上游发送事件,虽然

Netty3 源码分析 - NIO server绑定过程分析

一个框架封装的越好,越利于我们快速的coding,但是却掩盖了很多的细节和原理,但是源码能够揭示一切.服务器端代码在指定好ChannelFactory,设定好选项,而后Bootstrap.bind操作就会开启server,接受对端的连接.所以有必要对这后面的过程分析清楚,下图是关键流程.先是构建一个默认的Pipeline,为我们接下来要创建的监听通道服务,这个Pipeline里面会加入一个Binder的上行事件处理器:接下来创建了至关中的NioServerSocketChannel,在构造的过程

Netty3 源码分析 - ClientBootstrap

Bootstrap是通道初始化辅助类 提供了初始化通道或子通道所需要的数据结构,那么ClientBootstrap就是客户端的,而且会执行连接操作. 配置通道,就是把相应的键值对选项传递给底层: ClientBootstrap b = ...; // Options for a new channel b.setOption("remoteAddress", new InetSocketAddress("example.com", 8080)); b.setOpti

Netty3 源码分析 - ChannelStateEvent

ChannelStateEvent是ChannelEvent的子接口,可以代表改变的通知或者是请求,取决于它是上行还是下行事件. UpstreamChannelStateEvent是默认的上行通道状态事件实现类.结合ChannelState中的表很容易看懂源码. DownstreamChannelStateEvent是默认的下行通道状态事件实现类.不同的是需要指定一个Future对象,当相应的动作完成后得到通知.源码很容易理解: public class DownstreamChannelSta

Netty3 源码分析 - 套接字绑定实现原理

前面关注的地方都是Netty采用的流水线处理方式的组织方式,ChannelHandler如何管理,通道状态,通道事件等这些上层的架构设计,那么Netty中如何实现诸如套接字绑定,连接,关闭等这些底层的操作呢?不能只顾着套用API写程序,却对细节不求甚解.这里大致追踪下OIO模式下Channel中套接字绑定的实现,(NIO以后分析)其实逻辑都是一样的,只是在线程模型的地方时不同的. 大致过程如下(详细的源码注释,看我的github): 1.我们在通过Bootstrap启动客户端或者服务端的时候会提

Netty3 源码分析 - Channel

何为通道(Channel)?代表的是一个网络套接字的连接点(nexus). 一个通道抽象的内容包括: 1)当前通道状态,是否打开,是否绑定等: 2)通道的配置参数信息,如套接字缓冲区大小: 3)通道支持的IO操作: 4)处理和这个Channel相关的IO事件和请求的ChannelPipeline. 在Netty中所有的IO操作都是异步的,即执行一个IO调用的时候不会阻塞到操作完成,而后立即返回一个ChannelFuture对象,这个ChannelFuture对象会在某个时候通知我们IO操作执行结

Netty3 源码分析 - ChannelPipeline

ChannelPipeline的作用就是组织一系列的ChannelHandlers 为某一个Channel服务,处理各种事件.实现了拦截过滤器模式的高级形式(an advanced form of the Intercepting Filter pattern),进而有效控制如何处理一个事件以及ChannelHandlers之间如何交互.类型结构图为: 流水线的创建:对于每个新的通道,必须为其创建和添置一个Pipeline,一旦设置,他们之间的耦合就是永久的,这个通道不同添置另一个流水线,不能解

Netty3 源码分析 - ChannelHandlerContext

ChannelHandlerContext存在的意义是可以让其管理的Handler与Pipeline或其他handlers进行交互,ChannelHandler的理解在前面说过. 发送事件:可以调用 sendUpstream(ChannelEvent) 或sendDownstream(ChannelEvent)将一个事件传递给这个Pipeline中与其最近的那个Handler. 修改pipeline:调用 getPipeline()可以得到这个Handler所属的ChannelPipeline对

Netty3 源码分析 - ChannelState

枚举类ChannelState代表的是这个Channel的状态集,状态的解读和ChannelStateEvent中的value值以及事件的方向息息相关,下面这个表可以从宏观上把握. Direction State Value Meaning Upstream OPEN true The channel is open. Upstream OPEN false The channel is closed. Upstream BOUND SocketAddress The channel is bo