create NioEventLoopGroup Instance

一、NioServerSocketChannel init

note:Initializing ChannelConfig creates a WriteBufferWaterMark instance,Default low 32k,high 64k
  作用: 防止ChannelOutboundBuffer 太大最终导致内存溢出,达到 High water值,
  会传播ChannelHandler 的 channelWritabilityChanged method,但是依旧能 write to buffer
  需要依据ChannelOutboundBuffer.isWritable 方法判断是否继续 write 处理.
  
  方案:after write to buffer,调用 ChannelOutboundBuffer,isWritable 方法是否可写,不可写时候,
  调用Channel config AutoRead 置为false,停止从Socket接收缓冲区读取到应用缓冲区
  (利用Tcp协议栈的滑动窗口做流控),监听ChannelHandler.channelWritabilityChanged 方法处理是否
  恢复AutoRead:true

二、NioServerSocketChannel performs

register0 method code int the AbstractChannel class:

private void register0(ChannelPromise promise) {
try {
// check
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
doRegister();//Selector register ServerSocketChannel
neverRegistered = false;
registered = true; // 传播 ChannelHandler 的 handlerAdded 方法(先执行 initChannel 方法)
// 之前在ServerBootstrap 类中定义的init 方法里将会触发ChannelInitializer 的执行
// performs complete, remove current ChannelHandler
pipeline.invokeHandlerAddedIfNeeded(); safeSetSuccess(promise);//如果启用listener,callBacks Results //传播 channelHandler 的 channelRegistered 方法
pipeline.fireChannelRegistered(); // 是否传播 ChannelHandler 的 channelActive 方法
if (isActive()) {
if (firstRegistration) {
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {//默认AutoRead:true(是否从Socket接收缓冲区读取数据)
beginRead();
}
}
} catch (Throwable t) {
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}

note:sun Jdk的Selector选择是依据 OS 来挑选 select、poll、epoll.


三、ChannelPipeline, Channel, ChannelHandler 和 ChannelHandlerContext 的关系

.Channel 绑定到 ChannelPipeline
.ChannelPipeline 绑定到 包含 ChannelHandler 的 Channel
.ChannelHandler
.当添加 ChannelHandler 到 ChannelPipeline 时,ChannelHandlerContext 被创建

四、Client Connection to Server



note:传播之前添加的ServerBootstrapAcceptor(ChannelHandler) 的 channelRead 方法

note:ParentDefaultChannelPipeline -> NioServerSocketChannel
SubDefaultChannelPipeline -> NioSocketChannel(a TcpConnection map a NioSocketChannel)
流程和NioServerSocketChannel一致,对Multi NioScoketChannel采用分治思想,多线程去承担(IO Read/Write),
利用multi core cpu.

Core Code in the ServerBootstrap.ServerBootstrapAcceptor Class: 

public void channelRead(ChannelHandlerContext ctx, Object msg) {
final Channel child = (Channel) msg;//Converted to NioSockerChannel child.pipeline().addLast(childHandler);//Add Application setting childHandler //添加Application 配置的相关属性和选项
setChannelOptions(child, childOptions, logger); for (Entry<AttributeKey<?>, Object> e: childAttrs) {
child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
} //切换NioSocketChannel 到其他线程的Scheduling和Register
try {
childGroup.register(child).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {//操作结果失败
forceClose(child, future.cause());
}
}
});
} catch (Throwable t) {
forceClose(child, t);
}
}

五、Client transmits data to the Server

Core Code in the AbstractNioByteChannel.NioByteUnsafe Class:

public final void read() {
final ChannelConfig config = config();//获取NioSocketChannel 配置
//检查是否可读
if (shouldBreakReadReady(config)) {
clearReadPending();
return;
}
//接收缓存区分配器
final ChannelPipeline pipeline = pipeline();
final ByteBufAllocator allocator = config.getAllocator();
final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle();
allocHandle.reset(config);//重置 ByteBuf byteBuf = null;
boolean close = false;
try {
  //NioSocketChannel配置(AutoRead)是否可读,最大读取次数范围内是否读取数据流完毕
do {
byteBuf = allocHandle.allocate(allocator);//分配byteBuf
allocHandle.lastBytesRead(doReadBytes(byteBuf));//读取数据流
if (allocHandle.lastBytesRead() <= ) {//是否读取完毕
byteBuf.release();//释放资源
byteBuf = null;
close = allocHandle.lastBytesRead() < ;
if (close) {
readPending = false;
}
break;
} allocHandle.incMessagesRead();//递增一次读取次数
readPending = false;
pipeline.fireChannelRead(byteBuf);//Callbacks channelRead ChannelHandler
byteBuf = null;
} while (allocHandle.continueReading()); allocHandle.readComplete();
pipeline.fireChannelReadComplete();//Callbacks channelReadComplete ChannelHandler if (close) {
closeOnRead(pipeline);
}
}
...
}
}
 
Flow:
I/O Request
Channel
|
+---------------------------------------------------+---------------+
| ChannelPipeline | |
| \|/ |
| +---------------------+ +-----------+----------+ |
| | Inbound Handler N | | Outbound Handler | |
| +----------+----------+ +-----------+----------+ |
| /|\ | |
| | \|/ |
| +----------+----------+ +-----------+----------+ |
| | Inbound Handler N- | | Outbound Handler | |
| +----------+----------+ +-----------+----------+ |
| /|\ . |
| . . |
| ChannelHandlerContext.fireIN_EVT() ChannelHandlerContext.OUT_EVT()|
| [ method call] [method call] |
| . . |
| . \|/ |
| +----------+----------+ +-----------+----------+ |
| | Inbound Handler | | Outbound Handler M- | |
| +----------+----------+ +-----------+----------+ |
| /|\ | |
| | \|/ |
| +----------+----------+ +-----------+----------+ |
| | Inbound Handler | | Outbound Handler M | |
| +----------+----------+ +-----------+----------+ |
| /|\ | |
+---------------+-----------------------------------+---------------+
| \|/
+---------------+-----------------------------------+---------------+
| | | |
| [ Socket.read() ] [ Socket.write() ] |
| |
+-------------------------------------------------------------------+ writeAndFlush流程:
Application --write--> ChannelOutboundBuffer --flush--> Socket发送缓冲区

六、Netty UDP Server is Single Thread Mode

note:不能阻塞IO线程,业务依靠业务线程池处理,否则Socket接收缓冲区溢出,会造成接收数据丢失,
数据可靠性问题,服务端设计方向利用 listen multi Network Interface 去处理,利用资源

netty 服务器端流程调度Flow笔记的更多相关文章

  1. Netty源码分析第1章(Netty启动流程)---->第3节: 服务端channel初始化

    Netty源码分析第一章:Netty启动流程   第三节:服务端channel初始化 回顾上一小节的initAndRegister()方法: final ChannelFuture initAndRe ...

  2. Netty源码分析第1章(Netty启动流程)---->第4节: 注册多路复用

    Netty源码分析第一章:Netty启动流程   第四节:注册多路复用 回顾下以上的小节, 我们知道了channel的的创建和初始化过程, 那么channel是如何注册到selector中的呢?我们继 ...

  3. 题目:vbs批量开通工具,实现vbs开通的ux设计和流程调度

    题目:vbs批量开通工具,实现vbs开通的ux设计和流程调度 需求点:支持开通前检查(检查失败不允许开站),开通过程监控,开通后业务检验,失败后重新开通,支持部分站点开通(比如用户导入的模板中有10个 ...

  4. Netty启动流程剖析

    编者注:Netty是Java领域有名的开源网络库,特点是高性能和高扩展性,因此很多流行的框架都是基于它来构建的,比如我们熟知的Dubbo.Rocketmq.Hadoop等,针对高性能RPC,一般都是基 ...

  5. Netty执行流程分析与重要组件介绍

    一.环境搭建 创建工程,引入Netty依赖 二.基于Netty的请求响应Demo 1.TestHttpServerHandle  处理器.读取客户端发送过来的请求,并且向客户端返回hello worl ...

  6. Spring Web Flow 笔记

    在Spring 中配置 Web Flow <?xml version="1.0" encoding="UTF-8"?> <beans xmln ...

  7. openVswitch(OVS)源代码分析之工作流程(flow流表查询)

    原文链接: openVswitch(OVS)源代码分析之工作流程(flow流表查询)

  8. Netty writeAndFlush() 流程与异步

    Netty writeAndFlush()方法分为两步, 先 write 再 flush @Override public ChannelFuture writeAndFlush(Object msg ...

  9. Netty源码分析第1章(Netty启动流程)---->第1节: 服务端初始化

    Netty源码分析第一章:  Server启动流程 概述: 本章主要讲解server启动的关键步骤, 读者只需要了解server启动的大概逻辑, 知道关键的步骤在哪个类执行即可, 并不需要了解每一步的 ...

随机推荐

  1. Lodop提示BarCode Type(ena13)Invalid!

    前段时间遇到过一个奇怪的问题,就是代码里本身都是ENA13大写,却提示条码类型无效,而且进入打印设计后,选中打印项,条码类型变成了code39,但是实际是还有条码类型参数都是正确的,代码看上去没有问题 ...

  2. [模板] 2-SAT 问题

    简介 2-SAT (2-satisfiability) 问题形如: 给定一些变量 \(x_i \in \{true, false\}\); 给定一些一元/二元约束条件, 如 \(x_i \land \ ...

  3. Oracle查询所有表的字段明细

    SELECT USER_TAB_COLS.TABLE_NAME as 表名, UTC.COMMENTS as 表中文名, USER_TAB_COLS.COLUMN_ID as 列序号, USER_TA ...

  4. 一道php笔试题

    原文地址: http://www.walu.cc/php/a-bishiti.md 问题: 请找出下面代码中的问题,修复并优化. <?php //批量注册用户,每次>100个. //注册新 ...

  5. P1536 村村通

    原题链接 https://www.luogu.org/problemnew/show/P1536 昨天刚学的并查集,今天正好练习一下,于是就找到了这个题 看起来好像很简单,尤其是你明白了思路之后,完全 ...

  6. 微擎$_W['uniacid']无法获取

    原因: 微擎非系统级别管理员(不是商户管理员),必须要https才能取到值

  7. 【js】前端 js/jquery 常用代码和实践

    1.获取某天后几天的日期 //d为传入的日期 days为d后面的几天function getAfterDate(d,days){ var dd = new Date(d); dd.setDate(dd ...

  8. pre的内容自动转行

    使pre的内容自动换行(转) <pre> 元素可定义预格式化的文本.被包围在 pre 元素中的文本通常会保留空格和换行符.而文本也会呈现为等宽字体. <pre> 标签的一个常见 ...

  9. Python 防止mysql 注入的两种方式

    Python防止sql注入一般有两种方法 1.escape_string   MySQLdb.escape_string(param) 注意:如果报错出现 'ascii' codec can't en ...

  10. Git如何合并一个已经在GitHub上提交但没有合并的Pull Request请求

    步骤 进入Git仓库,执行curl -L https://github.com/<USER>/<REPO>/pull/<NO>.patch | git am