NIO实现Netty框架

         简介:Netty就是有 看门服务员(线程+selector) 是迎接客人(接受请求),点菜服务员 (线程+selector)去 处理客人的点菜等等。客人就相当于一个客户端的请求。

  各个类的流程

   一、主启动类流程:(Start.java)

        1、创建 线程池管理者 : 用于管理 Boss (看门服务员) 和  Worker (点菜服务员)的两个线程池。

        2、 把线程池管理者交给服务类

ServerBootstrap bootstrap = new ServerBootstrap(nioSelectorRunnablePool);

        3、服务类监听端口 

bootstrap.bind(new InetSocketAddress(10101));

    二、线程池管理者 构造方法:

          提示:一个线程池中可能有多个线程 => 有多个看门的服务员  和 多个点菜的服务员

          1、初始化 boss (看门服务员)线程池

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);
    }
}

 

          2、初始化 worker (点菜服务员)线程池

private void initWorker(Executor worker, int count) {
    this.workeres = new NioServerWorker[count];
    for (int i = 0; i < workeres.length; i++) {
                                     // (线程池,线程的名字,线程管理者对象)
        workeres[i] = new NioServerWorker(worker, "worker thread " + (i+1), this);
    }
}

提示:

      AbstractNioSelector、NioServerWorker、NioServerBoss、Boss、Worker、Runnable 实体类之间的关系图

      Boss(看门服务员接口)用来监听端口    Worker(点菜服务员接口) 实际的读写处理类

      NioServerBoss(看门服务员实体类)      NioServerWorker(点菜服务员实体类)

     AbstractNioSelector( 看门服务员 与 点 菜服务员 的抽象类)

java 引入postgresql JAVA 引入natty_初始化

       

       三、NioServerBoss 处理流程

               1、AbstrcatNioSelector的构造方法有 openSelector方法:

                     executor.execute(this);       // 执行当前线程 ,就是 Boss 线程

                     就会执行 抽象类 的run方法  ->  run方法中的  select  与  process 在不同的服务员中有不同的处理方式

public void run() {
    while (true) {
        wakenUp.set(false);
        select(selector);
        processTaskQueue();
        // 进行业务处理  (因为Boss和worker的工作任务时不同的)
        process(selector);
    }
}

               2、

               3、

               4、

 

 

 

所有代码示例:

  主启动类:

/**
 * 使用NIO麻烦netty框架
 */
public class Start {
	// 主启动类
	public static void main(String[] args) {
		//初始化线程(用来管理所有的线程池)
		NioSelectorRunnablePool nioSelectorRunnablePool = 
				new NioSelectorRunnablePool(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());   // 新建两个线程池,相当于一个是boss(看门服务员),一个是worker(点菜服务员)
		//获取服务类 (把线程管理者交给服务类)
		ServerBootstrap bootstrap = new ServerBootstrap(nioSelectorRunnablePool);
		
		//绑定端口   (服务类监听端口)
		bootstrap.bind(new InetSocketAddress(10101));
		
		System.out.println("start");
	}
	/*
	 * 我们可以打开CMD窗口 输入  telnet 127.0.0.1 10101进行连接  (可以自己多打开几个)
	 */
}

 

  线程管理者:

public class NioSelectorRunnablePool {
	/**
	 * boss线程数组(多个线程,多个看门服务员)
	 */
	private final AtomicInteger bossIndex = new AtomicInteger();
	private Boss[] bosses;

	/**
	 * worker线程数组
	 */
	private final AtomicInteger workerIndex = new AtomicInteger();
	private Worker[] workeres;

	//  初始化两个线程池,一个是boss,一个是worker
	public NioSelectorRunnablePool(Executor boss, Executor worker) {
		initBoss(boss, 1);
		//  系统核心数量 * 2 
		initWorker(worker, Runtime.getRuntime().availableProcessors() * 2);
	}

	/**
	 * 初始化boss线程
	 */
	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线程
	 */
	private void initWorker(Executor worker, int count) {
		this.workeres = new NioServerWorker[count];
		for (int i = 0; i < workeres.length; i++) {
			// 对应三个参数,  (线程池,线程的名字,线程管理者对象)
			workeres[i] = new NioServerWorker(worker, "worker thread " + (i+1), this);
		}
	}

	/**
	 * 获取一个 worker 服务员来为客人服务
	 */
	public Worker nextWorker() {
		// Math.abs() 返回绝对值
		return workeres[Math.abs(workerIndex.getAndIncrement() % workeres.length)];
		//  通过循环给每一个 worker 进行分配工作
	}

	/**
	 * 获取一个boss 来为客人欢迎光临
	 */
	public Boss nextBoss() {
		return bosses[Math.abs(bossIndex.getAndIncrement() % bosses.length)];
	}

}

   

  服务类:

/**
 * 服务类
 */
public class ServerBootstrap {
	private NioSelectorRunnablePool selectorRunnablePool;

	public ServerBootstrap(NioSelectorRunnablePool selectorRunnablePool) {
		this.selectorRunnablePool = selectorRunnablePool;
	}

	/**
	 * 绑定端口
	 */
	public void bind(final SocketAddress 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) {
			e.printStackTrace();
		}
	}
}

 

  AbstractNioSelector:Boss 和 Worker 的抽象类

/**
 * 抽象selector线程类
 */
public abstract class AbstractNioSelector implements Runnable {

	/**
	 * 线程池
	 */
	private final Executor executor;

	/**
	 * 选择器
	 */
	protected Selector selector;

	/**
	 * 选择器wakenUp状态标记
	 */
	protected final AtomicBoolean wakenUp = new AtomicBoolean();

	/**
	 * 任务队列     (这个queue是一个 线程安全 的 queue)
	 */
	private final Queue<Runnable> taskQueue = new ConcurrentLinkedQueue<Runnable>();

	/**
	 * 线程名称
	 */
	private String threadName;
	
	/**
	 * 线程管理对象
	 */
	protected NioSelectorRunnablePool selectorRunnablePool;

	AbstractNioSelector(Executor executor, String threadName, NioSelectorRunnablePool selectorRunnablePool) {
		// 线程池
		this.executor = executor;
		// 线程名
		this.threadName = threadName;
		// 线程管理者
		this.selectorRunnablePool = selectorRunnablePool;
		openSelector();
	}

	/**
	 * 获取selector并启动线程
	 */
	private void openSelector() {
		try {
			// selector打开,一个线程有selector才可以为多个客人服务的能力
			this.selector = Selector.open();
		} catch (IOException e) {
			throw new RuntimeException("Failed to create a selector.");
		}
		// 用线程池执行 当前对象 的run方法      this只的是当前的 NioServerBoss 或 NioServerWorker 对象
		// AbstractNioSelector 是 实现 Runnable的,所以肯定有run方法,相当于执行run方法
		executor.execute(this);
	}

	@Override
	public void run() {
		// 为当前线程设置名字
		Thread.currentThread().setName(this.threadName);
		while (true) {
			try {
				wakenUp.set(false);
				select(selector);
				processTaskQueue();
				// 进行业务处理  (因为Boss和worker的工作任务时不同的)
				process(selector);
			} catch (Exception e) {
				// ignore
			}
		}
	}

	/**
	 * 注册一个任务并激活selector
	 * 
	 * @param task
	 */
	protected final void registerTask(Runnable task) {
		taskQueue.add(task);
		Selector selector = this.selector;
		if (selector != null) {
			// 看是不是 false 状态,如果是false改为true ,不是就跳过
			if (wakenUp.compareAndSet(false, true)) {
				selector.wakeup();
				// 加入一个任务时,要重新 激活 selector的状态
			}
		} else {
			taskQueue.remove(task);
		}
	}

	/**
	 * 执行队列里的任务
	 */
	private void processTaskQueue() {
		for (;;) {
			// 将queue里的一个一个  Runnable(任务) 取出来 运行
			final Runnable task = taskQueue.poll();
			if (task == null) {
				break;
			}
			task.run();
		}
	}
	
	/**
	 * 获取线程管理对象
	 */
	public NioSelectorRunnablePool getSelectorRunnablePool() {
		return selectorRunnablePool;
	}
	/**
	 * select抽象方法  ,不同的对象有不同的方法
	 */
	protected abstract int select(Selector selector) throws IOException;

	/**
	 * selector的业务处理
	 */
	protected abstract void process(Selector selector) throws IOException;
}

 

    Boss接口:

public interface Boss {
	/**
	 * 加入一个新的ServerSocket
	 */
	public void registerAcceptChannelTask(ServerSocketChannel serverChannel);
}

    Worker接口:

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

 

   Boss实体类:

/**
 * boss实现类
 *  AbstractNioSelector 是一个单线程的抽象类
 */
public class NioServerBoss extends AbstractNioSelector implements Boss{

	public NioServerBoss(Executor executor, String threadName, NioSelectorRunnablePool selectorRunnablePool) {
		super(executor, threadName, selectorRunnablePool);
	}

	@Override
	protected void process(Selector selector) throws IOException {
		// 取出所有的key
		Set<SelectionKey> selectedKeys = selector.selectedKeys();
        if (selectedKeys.isEmpty()) {
            return;
        }
        
        for (Iterator<SelectionKey> i = selectedKeys.iterator(); i.hasNext();) {
            SelectionKey key = i.next();
            i.remove();
            ServerSocketChannel server = (ServerSocketChannel) key.channel();
    		// 新客户端
    		SocketChannel channel = server.accept();
    		// 设置为非阻塞
    		channel.configureBlocking(false);
    		
    		// 通过线程管理者对象 获取一个worker (类似于大门的服务生,把顾客引到一个区域后要交给这个区域的服务员)  
    		Worker nextworker = getSelectorRunnablePool().nextWorker();
    		// 注册新客户端接入任务   类似于往别的线程池队列里加任务,让线程池自己去执行  (类似通知这个服务员与服务它)
    		
    		nextworker.registerNewChannelTask(channel);
    		// 往别的线程队列中加任务,可以更好的避免 高并发出现的问题,不会直接去调用其他的线程, 让线程之间的耦合减低
    		
    		System.out.println("新客户端链接");
        }
	}
	
	public void registerAcceptChannelTask(final ServerSocketChannel serverChannel){
		 final Selector selector = this.selector;
		 registerTask(new Runnable() {
			@Override
			public void run() {
				try {
					//注册serverChannel到selector
					serverChannel.register(selector, SelectionKey.OP_ACCEPT);
				} catch (ClosedChannelException e) {
					e.printStackTrace();
				}
			}
		});
	}
	
	@Override
	protected int select(Selector selector) throws IOException {
		return selector.select();
	}
}

 

   Worker实体类:

package com.cn;
/**
 * worker实现类
 * @author -琴兽-
 */
public class NioServerWorker extends AbstractNioSelector implements Worker{
	public NioServerWorker(Executor executor, String threadName, NioSelectorRunnablePool selectorRunnablePool) {
		super(executor, threadName, selectorRunnablePool);
	}

	@Override
	protected void process(Selector selector) throws IOException {
		Set<SelectionKey> selectedKeys = selector.selectedKeys();
        if (selectedKeys.isEmpty()) {
            return;
        }
        Iterator<SelectionKey> ite = this.selector.selectedKeys().iterator();
		while (ite.hasNext()) {
			SelectionKey key = (SelectionKey) ite.next();
			// 移除,防止重复处理
			ite.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) {
				// ignore
			}
			//判断是否连接已断开
			if (ret <= 0 || failure) {   // 如果没有读取到数据就是客户端断开
				key.cancel();        // 取消关联
				System.out.println("客户端断开连接");
	        }else{
	        	 System.out.println("收到数据:" + new String(buffer.array()));	 
	     		//回写 数据 给 客户端
	     		ByteBuffer outBuffer = ByteBuffer.wrap("收到\n".getBytes());
	     		channel.write(outBuffer);// 将消息回送给客户端
	        }
		}
	}

	/**
	 * 加入一个新的socket客户端
	 * 加入一个任务
	 */
	public void registerNewChannelTask(final SocketChannel channel){
		 final Selector selector = this.selector;
		 registerTask(new Runnable() {
			@Override
			public void run() {
				try {
					//将客户端注册到selector中
					channel.register(selector, SelectionKey.OP_READ);
				} catch (ClosedChannelException e) {
					e.printStackTrace();
				}
			}
		});
	}

	@Override
	protected int select(Selector selector) throws IOException {
		return selector.select(500);
	}
}