(*文章基于Netty4.1.22版本)
ctx.writeAndFlush相当于先调用ctx.write然后再调用ctx.flush,所以下面分析write和flush
write
write和flush会经过pipeline的每个outbound的Handler,之前文章分析过流程,这里不再分析。
write方法最终到达HeadContext的write方法,然后什么都没做,将请求转发到底层实现unsafe,实现在AbstractUnsafe中
public final void write(Object msg, ChannelPromise promise) {
//Netty的缓冲区
ChannelOutboundBuffer outboundBuffer = this.outboundBuffer;
//....
int size;
try {
msg = filterOutboundMessage(msg);// 对msg类型进行过滤和包装
size = pipeline.estimatorHandle().size(msg);
if (size < 0) {
size = 0;
}
} catch (Throwable t) {
//....
}
将msg加入缓冲区
outboundBuffer.addMessage(msg, size, promise);
}
ChannelOutboundBuffer
Netty调用write的时候,不是真的将数据写出去,而是使用了一个缓冲区去存放这份数据,这个缓冲区的实现就是ChannelOutboundBuffer,看下其主要变量
//
// 链表中第一个已经被标记为已flush的Entry元素
private Entry flushedEntry;
// 链表中第一个已经被标记为未flush的Entry元素
private Entry unflushedEntry;
// 链表最后一个Entry元素
private Entry tailEntry;
// 已经标记为flush但是还未写出去的Entry数量
private int flushed;
// ByteBuffer 的数量和大小
private int nioBufferCount;
private long nioBufferSize;
ChannelOutboundBuffer是一个链表,每一个元素类型是Entry,结构如下
Entry(flushedEntry) –> … Entry(unflushedEntry) –> … Entry(tailEntry)
接下来看下addMessage方法
public void addMessage(Object msg, int size, ChannelPromise promise) {
Entry entry = Entry.newInstance(msg, size, total(msg), promise);
if (tailEntry == null) {
flushedEntry = null;
tailEntry = entry;
} else {
Entry tail = tailEntry;
tail.next = entry;
tailEntry = entry;
}
if (unflushedEntry == null) {
unflushedEntry = entry;
}
incrementPendingOutboundBytes(entry.pendingSize, false);
}
链表的操作,先构造一个Entry,然后加入到链表尾部,最后调用了一下incrementPendingOutboundBytes方法
private void incrementPendingOutboundBytes(long size, boolean invokeLater) {
if (size == 0) {
return;
}
// 更新写入的大小
long newWriteBufferSize = TOTAL_PENDING_SIZE_UPDATER.addAndGet(this, size);
if (newWriteBufferSize > channel.config().getWriteBufferHighWaterMark()) {
// 如果当前缓冲区大小大于指定的值,则调用setWritable方法
setUnwritable(invokeLate