摘要
摘要 本文讲解Netty5 Write和Flush事件处理过程。write是发送端的一个handler里的一个主动的write行为。当进行write的时候,是没有立即发送到网络上的,是会将数据先缓存到本地的(至于是怎么缓冲的,就是本文的主题)。当netty监听到socket的write事件发生的时候,就是worker线程将缓冲的数据flush到内核缓冲区的时候了。flush的触发以及处理流程也是本文讲解的内容。 注意:write不意味着另一端就会立即接收到数据,要看nio的write事件是否发生,对于netty来说,此时是否会出触发flush,才会影响另一端是否会接受到数据
欢迎大家关注我的微博 http://weibo.com/hotbain 会将发布的开源项目技术贴通过微博通知大家,希望大家能够互勉共进!谢谢!也很希望能够得到大家对我博文的反馈,写出更高质量的文章!!
write处理流程
业务逻辑handler调用context的write方法,将欲发送的数据发送到带发送缓冲区中.
看看write流程的触发代码(就是在一个业务handler中调用一下write方法即可):
public class DiscardServerHandler extends ChannelHandlerAdapter {
@Override
public void channelRead(final ChannelHandlerContext ctx,final Object msg) throws Exception {
ByteBuf bufferBuf =(ByteBuf)msg;
System.out.println(new String(bufferBuf.array()));
ctx.channel().write(bufferBuf);
}
追踪一下,ctx.channel().write(bufferBuf)的实现(假设out pipeline中没有其他的encode handler了,),我们会看到,最终会由AbstractUnsafe(AbstractUnsafe是channel的一个内部类对象)的write方法(很好找,顺着找就行了,记住,默认pipeline必定会有tail和head两个handler)进行处理,上代码:
public void write(Object msg, ChannelPromise promise) {
if (!isActive()) {
// Mark the write request as failure if the channel is inactive.
if (isOpen()) {
promise.tryFailure(NOT_YET_CONNECTED_EXCEPTION);
} else {
promise.tryFailure(CLOSED_CHANNEL_EXCEPTION);
}
// release message now to prevent resource-leak
ReferenceCountUtil.release(msg);
} else {
//往缓存中添加一个消息对象
outboundBuffer.addMessage(msg, promise);
}
}
这里关注一下outboundBuffer.addMessage() 到此处,大家就会恍然大悟,知道怎么回事儿了,就是这样,仅仅将要写入的message object写入到一个buffer中。下面我们来看一下outboundBuffer.addmessage的实现。
注意: outboundBuffer是一个ChannelOutboundBuffer类型的兑现,每一个channel都会一个ChannelOutboundBuffer对象与之关联,用来盛放欲发送的消息.上代码证明一切:
protected abstract class AbstractUnsafe implements Unsafe {
private ChannelOutboundBuffer outboundBuffer = ChannelOutboundBuffer.newInstance(AbstractChannel.this);
private boolean inFlush0;
}
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
private MessageSizeEstimator.Handle estimatorHandle;
private final Channel parent;
private final ChannelId id = DefaultChannelId.newInstance();
private final Unsafe unsafe;//channel中有Unsafe引用
private final DefaultChannelPipeline pipeline;
private final ChannelFuture succeededFuture = new SucceededChannelFuture(this, null);
/**省略部分代码***/
private final EventLoop eventLoop;
Unsafe对象里有一个outboundBuffer ,而channel里有个unsafe引用,所以可以说,channel与outboundBuffer有has-a关系
看一下ChannelOutboundBuffer outboundBuffer的addMessage实现:
void addMessage(Object msg, ChannelPromise promise) {
//预测message的size
int size = channel.estimatorHandle().size(msg);
if (size < 0) {
size = 0;
}
//创建一个Entry对象,一个entry就是一个欲发送的message以及描述信息
Entry e = buffer[tail++];
e.msg = msg;
e.pendingSize = size;
e.promise = promise;
e.total = total(msg);