Netty3源码原理
来源:互联网 发布:淘宝卖虚拟物品流程 编辑:程序博客网 时间:2024/06/06 13:16
Netty3主要有 Worker,Boss,AbstractNioSelector,NioSelectorRunnablePool,NioBossSelector ,NioWorkerSelector,ServerBootstrap 等类组成,如果把Netty3比作是一个餐厅的话,Boss相当于在门前欢迎客户的股东(老板,有多个),Worker相当于服务生(多个),负责客人点餐,老板在门口等到客人后把客人交给服务生,老板和服务生都是监听者(AbstractNioSelector),只是职能不同,NioSelectorRunnablePool是线程管理者,即可以管理老板和服务生。当然,Netty中远没有这么简单,这只是一个简单的类比。能力有限,如果类比有误,欢迎指正。
他们的关系如下:
1、AbstractNioSelector
老板和服务生都是一个selector,需要抽象出来,定义为类AbstractNioSelector,为一个虚类,是一个线程,老板服务类和服务生服务类都继承此类,此类需要定义
A、有执行任务的线程池Executor
B、选择器Selector
C、选择器状态标记,标记选择器是睡眠状态还是运行状态 AtomicBoolean
D、任务队列,要有任务执行才有意义,ConcurrentLinkedQueue
E、当前线程线程名 String threadName
F、线程管理对象,NioSelectorRunnablePool,后面会讲到。
方法需要定义
A、构造方法,初始化线程池、线程名、线程管理对象,并获取selector和启动线程
B、注册一个任务并且并激活selector,相当于在任务队列中加入一个任务,并且唤醒selector,表示可以执行任务了,因为没有任务的时候selector会设置为睡眠,定义为registerTask(Rannable task)
C、执行任务队列里的任务,定义为processTaskQueue();
D、选择选择器,定义为select(Selector selector);
E、处理业务逻辑,定义为process(Selector selector);老板服务类处理的业务逻辑为,接收到新连接的客户端,相当于在餐厅门口接到了客人,然后把客人交给服务生,然后老板就不管了,把客人交给服务生的时候需要用的线程管理对象获得一个服务生。然后服务生注册此客人。服务生服务类负责处理读写数据,相当于负责点餐。
F、最后定义run方法,因为是线程处理,循环执行 把唤醒标志设置为false,选择选择器,执行任务,处理业务逻辑。
2、NioSelectorRunnablePool
线程管理者,相当于一个线程池,用于管理老板和服务生,定义类为NioSelectorRunnablePool,需要定义
A、boss线程数组和boss计数器
B、worker线程组合worker计数器
方法需要定义
A、初始化boss线程,定义为initBoss(Executor boss,int count);创建count个Boss,并且把线程池给boss
B、初始化worker线程,定义为initWorker(Executor worker,int count);创建count个Worker,并且把线程池给Worker
C、获取下一个worker,定义为nextWorker();就是计数器对应的worker
D、获取下一个boss,定位为nextBoss();就是计数器对应的boss。
3、Worker
主要负责读写客户端消息, 只需定义一个方法,就是注册到通道任务中,定义为registerNewChannelTask(SocketChannel channel);
4、Boss
只需定义一个方法,就是加入一个新的ServerSocket,定义为registerAcceptChannelTask(ServerSocketChannel serverChannel);
5、NioBossSelector
负责监听客户端的连接处理,并把客户端交个worker处理读写。
6、NioWorkerSelector
负责处理客户端的读写数据等处理。
7、ServerBootstrap
绑定端口
模拟代码如下:
package com.sf.simba.netty.imitate.pool;import java.util.concurrent.Executor;import java.util.concurrent.atomic.AtomicInteger;import com.sf.simba.netty.imitate.NioBossSelector;import com.sf.simba.netty.imitate.NioWorkerSelector;/** * * @author 734621 * */public class NioSelectorRunnablePool { private Boss[] bosses; private AtomicInteger bossCount = new AtomicInteger(); private Worker[] workers; private AtomicInteger workersCount = new AtomicInteger(); public NioSelectorRunnablePool(Executor boss, Executor worker, int bossCount, int workerCount){ initBoss( boss, bossCount); initWorker(worker,workerCount); } public void initBoss(Executor boss,int count){ bosses = new Boss[count]; for(int i=0;i<count;i++){ bosses[i]= new NioBossSelector(boss, "boss thread"+i, this); } } public void initWorker(Executor worker,int count){ workers = new Worker[count]; for(int i=0;i<count;i++){ workers[i] = new NioWorkerSelector(worker,"worker thread"+i,this); } } /** * 获得一个worker * @return */ public Worker nextWorker(){ return workers[Math.abs(workersCount.getAndIncrement()%workers.length)]; } /** * 获得一个boss * @return */ public Boss nextBoss(){ return bosses[Math.abs(bossCount.getAndIncrement()%bosses.length)]; }}
package com.sf.simba.netty.imitate.pool;import java.io.IOException;import java.nio.channels.ServerSocketChannel;public interface Boss { /** * 注册新来的客户端 * 即相当于老板在门口迎接了新的客人,之后会交给服务生 * @param channel * @throws IOException */ public void registerAcceptChannelTask(ServerSocketChannel channel) throws IOException;}
package com.sf.simba.netty.imitate.pool;import java.nio.channels.SocketChannel;public interface Worker { public void registerNewChannelTask(SocketChannel channel);}
package com.sf.simba.netty.imitate;import java.io.IOException;import java.nio.channels.Selector;import java.util.Queue;import java.util.concurrent.ConcurrentLinkedQueue;import java.util.concurrent.Executor;import java.util.concurrent.atomic.AtomicBoolean;import com.sf.simba.netty.imitate.pool.NioSelectorRunnablePool;/** * bossSelector 和 workerSelector的抽象类 * @author 734621 * */public abstract class AbstractNioSelector implements Runnable{ //线程池 private final Executor executor; //选择器 protected Selector selector; //selector唤醒标志 private final AtomicBoolean wakeup = new AtomicBoolean(); //任务队列 private final Queue<Runnable> tasksQueue = new ConcurrentLinkedQueue<Runnable>(); private String threadName; /** * 线程管理器,管理boss和worker */ private NioSelectorRunnablePool selectPool; public AbstractNioSelector(Executor executor,String threadName,NioSelectorRunnablePool selectPool){ this.executor = executor; this.threadName = threadName; this.selectPool = selectPool; openSelector(); } /** * 获取selector并启用线程 */ private void openSelector(){ try { selector = Selector.open(); } catch (IOException e) { e.printStackTrace(); } executor.execute(this); } /** * 注册任务 相当于告诉boss或者worker有新的客人,需要开始工作了 * @param task */ public final void registerTask(Runnable task){ tasksQueue.add(task); Selector selector = this.selector; if(selector != null){ if(wakeup.compareAndSet(false, true)){ selector.wakeup(); } }else{ tasksQueue.remove(task); } } public void run(){ Thread.currentThread().setName(threadName); while(true){ wakeup.set(false); try { //选择选择器 select(selector); //处理任务 processTaskQueue(); //处理逻辑 process(selector); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 处理任务队列 */ protected final void processTaskQueue(){ while(true){ final Runnable task = tasksQueue.poll(); //如果没有任务了就直接退出循环 if(task == null) break; task.run(); } } protected abstract void select(Selector selector) throws IOException; protected abstract void process(Selector selector) throws IOException; public NioSelectorRunnablePool getSelectPool() { return selectPool; }}
package com.sf.simba.netty.imitate;import java.io.IOException;import java.nio.channels.ClosedChannelException;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.util.Set;import java.util.concurrent.Executor;import com.sf.simba.netty.imitate.pool.Boss;import com.sf.simba.netty.imitate.pool.NioSelectorRunnablePool;import com.sf.simba.netty.imitate.pool.Worker;public class NioBossSelector extends AbstractNioSelector implements Boss { public NioBossSelector(Executor executor, String threadName, NioSelectorRunnablePool selectPool) { super(executor, threadName, selectPool); // TODO Auto-generated constructor stub } @Override public void registerAcceptChannelTask(final ServerSocketChannel channel) throws IOException { final Selector selector = this.selector; registerTask(new Runnable(){ @Override public void run() { try { channel.register(selector, SelectionKey.OP_ACCEPT);//把boss注册为接受,即在门口迎接客人 } catch (ClosedChannelException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); } @Override public void select(Selector selector) throws IOException { selector.select(); } /** * 处理业务逻辑,boss的业务逻辑主要是在门口迎接客人并且把客人交给worker,worker接待后准备为客人点餐 * @throws IOException */ @Override public void process(Selector selector) throws IOException { Set<SelectionKey> selectionKeys = selector.selectedKeys(); if(selectionKeys.isEmpty()){ return; } for(SelectionKey key:selectionKeys){ ServerSocketChannel channel = (ServerSocketChannel)key.channel(); SocketChannel accept = channel.accept();//接收此客人 accept.configureBlocking(false); //把此客人交给一个服务生worker Worker nextworker = super.getSelectPool().nextWorker(); nextworker.registerNewChannelTask(accept); System.out.println("一个新的客户端连接了进来!"); } }}
package com.sf.simba.netty.imitate;import java.io.IOException;import java.nio.ByteBuffer;import java.nio.channels.ClosedChannelException;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.SocketChannel;import java.util.Set;import java.util.concurrent.Executor;import com.sf.simba.netty.imitate.pool.NioSelectorRunnablePool;import com.sf.simba.netty.imitate.pool.Worker;public class NioWorkerSelector extends AbstractNioSelector implements Worker { public NioWorkerSelector(Executor executor, String threadName, NioSelectorRunnablePool selectPool) { super(executor, threadName, selectPool); // TODO Auto-generated constructor stub } @Override public void select(Selector selector) throws IOException { selector.select(200); } @Override public void process(Selector selector) throws IOException { Set<SelectionKey> selectedKeys = selector.selectedKeys(); if(selectedKeys.isEmpty()) return; for(SelectionKey key : selectedKeys){ selectedKeys.remove(key);//移除,防止重复加载 SocketChannel channel = (SocketChannel) key.channel(); channel.configureBlocking(false); //开始读取数据 int messageCount = 0; boolean failture = true; ByteBuffer buffer = ByteBuffer.allocate(100); messageCount = channel.read(buffer); failture = false; //判断是否已经断开 if(messageCount <0 || failture){ key.cancel(); System.out.println("客户端已经断开连接!"); }else{ System.out.println("服务器收到数据:"+new String(buffer.array())); ByteBuffer outbuffer = ByteBuffer.wrap("服务器已经收到数据\n".getBytes()); channel.write(outbuffer); } } } /** * worker注册为 */ @Override public void registerNewChannelTask(final SocketChannel channel) { final Selector selector = this.selector; registerTask(new Runnable(){ public void run(){ try { channel.register(selector, SelectionKey.OP_READ); } catch (ClosedChannelException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); }}
package com.sf.simba.netty.imitate;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.channels.ServerSocketChannel;import com.sf.simba.netty.imitate.pool.Boss;import com.sf.simba.netty.imitate.pool.NioSelectorRunnablePool;public class ServerBootstrap { private NioSelectorRunnablePool selectorPool; public ServerBootstrap(NioSelectorRunnablePool selectorPool){ this.selectorPool = selectorPool; } /** * 绑定端口并获得一个boss * @param address * @throws IOException */ public void bind(final InetSocketAddress address) { try{ ServerSocketChannel channel = ServerSocketChannel.open(); channel.configureBlocking(false); channel.socket().bind(address); Boss boss = selectorPool.nextBoss(); boss.registerAcceptChannelTask(channel); }catch(IOException e){ e.printStackTrace(); } }}
package com.sf.simba.netty.imitate;import java.net.InetSocketAddress;import java.util.concurrent.Executor;import java.util.concurrent.Executors;import com.sf.simba.netty.imitate.pool.NioSelectorRunnablePool;public class Netty3Main { /** * 测试 * @param args */ public static void main(String [] args){ Executor boss = Executors.newCachedThreadPool(); Executor worker = Executors.newCachedThreadPool(); NioSelectorRunnablePool nsrp = new NioSelectorRunnablePool(boss,worker,1,Runtime.getRuntime().availableProcessors()*2); ServerBootstrap boot = new ServerBootstrap(nsrp); boot.bind(new InetSocketAddress(8000)); System.out.println("服务已启动!"); }}
- Netty3源码原理
- Netty3 源码分析 - 套接字绑定实现原理
- Netty3 源码分析 - Channel
- Netty3 源码分析 - AbstractChannel
- Netty3 源码分析 - ChannelHandler
- Netty3 源码分析 - ChannelHandlerContext
- Netty3 源码分析 - ChannelEvent
- Netty3 源码分析 - ChannelState
- Netty3 源码分析 - ChannelStateEvent
- Netty3 源码分析 - OioClientSocketChannelFactory
- Netty3 源码分析 - ClientBootstrap
- Netty3 源码分析 - ChannelPipeline
- Netty3 源码分析 - ChannelFuture
- Netty3 源码分析 - ChannelUpstreamHandler
- netty3 源码分析解
- netty3.2.3源码分析--ServerBootstrap启动分析
- netty3.2.3源码分析-ClientBootstrap启动分析
- netty3.2.3源码分析--ServerBootstrap启动分析
- JAVA程序员成长之路的总结
- PAT 1043 输出PATest(二)
- Spring 之SPEL表达式
- 【HDU1848】Fibonacci again and again (博弈论)
- 算法笔记_019-背包问题(Java)
- Netty3源码原理
- C中的二分函数:upper_bound()与lower_bound()
- 大话数据结构7 - 排序
- linux系统644、755、777权限详解
- 怎样应对“需求不确定型项目”?
- Go语言基础语法学习笔记[3]
- OpenCV Python教程(3、直方图的计算与显示)
- java mail邮件发送功能代码
- pgpool-II3.6安装配置:(流复制下的:主备模式)