当Channel write
向缓冲区写入数据的时候,如果数据量超过了设置的高水位值,就设置通道Channel
不可写状态。
当Channel flush
将缓冲区中的数据写入到TCP缓冲区之后,如果Netty缓冲区的数据量低于低水位值时,就设置通过Channel可写状态。
Netty默认设置的高水位为64KB
,低水位为32KB
。
1. 例子
ServerBootstrap sb = new ServerBootstrap();
bootstrap.childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(32 * 1024, 64 * 1024));
判断channel
为可写状态,则写入数据。
if (ctx.channel().isWritable()) {
ctx.channel().writeAndFlush(data);
}
2. Channel.writeAndFlush()
方法
// channel的writeAndFlush方法
public ChannelFuture writeAndFlush(Object msg) {
return pipeline.writeAndFlush(msg);
}
private void invokeWriteAndFlush(Object msg, ChannelPromise promise) {
if (invokeHandler()) {
invokeWrite0(msg, promise);
invokeFlush0();
} else {
writeAndFlush(msg, promise);
}
}
invokeWrite0(msg, promise)
会判断高水位线并设置不可写状态。最终调用HeadContext#write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
方法,该方法执行unsafe.write(msg, promise)
如下。
public final void write(Object msg, ChannelPromise promise) {
assertEventLoop();
ChannelOutboundBuffer outboundBuffer = this.outboundBuffer;
if (outboundBuffer == null) {
safeSetFailure(promise, newClosedChannelException(initialCloseCause));
ReferenceCountUtil.release(msg);
return;
}
int size;
try {
msg = filterOutboundMessage(msg);
size = pipeline.estimatorHandle().size(msg);
if (size < 0) {
size = 0;
}
} catch (Throwable t) {
safeSetFailure(promise, t);
ReferenceCountUtil.release(msg);
return;
}
outboundBuffer.addMessage(msg, size, promise);
}
outboundBuffer.addMessage(msg, size, promise)
添加消息到链表中, 如果超过高水位线则设置channel不可写状态。
public void addMessage(Object msg, int size, ChannelPromise promise) {
Entry entry = Entry.newInstance(msg, size, total(msg), promise);
if (tailEntry == null) {
flushedEntry = null;
} else {
Entry tail = tailEntry;
tail.next = entry;
}
tailEntry = entry;
if (unflushedEntry == null) {
unflushedEntry = entry;
}
incrementPendingOutboundBytes(entry.pendingSize, false);
}
// 如果超过高水位线则设置channel不可写状态。
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()) {
setUnwritable(invokeLater);
}
}
invokeFlush0()
会判断低水位线并设置可写状态。最终调用HeadContext#flush(ChannelHandlerContext ctx)
方法,该方法执行unsafe.flush()
,如果低于低水位线则设置channel可写状态,unsafe.flush
源码如下。
@Override
public final void flush() {
assertEventLoop();
ChannelOutboundBuffer outboundBuffer = this.outboundBuffer;
if (outboundBuffer == null) {
return;
}
outboundBuffer.addFlush();
flush0();
}
public void addFlush() {
Entry entry = unflushedEntry;
if (entry != null) {
if (flushedEntry == null) {
flushedEntry = entry;
}
do {
flushed ++;
if (!entry.promise.setUncancellable()) {
int pending = entry.cancel();
decrementPendingOutboundBytes(pending, false, true);
}
entry = entry.next;
} while (entry != null);
unflushedEntry = null;
}
}
private void decrementPendingOutboundBytes(long size, boolean invokeLater, boolean notifyWritability) {
if (size == 0) {
return;
}
long newWriteBufferSize = TOTAL_PENDING_SIZE_UPDATER.addAndGet(this, -size);
if (notifyWritability && newWriteBufferSize < channel.config().getWriteBufferLowWaterMark()) {
setWritable(invokeLater);
}
}