用这张图表示的就是一个基本的Netty框架

通过创建两个线程池,一个负责接入, 一个负责处理

public class Start {
public static void main(String[] args) { //初始化线程
NioSelectorRunnablePool nioSelectorRunnablePool = new NioSelectorRunnablePool(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()); //1 //获取服务类
ServerBootstrap bootstrap = new ServerBootstrap(nioSelectorRunnablePool); //绑定端口
bootstrap.bind(new InetSocketAddress(80)); System.out.println("start");
}
}
NioSelectorRunnablePool  相当于一个线程池操作类
public class NioSelectorRunnablePool {

    /**
* boss 线程数组
*/
private final AtomicInteger bossIndex = new AtomicInteger();
private Boss[] bosses; /**
* worker线程数组
*/
private final AtomicInteger workerIndex = new AtomicInteger();
private Worker[] workers; public NioSelectorRunnablePool(Executor boss, Executor worker) {
//初始化boss线程 即接入线程
initBoss(boss, 1);
//根据当前核心数*2 初始化处理线程
initWorker(worker, Runtime.getRuntime().availableProcessors() * 2);
} /**
* 初始化boss线程组
* @param boss
* @param count
*/
private void initBoss(Executor boss, int count) {
this.bosses = new NioServerBoss[count];
for (int i = 0; i < bosses.length; i++) {
//线程池数组
bosses[i] = new NioServerBoss(boss, "boss thread" + (i+1), this);
}
} /**
* 初始化worker线程
* @param worker worker线程池
* @param count 线程数
*/
private void initWorker(Executor worker, int count) {
this.workers = new NioServerWorker[count];
for (int i = 0; i < bosses.length; i++) {
workers[i] = new NioServerWorker(worker, "worker thread" + (i+1), this);
}
} /**
* 获取下一个boss线程
* @return
*/
public Boss nextBoss() {
return bosses[Math.abs(bossIndex.getAndIncrement() % bosses.length)];
} /**
* 获取下一个work线程
* @return
*/
public Worker nextWorkr() {
return workers[Math.abs(workerIndex.getAndIncrement() % workers.length)];
}
}
初始化两个线程池 NioServerBoss 和NioServerWorker  两个类都实现 各自的Boss  和 Worker 接口   继承 了 AbstractNioSelector 抽象Selector
public interface Boss {

    /**
* 加入一个新的ServerSocket
* @param serverChannel
*/
public void registerAcceptChannelTask(ServerSocketChannel serverChannel);
}

Boos

public interface Worker {
/**
* 加入一个新的客户端会话
* @param channel
*/
public void registerNewChannelTask(SocketChannel channel); }

Worker

/**
*@Description 抽象selector线程类
*@autor:mxz
*2018-08-17
**/
public abstract class AbstractNioSelector implements Runnable{
/**
* 线程池
*/
private Executor executor;
private String threadName; /**
* 选择器wakenUp状态标记
*/
protected final AtomicBoolean wakenUp = new AtomicBoolean(); /**
* 线程管理对象,存储线程池数组
*/
private NioSelectorRunnablePool selectorRunnablePool; protected Selector selector; /**
* 任务队列
*/
private final Queue<Runnable> taskQueue = new ConcurrentLinkedQueue<Runnable>(); public AbstractNioSelector(Executor executor, String threadName, NioSelectorRunnablePool selectorRunnablePool) {
this.executor = executor;
this.threadName = threadName;
this.selectorRunnablePool = selectorRunnablePool;
//一个线程 加入一个selector
openSelector();
} /**
* 获取线程管理对象
* @return
*/
protected NioSelectorRunnablePool getselectorRunnablePool() {
return this.selectorRunnablePool;
}
/**
* 获取selector并启动线程
*/
private void openSelector() {
try {
this.selector = Selector.open();
} catch (IOException e) {
throw new RuntimeException("Failed to create a selector");
}
//线程池执行该线程
executor.execute(this);
} @Override
public void run() {
Thread.currentThread().setName(this.threadName); while (true) {
try {
wakenUp.set(false);
//当注册事件到达时,方法返回,否则该方法会一直阻塞
select(selector); //运行任务队列中的任务
processTaskQueue(); process(selector);
} catch (Exception e) { }
}
}
/**
* 注册一个任务并激活selector 重新执行
* @param task
*/
protected final void registerTask(Runnable task) {
taskQueue.add(task); Selector selector = this.selector; if (selector != null) {
if (wakenUp.compareAndSet(false, true)) {
//会首先唤醒Boss 接入总线线程 唤醒阻塞在selector上的线程, 去做其他事情,例如注册channel改变interestOps的值
selector.wakeup();
}
} else {
taskQueue.remove(task);
}
} /**
*
*/ //执行队列中的任务
private void processTaskQueue() {
for(;;) {
final Runnable task = taskQueue.poll();
if (task == null) {
break;
}
task.run();
}
} /**
* selector抽象方法
* @param selector
* @return
* @throws IOException
*/
protected abstract int select(Selector selector) throws IOException; /**
* selector的业务处理
* @param selector
* @return
* @throws IOException
*/
protected abstract void process(Selector selector) throws IOException;
}

执行openSelector() 创建 selector  execute 执行线程  执行各自的 select()

public class NioServerBoss extends AbstractNioSelector implements Boss {

    public NioServerBoss(Executor boss, String threadName, NioSelectorRunnablePool selectorRunnablePool) {
super(boss, threadName, selectorRunnablePool);
} @Override
protected int select(Selector selector) throws IOException {
return selector.select();
} @Override
protected void process(Selector selector) throws IOException {
Set<SelectionKey> selectedKeys = selector.selectedKeys();
if (selectedKeys.isEmpty()) {
return;
} for (SelectionKey key : selectedKeys) {
selectedKeys.remove(key);
ServerSocketChannel server = (ServerSocketChannel) key.channel();
//新客户端
SocketChannel channel = server.accept();
//设置为非阻塞
channel.configureBlocking(false);
//获取一个worker
Worker nextworker = getselectorRunnablePool().nextWorkr();
//注册新客户端介入任务给另一个线程任务队列加入新任务
nextworker.registerNewChannelTask(channel);
System.out.println("新客户连接");
}
} @Override
public void registerAcceptChannelTask(final ServerSocketChannel serverChannel) {
final Selector selector = this.selector;
registerTask(new Runnable() {
@Override
public void run() {
try {
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (ClosedChannelException e) {
e.printStackTrace();
}
}
});
} }
public class NioServerWorker extends AbstractNioSelector implements Worker{

    public NioServerWorker(Executor worker, String threadName, NioSelectorRunnablePool selectorRunnablePool) {
super(worker, threadName, selectorRunnablePool);
} @Override
protected int select(Selector selector) throws IOException {
return selector.select();
} @Override
protected void process(Selector selector) throws IOException {
Set<SelectionKey> selectedKeys = selector.selectedKeys();
if (selectedKeys.isEmpty()) {
return;
}
Iterator<SelectionKey> iterator = this.selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
//移除 防止重复提交
iterator.remove(); //得到事件发生的socket通道
SocketChannel channel = (SocketChannel) key.channel(); //数据总长度
int ret = 0;
boolean failure = true;
ByteBuffer buffer = ByteBuffer.allocate(1024);
//读取数据
try {
ret = channel.read(buffer);
failure = false;
} catch (Exception e) {
}
//判断是否连接已断开
if (ret <= 0 || failure) {
key.channel();
System.out.println("客户端已断开连接");
} else {
System.out.println("收到数据:" + new String (buffer.array())); //回 写数据
ByteBuffer outBuf = ByteBuffer.wrap("收到\n".getBytes());
channel.write(outBuf);// 将消息发送到客户端
}
}
}

此时都会selector.selector() 阻塞等待连接

此时再看 bootstrap.bind(new InetSocketAddress(80));  会调用

public class ServerBootstrap {

    private NioSelectorRunnablePool selectorRunnablePool;

    public ServerBootstrap(NioSelectorRunnablePool selectorRunnablePool) {
this.selectorRunnablePool = selectorRunnablePool;
} public void bind(final InetSocketAddress localAddress) {
try {
//获得一个ServerSocket通道
ServerSocketChannel serverChannel = ServerSocketChannel.open();
//设置通道为非阻塞
serverChannel.configureBlocking(false);
//将该通道对应的serverSocket绑定到port
serverChannel.socket().bind(localAddress); //获取一个boss线程
Boss nextBoss = selectorRunnablePool.nextBoss();
//向当前boss 线 程注册一个ServerSocket通道
nextBoss.registerAcceptChannelTask(serverChannel);
} catch (Exception e) {
// TODO: handle exception
}
} }

这个时候通过获取下一个线程注入任务池(其实就一个) 这里可以看AbstractSelector 中的nextBoss 和nextWorker 方法 从线程数组循环拿出线程

这个时候会将当前通道在selector上注册 OP_ACCEPT  的事件 并将这个任务添加到Taskqueue

/**
* 注册一个任务并激活selector 重新执行
* @param task
*/
protected final void registerTask(Runnable task) {
taskQueue.add(task); Selector selector = this.selector; if (selector != null) {
if (wakenUp.compareAndSet(false, true)) {
//会首先唤醒Boss 接入总线线程 唤醒阻塞在selector上的线程, 去做其他事情,例如注册channel改变interestOps的值
selector.wakeup();
}
} else {
taskQueue.remove(task);
}
}

这个时候会唤醒selector  不过唤醒的是boss的selector

唤醒后之前的阻塞会继续往下执行

          wakenUp.set(false);
//当注册事件到达时,方法返回,否则该方法会一直阻塞
select(selector); //运行任务队列中的任务
processTaskQueue(); process(selector);

先执行任务  也就是 channel regiter 到 selector 上

执行 Boss中的 process 的方法

    @Override
protected void process(Selector selector) throws IOException {
Set<SelectionKey> selectedKeys = selector.selectedKeys();
if (selectedKeys.isEmpty()) {
return;
} for (SelectionKey key : selectedKeys) {
selectedKeys.remove(key);
ServerSocketChannel server = (ServerSocketChannel) key.channel();
//新客户端
SocketChannel channel = server.accept();
//设置为非阻塞
channel.configureBlocking(false);
//获取一个worker
Worker nextworker = getselectorRunnablePool().nextWorkr();
//注册新客户端介入任务给另一个线程任务队列加入新任务
nextworker.registerNewChannelTask(channel);
System.out.println("新客户连接");
}
}

同理再去 走相同的路线 把获取到的通道绑到 worker的selector上

 
 

Netty框架原理的更多相关文章

  1. 分布式服务框架介绍:最成熟的开源NIO框架Netty

    尽管JDK提供了丰富的NIO类库,网上也有很多NIO学习例程,但是直接使用Java NIO类库想要开发出稳定可靠的通信框架却并非易事,原因如下: 1)NIO的类库和API繁杂,使用麻烦,你需要熟练掌握 ...

  2. 新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析

    1.引言 Netty 是一个广受欢迎的异步事件驱动的Java开源网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端. 本文基于 Netty 4.1 展开介绍相关理论模型,使用场景,基本组件 ...

  3. netty实现的RPC框架

    自己手撸了一个nettyRPC框架,希望在这里给有兴趣的同学们做个参考. 要想实现nettyrpc需要了解的技术要点如下: spring的自定义注解.spring的bean的有关初始化. 反射和动态代 ...

  4. Netty高性能原理和框架架构解析

    1.引言 Netty 是一个广受欢迎的异步事件驱动的Java开源网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端. 本文基于 Netty 4.1 展开介绍相关理论模型,使用场景,基本组件 ...

  5. 这可能是目前最透彻的Netty原理架构解析

    https://juejin.im/post/5be00763e51d453d4a5cf289 本文基于 Netty 4.1 展开介绍相关理论模型,使用场景,基本组件.整体架构,知其然且知其所以然,希 ...

  6. 【转】目前为止最透彻的的Netty高性能原理和框架架构解析

    转自:https://zhuanlan.zhihu.com/p/48591893 1.引言 Netty 是一个广受欢迎的异步事件驱动的Java开源网络应用程序框架,用于快速开发可维护的高性能协议服务器 ...

  7. Netty原理架构解析

    Netty原理架构解析 转载自:http://www.sohu.com/a/272879207_463994本文转载关于Netty的原理架构解析,方便之后巩固复习 Netty是一个异步事件驱动的网络应 ...

  8. Netty 面试题 (史上最全、持续更新)

    文章很长,建议收藏起来,慢慢读! 疯狂创客圈为小伙伴奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 大厂必备 ...

  9. 【Netty】最透彻的Netty原理架构解析

    这可能是目前最透彻的Netty原理架构解析 本文基于 Netty 4.1 展开介绍相关理论模型,使用场景,基本组件.整体架构,知其然且知其所以然,希望给大家在实际开发实践.学习开源项目方面提供参考. ...

随机推荐

  1. codeforces524E

    题意:n*m的矩阵,给出k个点,Q次询问,问每个矩阵中每个点是否被看管,一个点被看管的定义是那个点所在的行或列有点,n,m<=1e5,k,q<=2e5 sol :发现行和列是独立的,即要么 ...

  2. mysql插入数据自动生成主键uuid

    DemoMapper.java //注意方法的返回值必须是void; void add(Demo demo); ============================================ ...

  3. Jenkins中插件下载失败的解决办法

    插件下载失败原因:通过国外服务器下载镜像,有较高的失败率,某些插件下载失败或者中断会引起其他有依赖关系的插件也下载失败 解决方案:1. 使用VPN.2. Jenkins镜像地址改为国内镜像地址:系统管 ...

  4. javascript中的contains方法和compareDocumentPosition方法

    IE有许多好用的方法,后来都被其他浏览器抄袭了,比如这个contains方法.如果A元素包含B元素,则返回true,否则false.唯一不支持这个方法的是IE的死对头firefox.不过火狐支持com ...

  5. 微信小程序:自定义导航栏

    在小程序开发的时候会遇到一些页面不需要头部导航,或像淘宝的商品详情一样自定义的导航栏.那先要清楚这导航可不能写死,每种手机的导航都各不相同. 一.在app.json的window对象中定义导航的样式: ...

  6. FCRA题库及答案(未完待续)

    一.FCRA-入门基础(23) 1.FineReport中普通模板总共有5种不同的预览模式:分页预览.填报预览.新填报预览.数据分析.移动端预览 决策报表下为表单预览.移动端预览 2.FineRepo ...

  7. vmware 两删除一清空

    快速处理办法: cat /etc/sysconfig/network-scripts/ifcfg-eth0 sed -i '/UUID/d' /etc/sysconfig/network-script ...

  8. ISO/IEC 9899:2011 条款5——5.2.4 环境限制

    5.2.4 环境限制 1.翻译与执行环境都约束了语言翻译器和库的实现.下面概述了对一个顺应标准实现的语言相关的环境限制:库相关的限制在条款7中讨论. 5.2.4.1 翻译限制 1.实现应该能够翻译并执 ...

  9. 使用C语言 判断当前网络是否联通

    方式一: int GetNetStat( ) { char buffer[BUFSIZ]; FILE *read_fp; int chars_read; int ret; try { memset( ...

  10. 阶段5 3.微服务项目【学成在线】_day07 课程管理实战_05-课程修改实战分析

    3 课程信息修改 3.1 需求分析 课程添加成功进入课程管理页面,通过课程管理页面修改课程的基本信息.编辑课程图片.编辑课程营销信息等. 本小节实现修改课程. 3.2 课程管理页面说明 3.2.1 页 ...