关于 Netty Channel 的 Autoread
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的更多相关文章
- 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了,提交脚本如 ...
- android netty5.0 编译时 java.lang.NoClassDefFoundError: io.netty.channel.nio.NioEventLoopGroup
android netty5.0 编译时 java.lang.NoClassDefFoundError: io.netty.channel.nio.NioEventLoopGroup 复制netty包 ...
- 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 ...
- Netty Channel 接口名词理解
1.Channel channel 是负责数据读,写的对象,有点类似于老的io里面的stream.它和stream的区别,channel是双向的,既可以write 也可以read,而stream要分o ...
- netty源码解解析(4.0)-3 Channel的抽象实现
AbstractChannel和AbstractUnsafe抽象类 io.netty.channel.AbstractChannel 从本章开始,会有大量的篇幅涉及到代码分析.为了能够清晰简洁的地说明 ...
- Netty那点事: 概述, Netty中的buffer, Channel与Pipeline
Netty那点事(一)概述 Netty和Mina是Java世界非常知名的通讯框架.它们都出自同一个作者,Mina诞生略早,属于Apache基金会,而Netty开始在Jboss名下,后来出来自立门户ne ...
- [编织消息框架][netty源码分析]8 Channel 实现类NioSocketChannel职责与实现
Unsafe是托委访问socket,那么Channel是直接提供给开发者使用的 Channel 主要有两个实现 NioServerSocketChannel同NioSocketChannel 致于其它 ...
- netty源码解解析(4.0)-14 Channel NIO实现:读取数据
本章分析Nio Channel的数据读取功能的实现. Channel读取数据需要Channel和ChannelHandler配合使用,netty设计数据读取功能包括三个要素:Channel, Eve ...
- netty源码解解析(4.0)-15 Channel NIO实现:写数据
写数据是NIO Channel实现的另一个比较复杂的功能.每一个channel都有一个outboundBuffer,这是一个输出缓冲区.当调用channel的write方法写数据时,这个数据被一系列C ...
随机推荐
- 基于MFC的单文档,多文档,对话框应用程序
从类的角度区分: 基于对话框(3个类): CAboutDlg 程序名App 程序名Dlg 单文档(5个类): CAboutDlg CMainFrame 程序名App 程序名Doc 程序名View 多文 ...
- Sql Server 按行处理表数据思路
SqlServer的游标当超过1000行左右的时候效率极其低下. DECLARE @Company VARCHAR(12)='' SELECT TOP 1 @Company=CompanyID FRO ...
- Dalvik系列02 - 指令格式
简介 该文档描述了Dalvik 可执行文件和Dalvik 字节码的指令格式. 按照位的描述 格式描述表(见下文)的第一列表示个格式的位结构,它由一个或者多个由空格分开的“指令单元”构成,每个指令单元的 ...
- mac 笔记
---恢复内容开始--- /* 因为外出mac 办公的时候越来越多,有时候4g wifi 流量告急,不得不寻找破解之道. */ 安装port& aircreak-ng sudo port in ...
- callback转Promise
环境: nodejs - v6.2.0 const fs = require('fs'); let Promise = require('bluebird'); let readSync = fun ...
- leetCode 354. Russian Doll Envelopes
You have a number of envelopes with widths and heights given as a pair of integers (w, h). One envel ...
- SQL SERVER时间格式化
begin ) begin BEGIN try ),@i)+' '+convert(VARCHAR,getdate(),@i) END TRY BEGIN catch end catch end en ...
- PHP include 和 require 语句
在 PHP 中,您可以在服务器执行 PHP 文件之前在该文件中插入一个文件的内容. include 和 require 语句用于在执行流中插入写在其他文件中的有用的代码. include 和 requ ...
- Chrome浏览器Network面板http请求时间分析
Chrome浏览器开发者工具Network窗口下,可以查看下载各组件所需的具体时间 根据上表进行简要分析-- Stalled(阻塞) 浏览器对同一个主机域名的并发连接数有限制,因此如果当前的连接数已经 ...
- 利用 cookie 模拟网站登录
import urllib import urllib2 import cookielib filename = 'cookie.txt' \#声明一个MozillaCookieJar对象实例来保存c ...