Netty3主要有 Worker,Boss,AbstractNioSelector,NioSelectorRunnablePool,NioBossSelector ,NioWorkerSelector,ServerBootstrap 等类组成,如果把Netty3比作是一个餐厅的话,Boss相当于在门前欢迎客户的股东(老板,有多个),Worker相当于服务生(多个),负责客人点餐,老板在门口等到客人后把客人交给服务生,老板和服务生都是监听者(AbstractNioSelector),只是职能不同,NioSelectorRunnablePool是线程管理者,即可以管理老板和服务生。当然,Netty中远没有这么简单,这只是一个简单的类比。能力有限,如果类比有误,欢迎指正。
他们的关系如下:
老板和服务生都是一个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,选择选择器,执行任务,处理业务逻辑。
线程管理者,相当于一个线程池,用于管理老板和服务生,定义类为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。
主要负责读写客户端消息, 只需定义一个方法,就是注册到通道任务中,定义为registerNewChannelTask(SocketChannel channel);
只需定义一个方法,就是加入一个新的ServerSocket,定义为registerAcceptChannelTask(ServerSocketChannel serverChannel);
负责监听客户端的连接处理,并把客户端交个worker处理读写。
负责处理客户端的读写数据等处理。
绑定端口
模拟代码如下:
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;inew NioBossSelector(boss, "boss thread"+i, this);
}
}
public void initWorker(Executor worker,int count){
workers = new Worker[count];
for(int i=0;inew 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 tasksQueue = new ConcurrentLinkedQueue();
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 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 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("服务已启动!");
}
}