NIO 主从Reactor服务
模型如下:
方案说明:
-
Reactor主线程 MainReactor 对象通过select 监听连接事件, 收到事件后,通过Acceptor 处理连接事件
-
当 Acceptor 处理连接事件后,MainReactor 将连接分配给SubReactor
-
subreactor 将连接加入到连接队列进行监听,并创建handler进行各种事件处理
-
当有新事件发生时, subreactor 就会调用对应的handler处理
-
handler 通过read 读取数据,分发给后面的worker 线程处理
-
worker 线程池分配独立的worker 线程进行业务处理,并返回结果
-
handler收到响应的结果后,再通过send 将结果返回给client
-
Reactor主线程可以对应多个Reactor 子线程, 即MainRecator 可以关联多个SubReactor
方案优缺点说明:
优点:父线程与子线程的数据交互简单职责明确,父线程只需要接收新连接,子线程完成后续的业务处理。
缺点:编程复杂度较高
实现
客户端
package com.company;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.time.LocalDateTime;
/**
* @author zhe.xiao
* @date 2022-03-24 9:43
* @description
**/
public class ReactorClient {
public void start() throws IOException, InterruptedException {
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(12345));
socketChannel.configureBlocking(false);
socketChannel.setOption(StandardSocketOptions.TCP_NODELAY, true);
//不断的自旋、等待连接完成
while (!socketChannel.finishConnect()) {
// do
}
ByteBuffer buffer = ByteBuffer.allocate(1024);
//发送数据到服务器
for (int i = 0; i < 100; i++) {
String data = "ReactorClient hello zhe " + i + " --- " + LocalDateTime.now();
System.out.println(data);
//buffer写模式
buffer.put(data.getBytes());
//buffer读模式
buffer.flip();
socketChannel.write(buffer);
//buffer切换写模式
buffer.clear();
Thread.sleep(5000);
}
//关闭
socketChannel.shutdownOutput();
socketChannel.close();
}
public static void main(String[] args) throws IOException, InterruptedException {
new ReactorClient().start();
}
}
服务端:
package com.company;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
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.Set;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author zhe.xiao
* @date 2022-03-30 15:47
* @description
**/
public class ReactorMasterServer implements Runnable {
Selector selector;
ServerSocketChannel serverSocketChannel;
//当前的selector序号
AtomicInteger selectorIdx = new AtomicInteger(0);
//多selector
private int cpuCores = 8;
private Selector[] selectorList = new Selector[cpuCores];
//定义子Reactor及运行子Reactor的线程
private ReactorSubServer[] reactorSubServerList = new ReactorSubServer[cpuCores];
private Thread[] reactorSubThreadList = new Thread[cpuCores];
public ReactorMasterServer(int port) throws IOException {
selector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(port));
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); //接收accept事件
System.out.println("ReactorMasterServer 初始化成功");
//初始化子Reactor
initReactorSub();
}
/**
* 初始化子Reactor
*
* @throws IOException
*/
private void initReactorSub() throws IOException {
for (int i = 0; i < cpuCores; i++) {
//创建选择器
Selector selector = Selector.open();
selectorList[i] = selector;
//创建子Reactor
ReactorSubServer reactorSubServer = new ReactorSubServer(selector, serverSocketChannel, i);
reactorSubServerList[i] = reactorSubServer;
//启动线程
Thread thread = new Thread(reactorSubServer);
reactorSubThreadList[i] = thread;
}
}
@Override
public void run() {
//启动子Reactor线程
for (Thread thread : reactorSubThreadList) {
thread.start();
}
try {
while (!Thread.interrupted()) {
selector.select();
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectionKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey selectionKey = keyIterator.next();
if (selectionKey.isAcceptable()) {
new Acceptor(serverSocketChannel).run();
}
keyIterator.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 处理线程接收
*/
class Acceptor implements Runnable {
final ServerSocketChannel serverSocketChannel;
Acceptor(ServerSocketChannel serverSocketChannel) throws IOException {
this.serverSocketChannel = serverSocketChannel;
}
@Override
public void run() {
try {
SocketChannel socketChannel = serverSocketChannel.accept();
System.out.println(socketChannel.socket().getRemoteSocketAddress().toString() + " is connected.");
if (socketChannel != null) {
socketChannel.configureBlocking(false);
//暂停子Reactor
reactorSubServerList[selectorIdx.get()].setSuspend(true);
// 使一個阻塞住的selector操作立即返回,不然的话会一直被suspend
selectorList[selectorIdx.get()].wakeup();
//针对某个selector注册事件
System.out.println("注册 Selector到索引:" + selectorIdx.get());
socketChannel.register(selectorList[selectorIdx.get()], SelectionKey.OP_READ);
//启动子Reactor
reactorSubServerList[selectorIdx.get()].setSuspend(false);
// 使一個阻塞住的selector操作立即返回,不然的话会一直被suspend
selectorList[selectorIdx.get()].wakeup();
//重置索引
selectorIdx.incrementAndGet();
if (selectorIdx.get() == selectorList.length) {
selectorIdx.set(0);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException {
Thread thread = new Thread(new ReactorMasterServer(12345));
thread.start();
}
}
/**
* 核心的Reactor服务
*/
class ReactorSubServer implements Runnable {
final Selector selector;
final ServerSocketChannel serverSocketChannel;
private int selectorIdx;
//暂停线程
private boolean suspend = false;
public ReactorSubServer(Selector selector, ServerSocketChannel serverSocketChannel, int selectorIdx) {
this.selector = selector;
this.serverSocketChannel = serverSocketChannel;
this.selectorIdx = selectorIdx;
System.out.println("启动子Reactor ReactorSubServer 线程:" + selectorIdx);
}
@Override
public void run() {
try {
while (!Thread.interrupted()) {
// System.out.println("启动子Reactor ReactorSubServer 线程 " + selectorIdx + " 暂停中");
//判断是否暂停
while (!suspend) {
selector.select();
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectionKeys.iterator();
while (keyIterator.hasNext()) {
System.out.println("启动子Reactor ReactorSubServer 线程 " + selectorIdx + " 运行中");
SelectionKey selectionKey = keyIterator.next();
if (selectionKey.isReadable()) {
new ReactorMasterHandler(selectionKey).run();
}
keyIterator.remove();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void setSuspend(boolean suspend) {
this.suspend = suspend;
}
}
/**
* 线程池处理器
*/
class ReactorMasterHandler implements Runnable {
SelectionKey selectionKey;
SocketChannel socketChannel;
private static final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 10L, TimeUnit.SECONDS, new LinkedBlockingDeque<>());
public ReactorMasterHandler(SelectionKey selectionKey) {
this.selectionKey = selectionKey;
}
@Override
public void run() {
try {
if (selectionKey.isReadable()) {
readOperate();
} else {
//写操作
}
} catch (Exception e) {
closeChannel();
}
}
/**
* 执行读
*
* @throws IOException
*/
private synchronized void readOperate() throws IOException {
socketChannel = (SocketChannel) selectionKey.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int len = 0;
while ((len = socketChannel.read(buffer)) > 0) {
String str = new String(buffer.array(), 0, len);
threadPoolExecutor.execute(new WorkThread(str));
}
}
/**
* 关闭
*/
private void closeChannel() {
selectionKey.cancel();
try {
socketChannel.close();
} catch (IOException e) {
System.out.println("close error");
}
System.out.println("关闭连接");
}
/**
* 业务逻辑交给工作线程处理
*/
static class WorkThread implements Runnable {
String input;
public WorkThread(String input) {
this.input = input;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " input : " + input);
}
}
}