Netty 4 的 Channel 多了一个 autoread 参数, 它的用处是在让 channel 在触发某些事件以后(例如 channelActive, channelReadComplete)以后还会自动调用一次 read(), 代码:

DefaultChannelPipeline.java

    @Override
public ChannelPipeline fireChannelActive() {
head.fireChannelActive(); if (channel.config().isAutoRead()) {
channel.read();
} return this;
} ----------------------------------- @Override
public ChannelPipeline fireChannelReadComplete() {
head.fireChannelReadComplete();
if (channel.config().isAutoRead()) {
read();
}
return this;
}

另外一个很重要的作用是在触发某些事件(例如 socket 关闭)时, 在 NioEventloop 的 OP_READ 位为 1 时, 是否真正的去 channel 读取数据, 去 channel 读取数据的意义还包括可以更新 channel 的状态, 例如改变 active 状态等, 代码:

Eventloop.java

private static void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
final NioUnsafe unsafe = ch.unsafe();
if (!k.isValid()) {
// close the channel if the key is not valid anymore
unsafe.close(unsafe.voidPromise());
return;
} try {
int readyOps = k.readyOps();
// Also check for readOps of 0 to workaround possible JDK bug which may otherwise lead
// to a spin loop
if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
unsafe.read();
if (!ch.isOpen()) {
// Connection already closed - no need to handle write.
return;
}
}
if ((readyOps & SelectionKey.OP_WRITE) != 0) {
// Call forceFlush which will also take care of clear the OP_WRITE once there is nothing left to write
ch.unsafe().forceFlush();
}
if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
// remove OP_CONNECT as otherwise Selector.select(..) will always return without blocking
// See https://github.com/netty/netty/issues/924
int ops = k.interestOps();
ops &= ~SelectionKey.OP_CONNECT;
k.interestOps(ops); unsafe.finishConnect();
}
} catch (CancelledKeyException e) {
unsafe.close(unsafe.voidPromise());
}
}

AbstractNioByteChannel.java (unsafe.read())

public void read() {
final ChannelConfig config = config();
// 判断是否是 autoread, 如果不是直接移除 opRead 标志位返回
if (!config.isAutoRead() && !isReadPending()) {
// ChannelConfig.setAutoRead(false) was called in the meantime
removeReadOp();
return;
} final ChannelPipeline pipeline = pipeline();
final ByteBufAllocator allocator = config.getAllocator();
final int maxMessagesPerRead = config.getMaxMessagesPerRead();
RecvByteBufAllocator.Handle allocHandle = this.allocHandle;
if (allocHandle == null) {
this.allocHandle = allocHandle = config.getRecvByteBufAllocator().newHandle();
} ByteBuf byteBuf = null;
int messages = 0;
boolean close = false;
try {
int totalReadAmount = 0;
boolean readPendingReset = false;
do {
byteBuf = allocHandle.allocate(allocator);
int writable = byteBuf.writableBytes();
// 这里会到 channel 中 read 一次, 如果返回 -1, 则表示 channel 关闭
// 假如说 autoread 为 false, 则在 socket close 时永远不会进入这里, 从而改变 channel 的 active 状态
int localReadAmount = doReadBytes(byteBuf);
if (localReadAmount <= 0) {
// not was read release the buffer
byteBuf.release();
close = localReadAmount < 0;
break;
}
if (!readPendingReset) {
readPendingReset = true;
setReadPending(false);
}
pipeline.fireChannelRead(byteBuf);
byteBuf = null; if (totalReadAmount >= Integer.MAX_VALUE - localReadAmount) {
// Avoid overflow.
totalReadAmount = Integer.MAX_VALUE;
break;
} totalReadAmount += localReadAmount; // stop reading
if (!config.isAutoRead()) {
break;
} if (localReadAmount < writable) {
// Read less than what the buffer can hold,
// which might mean we drained the recv buffer completely.
break;
}
} while (++ messages < maxMessagesPerRead); pipeline.fireChannelReadComplete();
allocHandle.record(totalReadAmount);
// 关闭 channel, 并改变 channel active 状态
if (close) {
closeOnRead(pipeline);
close = false;
}
} catch (Throwable t) {
handleReadException(pipeline, byteBuf, t, close);
} finally {
// Check if there is a readPending which was not processed yet.
// This could be for two reasons:
// * The user called Channel.read() or ChannelHandlerContext.read() in channelRead(...) method
// * The user called Channel.read() or ChannelHandlerContext.read() in channelReadComplete(...) method
//
// See https://github.com/netty/netty/issues/2254
if (!config.isAutoRead() && !isReadPending()) {
removeReadOp();
}
}
}
}

关于 Netty Channel 的 Autoread的更多相关文章

  1. SparkStreaming+Flume出现ERROR ReceiverTracker: Deregistered receiver for stream 0: Error starting receiver 0 - org.jboss.netty.channel.ChannelException

    文章发自http://www.cnblogs.com/hark0623/p/4204104.html ,转载请注明 我发现太多太多的坑要趟了… 向yarn提交sparkstreaming了,提交脚本如 ...

  2. android netty5.0 编译时 java.lang.NoClassDefFoundError: io.netty.channel.nio.NioEventLoopGroup

    android netty5.0 编译时 java.lang.NoClassDefFoundError: io.netty.channel.nio.NioEventLoopGroup 复制netty包 ...

  3. netty-websocket-spring-boot-starter关闭报错 io/netty/channel/AbstractChannel$AbstractUnsafe io/netty/util/concurrent/GlobalEventExecutor

    报错 java.lang.NoClassDefFoundError: io/netty/channel/AbstractChannel$AbstractUnsafe$ at io.netty.chan ...

  4. Netty Channel 接口名词理解

    1.Channel channel 是负责数据读,写的对象,有点类似于老的io里面的stream.它和stream的区别,channel是双向的,既可以write 也可以read,而stream要分o ...

  5. netty源码解解析(4.0)-3 Channel的抽象实现

    AbstractChannel和AbstractUnsafe抽象类 io.netty.channel.AbstractChannel 从本章开始,会有大量的篇幅涉及到代码分析.为了能够清晰简洁的地说明 ...

  6. Netty那点事: 概述, Netty中的buffer, Channel与Pipeline

    Netty那点事(一)概述 Netty和Mina是Java世界非常知名的通讯框架.它们都出自同一个作者,Mina诞生略早,属于Apache基金会,而Netty开始在Jboss名下,后来出来自立门户ne ...

  7. [编织消息框架][netty源码分析]8 Channel 实现类NioSocketChannel职责与实现

    Unsafe是托委访问socket,那么Channel是直接提供给开发者使用的 Channel 主要有两个实现 NioServerSocketChannel同NioSocketChannel 致于其它 ...

  8. netty源码解解析(4.0)-14 Channel NIO实现:读取数据

     本章分析Nio Channel的数据读取功能的实现. Channel读取数据需要Channel和ChannelHandler配合使用,netty设计数据读取功能包括三个要素:Channel, Eve ...

  9. netty源码解解析(4.0)-15 Channel NIO实现:写数据

    写数据是NIO Channel实现的另一个比较复杂的功能.每一个channel都有一个outboundBuffer,这是一个输出缓冲区.当调用channel的write方法写数据时,这个数据被一系列C ...

随机推荐

  1. MVC之路由规则 (自定义,约束,debug)

    自定义路由规则的要求,小范围写在前,大范围写在后.路由规则可以注册多条,路由规则的名称不能重复路由规则有顺序,并且按照顺序进行匹配,建议小范围写在前,大范围写在后.路由规则可以设置约束 即正则表达式路 ...

  2. 15,SFDC 管理员篇 - 变更和部署

    Setup | Deploy | Sandbox 通过在Production上建立Dev .Test 两套环境来   Sandbox 有四种类型 Developer Sandbox & Dev ...

  3. log4j输出模板

    log4j.rootLogger=DEBUG, A1,A2 log4j.appender.A1.MaxFileSize=1kb#10个备份 log4j.appender.A1.MaxBackupInd ...

  4. C语言隐形密码输入

    今天费了老大的劲,终于做出来了!虽然简单,但也是自己的心血,分享一下! #include<stdio.h> #include<conio.h> int main(){ char ...

  5. PHP中使用cURL实现Get和Post请求的方法

    1.cURL介绍  cURL 是一个利用URL语法规定来传输文件和数据的工具,支持很多协议,如HTTP.FTP.TELNET等.最爽的是,PHP也支持 cURL 库.本文将介绍 cURL 的一些高级特 ...

  6. UICollectionReusableView 使用时的一些问题

    在使用UICollectionView 时, 设置分区头时, - (UICollectionReusableView *)collectionView:(UICollectionView *)coll ...

  7. 手动部署servlet

    1.编写servlet,在tomcat\webapps目录下新建文件Test,Test目录如下 Test | classes   web.xml | test01 | Servletfirst.jav ...

  8. Nvelocity用法

    NVelocity用法 NVelocity是一个基于.NET的模板引擎(template engine).它允许任何人仅仅简单的使用模板语言(template language)来引用由.NET代码定 ...

  9. 调用SAP函数创建寄售退货订单的时候报错:业务对象 BUS2032 是销售订单,销售凭证类别 H 是退货。

    RE.KR订单类型用BAPI_CUSTOMERRETURN_CREATE 其他用BAPI_SALESORDER_CREATEFROMDAT2

  10. 初学c# -- 学习笔记(八)

    RichTextBox我服了,背景透明.宽度高度自适应.图片背景透明.gif动画等等都tm实现困难无比,搞来搞去,就最后一题做不出来了: RichTextBox不管什么背景,透明背景也好,图片背景也罢 ...