Netty(三)Netty模型
1. Netty模型
Netty主要基于主从Reactor多线程模型做了一定的改进,其中主从Reactor多线程模型有多个Reactor。
简版图:
说明:
- BossGroup线程维护Selector,只关注Accept
- 当接收到Accept事件,获取到对应的SocketChannel,封装成NIOSocketChannel并注册到Worker线程(事件循环),并进行维护
- 当Worker线程监听到selector中通道发生自己感兴趣的事件后,就进行处理(就由handler),注意,handler已经加入到channel
Netty模型进阶版图:
详细版:
模型说明:
- Netty抽象出2组线程池:
- BossGroup:专门接受客户端的连接
- WorkerGroup:专门负责网络的读写
- BossGroup和WorkerGroup类型都是NioEventLoopGroup
- NioEventLoopGroup相当于一个事件循环组,这个组中含有多个事件循环,每一个事件循环是NioEventLoop
- NioEventLoop表示一个不断循环的执行处理任务的线程,每个NioEventLoop都有一个selector,用于监听绑定在其上的socket的网络通讯
- NioEventLoop可以有多个线程,即可以含有多个NioEventLoop
- 每个Boss NioEventLoop循环执行的步骤有3步:
- 轮询accept事件
- 处理accept事件,与client建立连接,生成NioSocketChannel,并将其注册到某个worker
- 处理任务队列的任务,即runAllTasks
- 每个Worker NIOEventLoop循环执行的步骤:
- 轮询read,write事件
- 处理I/O事件,即read,write事件,在对应NioSocketChannel处理
- 处理任务队列的任务,即runAllTasks
- 每个Worker NIOEventLoop处理业务时,会使用pipeline(管道),pipeline中包含了channel,即通过pipeline可以获取到对应channel,管道中维护了很多的处理器
2. Netty实现简单服务端与客户端交互
NettyServer.java
package com.tang.netty.simple; import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel; public class NettyServer { public static void main(String[] args) {
// 创建 BossGroup 和 WorkerGroup
// 1.创建 2 个线程组 boosGroup 和 workerGroup
// 2.bossGroup只是处理连接请求,真正与客户端的业务处理,会交给workerGroup
// 3.两个都是无限循环
// 4.bossGroup 和 workerGroup 含有的子线程(NioEventLoop)的个数,默认为实际 CPU 核数*2
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup(); // 创建服务器端的启动对象,配置参数
ServerBootstrap bootstrap = new ServerBootstrap(); // 使用链式编程来进行设置
bootstrap.group(bossGroup, workerGroup) // 设置2个线程组
.channel(NioServerSocketChannel.class) // 使用 NioServerSocketChannel 作为服务器通道的实现
.option(ChannelOption.SO_BACKLOG, 128) // 设置线程队列得到连接数
.childOption(ChannelOption.SO_KEEPALIVE, true) // 设置保持活动连接状态
.childHandler(new ChannelInitializer<SocketChannel>() { // 创建一个通道测试对象(匿名对象)
// 给pipeline 设置处理器
// 使用的自己实现的 NettyServerHandler
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new NettyServerHandler());
}
}); // 给我们 workerGroup 的 EventLoop 对应的管道设置处理器 System.out.println("....Server is ready..."); try {
// 绑定一个端口并且同步,生成了一个 ChannelFuture 对象
// 启动服务器
ChannelFuture cf = bootstrap.bind(6668).sync(); // 对关闭通道进行监听
cf.channel().closeFuture().sync(); } catch (InterruptedException e){
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
} }
}
NettyServerHandler.java
package com.tang.netty.simple; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.util.CharsetUtil; import java.nio.ByteBuffer; /**
* 我们自定义一个Handler 需要继承netty 规定好的某个 HandlerAdapter(规范)
* 这个 ChannelInboundHandlerAdapter 是 Pipeline 里的 ChannelHandler 的一个实现
*/
public class NettyServerHandler extends ChannelInboundHandlerAdapter { // 读取数据(这里我们可以读取客户端发送的消息) /**
1.ChannelHandlerContext ctx:上下文对象,含有管道 pipeline,通道 channel,地址
2.Object msg:就是客户端发送的数据,默认Object
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception{
System.out.println("服务器读取线程 " + Thread.currentThread().getName());
System.out.println("server ctx = " + ctx);
System.out.println("查看 channel 与 pipeline 的关系");
Channel channel = ctx.channel();
ChannelPipeline pipeline = ctx.pipeline(); // 本质是一个双向链表,出战入站 // 将 msg 转为 ByteBuf
// ByteBuf 是 Netty 提供的,不是 NIO 的 ByteBuffer
ByteBuf buf = (ByteBuf) msg;
System.out.println("客户端发送的消息是:" + buf.toString(CharsetUtil.UTF_8));
System.out.println("客户端地址:" + channel.remoteAddress()); } // 数据读取完毕
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception{ // writeAndFlush 是 write + flush
// 将数据写入到缓冲,并刷新
// 一般讲,我们对这个发送的数据进行编码
ctx.writeAndFlush(Unpooled.copiedBuffer("Hello,客户端~ 收到", CharsetUtil.UTF_8));
} // 处理异常,一般是需要关闭通道
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
ctx.close();
}
}
NettyClient.java
package com.tang.netty.simple; import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel; public class NettyClient { public static void main(String[] args) {
// 客户端需要一个事件循环组
EventLoopGroup eventExecutors = new NioEventLoopGroup(); try{
// 创建客户端启动对象
// 注意客户端使用的不是 ServerBootstrap 而是 Bootstrap
Bootstrap bootstrap = new Bootstrap(); // 设置相关参数
bootstrap.group(eventExecutors) // 设置线程组
.channel(NioSocketChannel.class) // 设置客户端Channel的实现类
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new NettyClientHandler()); // 加入自己的处理器
}
}); System.out.println("客户端 ok..."); // 启动客户端去连接服务器端
ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 6668).sync(); // 给关闭通道进行监听
channelFuture.channel().closeFuture().sync(); } catch (InterruptedException e){
e.printStackTrace();
} finally {
eventExecutors.shutdownGracefully();
} }
}
NettyClientHandler.java
package com.tang.netty.simple; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil; public class NettyClientHandler extends ChannelInboundHandlerAdapter { // 当 Channel 就绪时,就会触发该方法
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("client " + ctx);
ctx.writeAndFlush(Unpooled.copiedBuffer("hello, server, this is client", CharsetUtil.UTF_8)); } // 当 Channel 有读取事件时,会触发
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
System.out.println("服务器回复的消息:" + buf.toString(CharsetUtil.UTF_8));
System.out.println("服务器的地址:" + ctx.channel().remoteAddress());
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
------------------------------------
此 Netty 笔记为学习尚硅谷韩老师讲的 Netty 整理完成,原视频讲解十分详细,建议对 Netty 框架感兴趣的同学们可以看一遍原视频:
https://www.bilibili.com/video/BV1DJ411m7NR
Netty(三)Netty模型的更多相关文章
- Netty IO线程模型学习总结
Netty框架的 主要线程是IO线程.线程模型的好坏直接决定了系统的吞吐量.并发性和安全性. Netty的线程模型遵循了Reactor的基础线程模型.以下我们先一起看下该模型 Reactor线程模型 ...
- Netty Reactor 线程模型笔记
引用: https://www.cnblogs.com/TomSnail/p/6158249.html https://www.cnblogs.com/heavenhome/articles/6554 ...
- netty之==线程模型
1.1 netty线程模型本质遵循了Reactor的基础线程模型,所以得先介绍Reactor模型 1.2 Reactor模型 无论是C++还是Java编写的网络框架,大多数都是基于Reactor模 ...
- 面试官:Netty的线程模型可不只是主从多Reactor这么简单
笔者看来Netty的内核主要包括如下图三个部分: 其各个核心模块主要的职责如下: 内存管理 主要提高高效的内存管理,包含内存分配,内存回收. 网通通道 复制网络通信,例如实现对NIO.OIO等底层JA ...
- Netty服务器线程模型概览
一切从ServerBootstrap开始 ServerBootstrap负责初始话netty服务器,并且开始监听端口的socket请求. bootstrap bootstrap =newServerB ...
- SDN三种模型解析
数十年前,计算机科学家兼网络作家Andrew S. Tanenbaum讽刺标准过多难以选择,当然现在也是如此,比如软件定义网络模型的数量也很多.但是在考虑部署软件定义网络(SDN)或者试点之前,首先需 ...
- Javascript事件模型系列(一)事件及事件的三种模型
一.开篇 在学习javascript之初,就在网上看过不少介绍javascript事件的文章,毕竟是js基础中的基础,文章零零散散有不少,但遗憾的是没有看到比较全面的系列文章.犹记得去年这个时候,参加 ...
- Atitit.web三编程模型 Web Page Web Forms 和 MVC
Atitit.web三编程模型 Web Page Web Forms 和 MVC 1. 编程模型是 Web Forms 和 MVC (Model, View, Controller). 2. W ...
- NLP —— 图模型(零):EM算法简述及简单示例(三硬币模型)
最近接触了pLSA模型,该模型需要使用期望最大化(Expectation Maximization)算法求解. 本文简述了以下内容: 为什么需要EM算法 EM算法的推导与流程 EM算法的收敛性定理 使 ...
- PHP.23-ThinkPHP框架的三种模型实例化-(D()方法与M()方法的区别)
三种模型实例化 原则上:每个数据表应对应一个模型类(Home/Model/GoodsModel.class.php --> 表tp_goods) 1.直接实例化 和实例化其他类库一样实例化模型类 ...
随机推荐
- Echarts立体地图加3D柱图可点击可高亮选中的开发
注意 echarts请使用v5.1.0以上版本,低版本会无法显示,或者无法触发点击事件. 若有闪屏bug,不要设置temporalSuperSampling属性. 注意图层顺序. 实现原理 借助 ec ...
- 使用NSSM将.exe程序安装成windows服务
1.下载NSSM:NSSM - the Non-Sucking Service Manager 2.cmd方式安装服务 将下载的压缩包解压,找到nssm.exe,以管理员身份打开cmd,在cmd中定位 ...
- 【简说Python WEB】Bootstrap
目录 [简说Python WEB]Bootstrap Bootstrap的导航组件应用 404,500错误页面定制化 系统环境:Ubuntu 18.04.1 LTS Python使用的是虚拟环境:vi ...
- MindSpore反向传播配置关键字参数
技术背景 在MindSpore深度学习框架中,我们可以向construct函数传输必备参数或者关键字参数,这跟普通的Python函数没有什么区别.但是对于MindSpore中的自定义反向传播bprop ...
- python教程6.1-模块和包
模块分类 1.内置标准模块(⼜称标准库)执⾏help('modules')查看所有python⾃带模块列表 2.第三⽅开源模块,可通过pip install 模块名 联⽹安装 3.⾃定义模块 模块导入 ...
- jeecg-boot中分页接口用自定义sql和list实现
1.controller中 @ApiOperation(value="分析仪工作状态和报警-3列-分页", notes="分析仪工作状态和报警状态-分页") @ ...
- MSP 通过 Splashtop SOS 远程支持非托管设备
RMM 是 MSP 的绝佳工具.它们使 MSP 可以通过集中控制台来管理其所有客户计算机,通常使他们能够远程访问任何计算机以提供远程支持. 但是,这样做的一个很大限制是--并非所有客户设备都在 MSP ...
- 在 Chromebook 上使用 Word 的最佳方法
Splashtop 允许您从 Chromebook 远程控制 Windows 和 Mac 计算机,从而可以访问 Word 的桌面版本和所有文件. 对于远程工作者和学生,Chromebook 可以是一种 ...
- Hello Laravel! 准备
Hello Laravel! 准备 目录 Hello Laravel! 准备 什么是 Laravel? 为什么选择 Laravel? 优雅的语法 丰富的功能 强大的社区支持 安全性 易于扩展 Lara ...
- containerd 源码分析:启动注册流程
0. 前言 containerd 是一个行业标准的容器运行时,其强调简单性.健壮性和可移植性.本文将从 containerd 的代码结构入手,查看 containerd 的启动注册流程. 1. 启动注 ...