Unsafe是托委访问socket,那么Channel是直接提供给开发者使用的

Channel 主要有两个实现 NioServerSocketChannel同NioSocketChannel 致于其它不常用不在研究范围内

NioServerSocketChannel 是给server用的,程序由始至终只有一个NioServerSocketChannel

NioSocketChannel 是给客户端用的,每个连接生成一个NioSocketChannel 对象

NioSocketChannel同NioSocketChannel的继承关系

NioSocketChannel -> AbstractNioByteChannel -> AbstractNioChannel -> AbstractChannel

NioServerSocketChannel -> AbstractNioMessageChannel-> AbstractNioChannel -> AbstractChannel

小提示:如果看文字不够直观可以在eclipse里按快捷键 选择类 ctrl+t

channel有unsafe相应的实现类,反之亦是。其实功能是很简单的,划分太多对象目的是对某部分功能重用,有时也可能因过渡设计造成

对于channel我们主要分析 I/O read/write操作

public class NioServerSocketChannel extends AbstractNioMessageChannel implements io.netty.channel.socket.ServerSocketChannel {
private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider(); //构造时就绑定SelectorProvider,然后注册OP_ACCEPT
public NioServerSocketChannel() {
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
} public NioServerSocketChannel(ServerSocketChannel channel) {
super(null, channel, SelectionKey.OP_ACCEPT);
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
} /**
server read操作对应的为readMessages
参数是个数组,是C语言书写风格,如果需要返回多种类型数据,那么传个对象进去外部就能获取到
这里比较重要,当有接收到socket时,生成NioSocketChannel对象
   读者如果还有印象的话在讲NioEventLoop 有提示netty read 操作是不分 OP_ACCEPT、OP_READ的,可以在这方法打上断点观察
*/
@Override
protected int doReadMessages(List<Object> buf) throws Exception {
SocketChannel ch = javaChannel().accept();
try {
if (ch != null) {
//生成NioSocketChannel
buf.add(new NioSocketChannel(this, ch));
return 1;
}
} catch (Throwable t) {
ch.close();
} return 0;
}
//server 应该没有write操作才对,因为server是一对多处理,不知道发给那一个clinet
@Override
protected void doWrite(ChannelOutboundBuffer in) throws Exception {}
}
public class NioSocketChannel extends AbstractNioByteChannel implements io.netty.channel.socket.SocketChannel {
public NioSocketChannel(Channel parent, SocketChannel socket) {
super(parent, socket);
config = new NioSocketChannelConfig(this, socket.socket());
} //////////////////////////////这部分是unsafe底层调用上层的实现//////////////////////////////////////////////
@Override
protected int doReadBytes(ByteBuf byteBuf) throws Exception {
final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();
//这里设置byteBuf写入数据坐标
allocHandle.attemptedBytesRead(byteBuf.writableBytes());
return byteBuf.writeBytes(javaChannel(), allocHandle.attemptedBytesRead());
} @Override
protected int doWriteBytes(ByteBuf buf) throws Exception {
final int expectedWrittenBytes = buf.readableBytes();
return buf.readBytes(javaChannel(), expectedWrittenBytes);
} @Override
protected void doWrite(ChannelOutboundBuffer in) throws Exception {
for (;;) {
int size = in.size();
//没有数据退出
if (size == 0) {
clearOpWrite();
break;
} long writtenBytes = 0; //记录写数据size
boolean done = false; //是否完成
boolean setOpWrite = false; ByteBuffer[] nioBuffers = in.nioBuffers();
int nioBufferCnt = in.nioBufferCount();
long expectedWrittenBytes = in.nioBufferSize();
SocketChannel ch = javaChannel(); //这里有三种分支处理
//如果没有ByteBuffer 有可能只发送几个byte
//1跟default逻辑其实是一样的
switch (nioBufferCnt) {
case 0:
//调用父类 AbstractNioByteChannel doWrite,逻辑基本相同,不同的是AbstractNioByteChannel处理的是byte 实现调用的是 doWriteBytes(ByteBuf buf)方法。。。
super.doWrite(in);
return;
case 1:
//这里只循环16次,可以看出是复制下面代码的哈。。。
ByteBuffer nioBuffer = nioBuffers[0];
for (int i = config().getWriteSpinCount() - 1; i >= 0; i --) {
final int localWrittenBytes = ch.write(nioBuffer);
if (localWrittenBytes == 0) {
setOpWrite = true;
break;
}
expectedWrittenBytes -= localWrittenBytes;
writtenBytes += localWrittenBytes;
if (expectedWrittenBytes == 0) {
done = true;
break;
}
}
break;
default:
//多个ByteBuffer时跟上面逻辑一样
for (int i = config().getWriteSpinCount() - 1; i >= 0; i --) {
final long localWrittenBytes = ch.write(nioBuffers, 0, nioBufferCnt);
if (localWrittenBytes == 0) {
setOpWrite = true;
break;
}
expectedWrittenBytes -= localWrittenBytes;
writtenBytes += localWrittenBytes;
if (expectedWrittenBytes == 0) {
done = true;
break;
}
}
break;
} // Release the fully written buffers, and update the indexes of the partially written buffer.
in.removeBytes(writtenBytes); if (!done) {
// Did not write all buffers completely.
incompleteWrite(setOpWrite);
break;
}
}
}
}
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
//生成NioSocketChannel时就绑定 unsafe pipeline
protected AbstractChannel(Channel parent) {
this.parent = parent;
id = newId();
unsafe = newUnsafe();
pipeline = newChannelPipeline();
}
}
protected abstract class AbstractUnsafe implements Unsafe {
private void register0(ChannelPromise promise) {
try {
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
doRegister();
// doRegister 是调用 AbstractNioChannel selectionKey = javaChannel().register(eventLoop().selector, 0, this);
neverRegistered = false;
registered = true;
//这里是添加 Handler 每个Handler会生成一个Context
pipeline.invokeHandlerAddedIfNeeded(); safeSetSuccess(promise);
//通知Handler Registered
pipeline.fireChannelRegistered();
if (isActive()) {
if (firstRegistration) {
//通知Handler Active
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
beginRead();
}
}
} catch (Throwable t) {
//.......
}
}
}

小结:看似很复杂的Channel实现其实没想象难,大多数读写坐标记录交给ByteBuf处理掉了

1.server每个client连接转换成NioSocketChannel对象

2.构建NioSocketChannel时就已经生成 unsafe、pipeline

[编织消息框架][netty源码分析]8 Channel 实现类NioSocketChannel职责与实现的更多相关文章

  1. [编织消息框架][netty源码分析]6 ChannelPipeline 实现类DefaultChannelPipeline职责与实现

    ChannelPipeline 负责channel数据进出处理,如数据编解码等.采用拦截思想设计,经过A handler处理后接着交给next handler ChannelPipeline 并不是直 ...

  2. [编织消息框架][netty源码分析]3 EventLoop 实现类SingleThreadEventLoop职责与实现

    eventLoop是基于事件系统机制,主要技术由线程池同队列组成,是由生产/消费者模型设计,那么先搞清楚谁是生产者,消费者内容 SingleThreadEventLoop 实现 public abst ...

  3. [编织消息框架][netty源码分析]4 eventLoop 实现类NioEventLoop职责与实现

    NioEventLoop 是jdk nio多路处理实现同修复jdk nio的bug 1.NioEventLoop继承SingleThreadEventLoop 重用单线程处理 2.NioEventLo ...

  4. [编织消息框架][netty源码分析]11 ByteBuf 实现类UnpooledHeapByteBuf职责与实现

    每种ByteBuf都有相应的分配器ByteBufAllocator,类似工厂模式.我们先学习UnpooledHeapByteBuf与其对应的分配器UnpooledByteBufAllocator 如何 ...

  5. [编织消息框架][netty源码分析]5 eventLoop 实现类NioEventLoopGroup职责与实现

    分析NioEventLoopGroup最主有两个疑问 1.next work如何分配NioEventLoop 2.boss group 与child group 是如何协作运行的 从EventLoop ...

  6. [编织消息框架][netty源码分析]9 Promise 实现类DefaultPromise职责与实现

    netty Future是基于jdk Future扩展,以监听完成任务触发执行Promise是对Future修改任务数据DefaultPromise是重要的模板类,其它不同类型实现基本是一层简单的包装 ...

  7. [编织消息框架][netty源码分析]5 EventLoopGroup 实现类NioEventLoopGroup职责与实现

    分析NioEventLoopGroup最主有两个疑问 1.next work如何分配NioEventLoop 2.boss group 与child group 是如何协作运行的 从EventLoop ...

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

    Unsafe 是channel的内部接口,从书写跟命名上看是不公开给开发者使用的,直到最后实现NioSocketChannelUnsafe也没有公开出去 public interface Channe ...

  9. [编织消息框架][netty源码分析]13 ByteBuf 实现类CompositeByteBuf职责与实现

    public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements Iterable<ByteBuf ...

随机推荐

  1. hdu2819二分图匹配

    Given an N*N matrix with each entry equal to 0 or 1. You can swap any two rows or any two columns. C ...

  2. Android WebView导入HTML使Js生效的方法

    WebSettings ws = webview.getSettings(); ws.setJavaScriptEnabled(true);//加上这句 webview.loadDataWithBas ...

  3. 关于删除数组中重复元素的lintcode代码

    时间自由度为o(n),空间自由度为o(1); class Solution {public:    /**     * @param A: a list of integers     * @retu ...

  4. 如何通过 WebP 自适应方案减少图片资源大小

    前言 我们知道,理想的网页应该在 1 秒内打开,而在页面的整体大小中,图片往往是所占比例最大的一部分(大约占到 60% 以上,更多了解请点击),也可以参照如下图所示.优化图片不仅可以加快页面显示,还能 ...

  5. js:不是空字符串的空字符串引起的bug

    今天在用js的时候,使用了两段完全相同的代码,可是一个报错,一个好好的 代码如下: <script type="text/javascript">    console ...

  6. 学生成绩管理C语言版

    [标题]学生成绩管理的设计与实现 [开发语言]C语言 [概要设计]使用结构体存储学生的学号.姓名和成绩信息,实现对学生成绩类的基本操作:增加.删除.查询.排序 [测试数据]按提示输入5组正确的正确的数 ...

  7. 自己实现so加载器

    在进行安全研究中,我们需要经常使用ida等工具对app的so进行动态调试.这其中遇到的最大问题可能就是app加了反调试.反root等保护手段对应用运行环境进行检测,而这些手段往往是在我们附加进程之前就 ...

  8. C语言中,隐藏结构体的细节

    我们都知道,在C语言中,结构体中的字段都是可以访问的.或者说,在C++ 中,类和结构体的主要区别就是类中成员变量默认为private,而结构体中默认为public.结构体的这一个特性,导致结构体中封装 ...

  9. SparkMLlib学习分类算法之逻辑回归算法

    SparkMLlib学习分类算法之逻辑回归算法 (一),逻辑回归算法的概念(参考网址:http://blog.csdn.net/sinat_33761963/article/details/51693 ...

  10. 前端工程之node基础

    Node.exe是一个基于 Chrome V8 引擎的 JavaScript 运行环境. Nodejs定义了一个构造函数 Module,所有的模块(Node中一个文件即一个模块)都是 Module 的 ...