没有合适的资源?快使用搜索试试~ 我知道了~
聊聊 Netty 那些事儿之 Reactor 在 Netty 中的实现(创建篇).doc
1.该资源内容由用户上传,如若侵权请联系客服进行举报
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
版权申诉
0 下载量 129 浏览量
2022-07-08
15:42:21
上传
评论
收藏 3.27MB DOC 举报
温馨提示
试读
42页
聊聊 Netty 那些事儿之 Reactor 在 Netty 中的实现(创建篇).doc
资源推荐
资源详情
资源评论
聊聊 Netty 那些事儿之 Reactor 在 Netty 中的实现(创建篇)
本文介绍了 Netty 对各种 IO 模型的支持以及如何轻松切换各种 IO 模型。还花了
大量的篇幅介绍 Netty 服务端的核心引擎主从 Reactor 线程组的创建过程。在这个过程中,
我们还提到了 Netty 对各种细节进行的优化,展现了 Netty 对性能极致的追求。
本系列 Netty 源码解析文章基于 4.1.56.Final 版本
在上篇文章《聊聊 Netty 那些事儿之从内核角度看 IO 模型》中我们花了大量的篇幅来从
内核角度详细讲述了五种 IO 模型的演进过程以及 ReactorIO 线程模型的底层基石 IO 多路
复用技术在内核中的实现原理。
最后我们引出了 netty 中使用的主从 Reactor IO 线程模型。
通过上篇文章的介绍,我们已经清楚了在 IO 调用的过程中内核帮我们搞了哪些事情,那
么俗话说的好内核领进门,修行在 netty,netty 在用户空间又帮我们搞了哪些事情?
那么从本文开始,笔者将从源码角度来带大家看下上图中的 Reactor IO 线程模型在 Netty
中是如何实现的。
本文作为 Reactor 在 Netty 中实现系列文章中的开篇文章,笔者先来为大家介绍 Reactor 的
骨架是如何创建出来的。
在上篇文章中我们提到 Netty 采用的是主从 Reactor 多线程的模型,但是它在实现上又与
Doug Lea 在 Scalable IO in Java 论文中提到的经典主从 Reactor 多线程模型有所差异。
Netty 中的 Reactor 是以 Group 的形式出现的,主从 Reactor 在 Netty 中就是主从 Reactor
组,每个 Reactor Group 中会有多个 Reactor 用来执行具体的 IO 任务。当然在 netty 中 Reactor
不只用来执行 IO 任务,这个我们后面再说。
Main Reactor Group 中的 Reactor 数量取决于服务端要监听的端口个数,通常我们的服务
端程序只会监听一个端口,所以 Main Reactor Group 只会有一个 Main Reactor 线程来处理最
重要的事情:绑定端口地址,接收客户端连接,为客户端创建对应的 SocketChannel,将客
户端 SocketChannel 分配给一个固定的 Sub Reactor。也就是上篇文章笔者为大家举的例子,
饭店最重要的工作就是先把客人迎接进来。“我家大门常打开,开放怀抱等你,拥抱过就有
了默契你会爱上这里......”
Sub Reactor Group 里有多个 Reactor 线程,Reactor 线程的个数可以通过系统参数 -D
io.netty.eventLoopThreads 指定。默认的 Reactor 的个数为 CPU 核数 * 2。Sub Reactor 线程主
要用来轮询客户端 SocketChannel 上的 IO 就绪事件,处理 IO 就绪事件,执行异步任务。 Sub
Reactor Group 做的事情就是上篇饭店例子中服务员的工作,客人进来了要为客人分配座位,
端茶送水,做菜上菜。“不管远近都是客人,请不用客气,相约好了在一起,我们欢迎
您......”
一个客户端 SocketChannel 只能分配给一个固定的 Sub Reactor。一个 Sub Reactor 负责处
理多个客户端 SocketChannel,这样可以将服务端承载的全量客户端连接分摊到多个 Sub
Reactor 中处理,同时也能保证客户端 SocketChannel 上的 IO 处理的线程安全性。
由于文章篇幅的关系,作为 Reactor 在 netty 中实现的第一篇我们主要来介绍主从 Reactor
Group 的创建流程,骨架脉络先搭好。
下面我们来看一段 Netty 服务端代码的编写模板,从代码模板的流程中我们来解析下主从
Reactor 的创建流程以及在这个过程中所涉及到的 Netty 核心类。
Netty 服务端代码模板
/**
* Echoes back any received data from a client.
*/
public final class EchoServer {
static final int PORT = Integer.parseInt(System.getProperty(“port”, “8007”));
public static void main(String[] args) throws Exception {
// Configure the server.
//创建主从 Reactor 线程组
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
final EchoServerHandler serverHandler = new EchoServerHandler();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)//配置主从 Reactor
.channel(NioServerSocketChannel.class)//配置主 Reactor 中的 channel 类型
.option(ChannelOption.SO_BACKLOG, 100)//设置主 Reactor 中 channel 的 option
选项
.handler(new LoggingHandler(LogLevel.INFO))// 设 置 主 Reactor 中
Channel->pipline->handler
.childHandler(new ChannelInitializer() {//设置从 Reactor 中注册 channel 的 pipeline
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
//p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(serverHandler);
}
});
// Start the server. 绑定端口启动服务,开始监听 accept 事件
ChannelFuture f = b.bind(PORT).sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
} finally {
// Shut down all event loops to terminate all threads.
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
首 先 我 们 要 创 建 Netty 最 核 心 的 部 分 -> 创 建 主 从 Reactor Group , 在 Netty 中
EventLoopGroup 就是 Reactor Group 的实现类。对应的 EventLoop 就是 Reactor 的实现类。
//创建主从 Reactor 线程组
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
创建用于 IO 处理的 ChannelHandler,实现相应 IO 事件的回调函数,编写对应的 IO 处理
逻辑。注意这里只是简单示例哈,详细的 IO 事件处理,笔者会单独开一篇文章专门讲述。
final EchoServerHandler serverHandler = new EchoServerHandler();
/**
* Handler implementation for the echo server.
*/
@Sharable
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
................省略 IO 处理逻辑................
ctx.write(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised.
cause.printStackTrace();
ctx.close();
}
}
创建 ServerBootstrap Netty 服务端启动类,并在启动类中配置启动 Netty 服务端所需要的
一些必备信息。
通 过 serverBootstrap.group(bossGroup, workerGroup) 为 Netty 服 务 端 配 置 主 从 Reactor
Group 实例。
通 过 serverBootstrap.channel(NioServerSocketChannel.class) 配 置 Netty 服 务 端 的
ServerSocketChannel 用 于 绑 定 端 口 地 址 以 及 创 建 客 户 端 SocketChannel 。 Netty 中 的
NioServerSocketChannel.class 就是对 JDK NIO 中 ServerSocketChannel 的封装。而用于表示
客户端连接的 NioSocketChannel 是对 JDK NIO SocketChannel 封装。
在上篇文章介绍 Socket 内核结构小节中我们提到,在编写服务端网络程序时,我们首先
要创建一个 Socket 用于 listen 和 bind 端口地址,我们把这个叫做监听 Socket,这里对应的就
是 NioServerSocketChannel.class。当客户端连接完成三次握手,系统调用 accept 函数会基于
监听 Socket 创建出来一个新的 Socket 专门用于与客户端之间的网络通信我们称为客户端连
接 Socket,这里对应的就是 NioSocketChannel.class
serverBootstrap.option(ChannelOption.SO_BACKLOG, 100) 设 置 服 务 端
ServerSocketChannel 中的 SocketOption。关于 SocketOption 的选项我们后边的文章再聊,本
文主要聚焦在 Netty Main Reactor Group 的创建及工作流程。
serverBootstrap.handler(....) 设 置 服 务 端 NioServerSocketChannel 中 对 应 Pipieline 中 的
ChannelHandler。
剩余41页未读,继续阅读
资源评论
书博教育
- 粉丝: 1
- 资源: 2836
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功