架构图:
-
Reactor
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class NIOReactorServer {
//服务所用端口
private static final int PORT=9999;
//选择器
private Selector selector;
//服务端serverSocketChannel, 主要功能是处理事件
private ServerSocketChannel serverSocketChannel;
//处理连接的acceptor
private Acceptor acceptor;
//线程池
private ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
//初始化服务端
{
try {
//创建选择器
selector=Selector.open();
//创建serverSocketChannel
serverSocketChannel=ServerSocketChannel.open();
//设置为非阻塞式
serverSocketChannel.configureBlocking(false);
//绑定端口
serverSocketChannel.socket().bind(new InetSocketAddress(PORT));
//把serverSocketChannel注册到选择器,使选择器监听accept事件
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
}catch (Exception e){
e.printStackTrace();
}
}
public Acceptor getAcceptor() {
return acceptor;
}
public void setAcceptor(Acceptor acceptor) {
this.acceptor = acceptor;
}
public void dispatch(){
//当有事件发生时,获取发生事件的SelectionKey集合,通过SelectionKey可以获取socketChannel通道和发生事件的类型等
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
System.out.print(Thread.currentThread().getName()+"监听到事件:");
SelectionKey selectionKey = iterator.next();
//accept事件处理
if (selectionKey.isAcceptable()) {
System.out.println(Thread.currentThread().getName()+"连接事件");
if(acceptor!=null)
acceptor.accept(selector,serverSocketChannel);
}
//read事件处理
if (selectionKey.isReadable()) {
System.out.println(Thread.currentThread().getName()+"消息读取事件");
//群发消息(不包含自己)
MsgHandler msgHandler=MsgHandlerPool.getMsgHandler();
msgHandler.setSelector(selector);
msgHandler.setSelf(selectionKey);
//读消息
String msg=msgHandler.read(selectionKey);
System.out.println(Thread.currentThread().getName()+"服务器群发消息:" + msg);
//处理业务 发送消息
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
String userName ="未知";
try {
userName = socketChannel.getRemoteAddress().toString().substring(11);
}catch (Exception e){
e.printStackTrace();
}
//调用msgHandler的work方法做后续工作,主线程可以返回了
msgHandler.work(userName,msg);
System.out.println(Thread.currentThread().getName()+"主线程返回");
}
//移出处理完事件的selectionKey
iterator.remove();
}
}
//事件监听:accept和read事件
public void select(){
while (true) {
try {
System.out.println(Thread.currentThread().getName()+"开始监听事件");
//当没有事件发生时会阻塞在此位置,也可设置不阻塞或阻塞超时时间
selector.select();
//事件分发
dispatch();
}catch (Exception e){
e.printStackTrace();
}
}
}
public static void main(String[] args) {
//线程池
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
//创建服务端
NIOReactorServer server=new NIOReactorServer();
//指定连接处理器
server.setAcceptor(new Acceptor());
//开始监听
server.select();
}
}
-
Acceptor(未变动)
import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
/**
* 处理连接对象
*/
public class Acceptor {
public void accept(Selector selector, ServerSocketChannel serverSocketChannel) {
try {
System.out.println(Thread.currentThread().getName()+"分配一个代表客户端连接的socketChannel");
//使用serverSocketChannel分配一个代表客户端连接的socketChannel
SocketChannel socketChannel = serverSocketChannel.accept();
//设置为非阻塞式
socketChannel.configureBlocking(false);
//注册到选择器上,并让选择器监听read事件
socketChannel.register(selector, SelectionKey.OP_READ);
} catch (IOException e) {
e.printStackTrace();
}
}
}
-
MsgHandler
msgHandler.work方法用来处理业务数据
msgHandler.close方法用来把对象返回到对象池
import java.io.Closeable;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
/**
* 处理业务部分的handler
*/
public class MsgHandler implements Closeable {
//选择器
private Selector selector;
//是否正在运行
private boolean isRunning=false;
private SelectionKey self;
public MsgHandler(){}
public Selector getSelector() {
return selector;
}
public void setSelector(Selector selector) {
this.selector = selector;
}
public SelectionKey getSelf() {
return self;
}
public void setSelf(SelectionKey self) {
this.self = self;
}
public boolean isRunning() {
return isRunning;
}
public void setRunning(boolean running) {
isRunning = running;
}
//读取从客户端发来的数据
public String read(SelectionKey self) {
try {
//获取事件发生、代表客户端连接的socketChannel
SocketChannel socketChannel = (SocketChannel) self.channel();
//读取通道的数据到缓存,用来记录日志
ByteBuffer b = ByteBuffer.allocate(1024);
int read = socketChannel.read(b);
if(read>0)
return new String(b.array(), 0, read);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
//群发消息(不包含自己)
public void send(final String msg) {
System.out.println(Thread.currentThread().getName()+"一共有" + selector.keys().size() + "个连接");
selector.keys().stream().filter(selectionKey -> self != selectionKey).forEach(selectionKey -> {
try {
//群发消息(ServerSocketChannel除外)
if (selectionKey.channel() instanceof SocketChannel) {
//获取代表客户端连接的socketChannel通道
SocketChannel socketChannel1 = (SocketChannel) selectionKey.channel();
//把缓存内的数据写入到socketChannel通道
socketChannel1.write(ByteBuffer.wrap(msg.getBytes()));
}
} catch (IOException e) {
e.printStackTrace();
}
});
}
//获取业务数据
public void work(String userName, String msg) {
MsgHandlerPool.getThreadPool().execute(new Worker(this,userName, msg));
}
@Override
public void close() throws IOException {
MsgHandlerPool.returnBack(this);
}
}
-
MsgHandlerPool
对象池,包含msgHandler对象池和线程池
import java.util.Iterator;
import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MsgHandlerPool {
//线程池
private static final ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
//消息处理对象池
private static final LinkedList<MsgHandler> msgHandlers=new LinkedList<MsgHandler>();
static {
init();
}
//初始化:默认初始化10个msgHandler对象到对象池中
private static void init(){
for(int i=0;i<10;i++){
msgHandlers.add(new MsgHandler());
}
}
private MsgHandlerPool(){}
//获取msgHandler对象
public static MsgHandler getMsgHandler(){
if(msgHandlers.size()<=0){
synchronized (MsgHandlerPool.class){
if(msgHandlers.size()<=0){
init();
}
}
}
MsgHandler msgHandler = msgHandlers.removeFirst();
msgHandler.setRunning(true);
System.out.println(Thread.currentThread().getName()+"拿出一个msgHandler对象,对象池中还有"+msgHandlers.size()+"个对象");
return msgHandler;
}
//回收msgHandler对象
public static void returnBack(MsgHandler msgHandler){
if(msgHandler!=null){
msgHandler.setRunning(false);
msgHandlers.addLast(msgHandler);
}
System.out.println(Thread.currentThread().getName()+"回收一个msgHandler对象,对象池中还有"+msgHandlers.size()+"个对象");
gc();
}
//获取线程池对象
public static ExecutorService getThreadPool(){
return cachedThreadPool;
}
//回收没有运行的msgHandler
private static void gc(){
if(msgHandlers.size()>100){
synchronized (MsgHandlerPool.class){
if(msgHandlers.size()>100){
System.out.println(Thread.currentThread().getName()+"gc msgHandler对象池");
Iterator<MsgHandler> iterator = msgHandlers.iterator();
while (iterator.hasNext()){
MsgHandler msgHandler = iterator.next();
if(!msgHandler.isRunning()){
iterator.remove();
}
}
}
}
}
}
}
-
Worker
用来处理业务数据,处理结束后调用msgHandler的send方法返回结束给客户端
public class Worker implements Runnable {
private String userName;
private String msg;
private MsgHandler msgHandler;
public Worker(MsgHandler msgHandler, String userName, String msg) {
this.msgHandler=msgHandler;
this.userName=userName;
this.msg=msg;
}
@Override
public void run() {
//模拟业务处理
String m=userName + "说:"+msg;
try {
msgHandler.send(m);
}finally {
if(msgHandler!=null)
try {
msgHandler.close();
} catch (IOException e) {
msgHandler=null;
e.printStackTrace();
}
}
}
}