[编织消息框架][netty源码分析]8 Channel 实现类NioSocketChannel职责与实现
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职责与实现的更多相关文章
- [编织消息框架][netty源码分析]6 ChannelPipeline 实现类DefaultChannelPipeline职责与实现
ChannelPipeline 负责channel数据进出处理,如数据编解码等.采用拦截思想设计,经过A handler处理后接着交给next handler ChannelPipeline 并不是直 ...
- [编织消息框架][netty源码分析]3 EventLoop 实现类SingleThreadEventLoop职责与实现
eventLoop是基于事件系统机制,主要技术由线程池同队列组成,是由生产/消费者模型设计,那么先搞清楚谁是生产者,消费者内容 SingleThreadEventLoop 实现 public abst ...
- [编织消息框架][netty源码分析]4 eventLoop 实现类NioEventLoop职责与实现
NioEventLoop 是jdk nio多路处理实现同修复jdk nio的bug 1.NioEventLoop继承SingleThreadEventLoop 重用单线程处理 2.NioEventLo ...
- [编织消息框架][netty源码分析]11 ByteBuf 实现类UnpooledHeapByteBuf职责与实现
每种ByteBuf都有相应的分配器ByteBufAllocator,类似工厂模式.我们先学习UnpooledHeapByteBuf与其对应的分配器UnpooledByteBufAllocator 如何 ...
- [编织消息框架][netty源码分析]5 eventLoop 实现类NioEventLoopGroup职责与实现
分析NioEventLoopGroup最主有两个疑问 1.next work如何分配NioEventLoop 2.boss group 与child group 是如何协作运行的 从EventLoop ...
- [编织消息框架][netty源码分析]9 Promise 实现类DefaultPromise职责与实现
netty Future是基于jdk Future扩展,以监听完成任务触发执行Promise是对Future修改任务数据DefaultPromise是重要的模板类,其它不同类型实现基本是一层简单的包装 ...
- [编织消息框架][netty源码分析]5 EventLoopGroup 实现类NioEventLoopGroup职责与实现
分析NioEventLoopGroup最主有两个疑问 1.next work如何分配NioEventLoop 2.boss group 与child group 是如何协作运行的 从EventLoop ...
- [编织消息框架][netty源码分析]7 Unsafe 实现类NioSocketChannelUnsafe职责与实现
Unsafe 是channel的内部接口,从书写跟命名上看是不公开给开发者使用的,直到最后实现NioSocketChannelUnsafe也没有公开出去 public interface Channe ...
- [编织消息框架][netty源码分析]13 ByteBuf 实现类CompositeByteBuf职责与实现
public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements Iterable<ByteBuf ...
随机推荐
- 编写高质量的JavaScript代码(一)
欢迎大家关注腾讯云技术社区-博客园官方主页,我们将持续在博客园为大家推荐技术精品文章哦~ 2016年6月加入腾讯,目前在SNG社交网络质量部从事内部平台工具的研发.熟悉PHP.JS.CSS,喜欢弹吉他 ...
- Spring Session实现分布式session的简单示例
前面有用 tomcat-redis-session-manager来实现分布式session管理,但是它有一定的局限性,主要是跟tomcat绑定太紧了,这里改成用Spring Session来管理分布 ...
- HDU4712 Hamming Distance (随机化)
link:http://acm.hdu.edu.cn/showproblem.php?pid=4712 题意:给1e5个数字,输出这些数中,最小的海明码距离. 思路:距离的范围是0到20.而且每个数的 ...
- 基于webpack2.x的vue2.x的多页面站点
vue的多页面 依旧使用vue-cli来初始化我们的项目 然后修改主要目录结构如下: ├── build │ ├── build.js │ ├── check-versions.js │ ...
- miller_rabin算法检测生成大素数的RSA算法实现
import math from functools import reduce #用于合并字符 from os import urandom #系统随机的字符 import binascii # ...
- 用ArrayList(解决约瑟夫问题)
约瑟夫问题(Josephus problem)又称为约瑟夫斯置换,是一个出现在计算机科学和数学中的问题.在计算机编程的算法中,约瑟夫问题类似问题又称为约瑟夫环."丢手绢问题". 据 ...
- JAVA的节点流和处理流
节点流:可以从或向一个特定的地方(节点)读写数据.如FileReader. 处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写.如BufferedReader.处理流的构造方 ...
- makefile文件模板介绍
1 src : = $(shell ls *.c)2 objs : = $(patsubst %.c, %.o, $(src))3 test : $(objs)4 ...
- SSH协议(转载)
一. SSH是什么? SSH的全称是Secure Shell, 是一种"用来在不安全的网络上安全地运行网络服务的一种加密网络协议". 简单说,SSH是一种网络协议,用于计算机之间的 ...
- 【JAVAWEB学习笔记】15_request
HttpServletRequest 学习目标 案例一.完成用户注册 案例二.完成登录错误信息的回显 1.HttpServletRequest概述 我们在创建Servlet时会覆盖service()方 ...