以下图则是Netty模型,一个BoosGroup,一个WorkerGroup。而BoosGroup负责轮询Accept事件,并处理建立链接的Channel将其注册到WorkerGroup的selector中,并且同步处理TaskQueue队列任务。
服务端代码:启动服务端
/**
* @author x y
* @description TODO
* @date 2022-03-08 9:23
*/
public class MainThread {
public static void main(String[] args) {
// 与具体的io和业务无关的主线程
// 创建管理selector线程组
SelectorGroupThread boos = new SelectorGroupThread(3);
// 一个selector只负责accept 他的工作selector负责R/W
SelectorGroupThread work = new SelectorGroupThread(3);
boos.setWork(work);
// 绑定端口
boos.bind(9999);
}
}
客户端代码: 作用链接服务端
public class ClientThread {
public static void main(String[] args) throws IOException {
for (int i=0;i<10;i++){
SocketChannel channel = null;
try {
channel = SocketChannel.open();
channel.configureBlocking(false);
channel.connect(new InetSocketAddress("localhost",9999));
} catch (IOException e) {
e.printStackTrace();
}
}
System.in.read();
}
}
处理逻辑代码之多路复用器GroupThread:
/**
* @author x y
* @description TODO
* @date 2022-03-08 16:02
*/
public class SelectorGroupThread {
SelectorThread[] selectorThreads;
AtomicInteger atomicInteger = new AtomicInteger(0);
SelectorGroupThread work = this;
// 设置多个selector
SelectorGroupThread(int num) {
selectorThreads = new SelectorThread[num];
for (int i = 0; i < selectorThreads.length; i++) {
selectorThreads[i] = new SelectorThread(this);
new Thread(selectorThreads[i]).start();
}
}
public void setWork(SelectorGroupThread work) {
this.work = work;
}
public void bind(int port) {
try {
ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(false);
server.bind(new InetSocketAddress(port));
// 考虑轮询到制定selector
nextSelector(server);
} catch (IOException e) {
e.printStackTrace();
}
}
public void nextSelector(Channel server) {
SelectorThread selectorThread = next();
selectorThread.queue.offer(server);
selectorThread.selector.wakeup(); // 唤醒阻塞的select方法
}
private SelectorThread next() {
int index = atomicInteger.incrementAndGet() % selectorThreads.length;
return selectorThreads[index];
}
public void nextWorkSelector(Channel server) {
SelectorThread selectorThread = nextWork();
selectorThread.queue.offer(server);
selectorThread.selector.wakeup(); // 唤醒阻塞的select方法
}
private SelectorThread nextWork() {
int index = atomicInteger.incrementAndGet() % work.selectorThreads.length;
return work.selectorThreads[index];
}
}
最后多路复用器代码:
/**
* @author x y
* @description TODO
* @date 2022-03-08 9:23
*/
public class SelectorThread extends ThreadLocal<LinkedBlockingQueue<Channel>> implements Runnable {
// selector线程处理器 处理注册,读 写 以及多线程的管理
Selector selector = null;
LinkedBlockingQueue<Channel> queue = get();
SelectorGroupThread sgt = null;
@Override
protected LinkedBlockingQueue<Channel> initialValue() {
return new LinkedBlockingQueue<Channel>();
}
SelectorThread(SelectorGroupThread sgt) {
try {
selector = Selector.open();
this.sgt = sgt;
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true) {
// 1 selector 处理
try {
System.err.println(Thread.currentThread().getName() + " before......" + selector.keys().size());
int num = selector.select();// 不设置超时时间则会进行阻塞 可以通过wakeup 让selector向下运行
System.err.println(Thread.currentThread().getName() + " after......" + selector.keys().size());
if (num > 0) {
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> ite = keys.iterator();
while (ite.hasNext()) {
//2 将监听的socket轮询放入
SelectionKey key = ite.next();
ite.remove();
if (key.isAcceptable()) {
// 注册
acceptHandler(key);
} else if (key.isReadable()) {
// 读取内容
readHandler(key);
}
}
}
// 3 处理其他任务
if (!queue.isEmpty()) {
Channel c = queue.take();
if (c instanceof ServerSocketChannel) {
ServerSocketChannel server = (ServerSocketChannel) c;
server.register(selector, SelectionKey.OP_ACCEPT);
}
if (c instanceof SocketChannel) {
SocketChannel client = (SocketChannel) c;
ByteBuffer byteBuffer = ByteBuffer.allocate(4096);
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ, byteBuffer);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void readHandler(SelectionKey key) {
ByteBuffer byteBuffer = (ByteBuffer) key.attachment();
byteBuffer.clear();
SocketChannel client = (SocketChannel) key.channel();
while (true) {
try {
int size = client.read(byteBuffer);
if (size > 0) {
while (byteBuffer.hasRemaining()) {
byteBuffer.flip();
client.write(byteBuffer); // 写回
byteBuffer.clear();
}
}
if (size == 0) {
// 没有读取的数据
break;
}
if (size < 0) {
// 客户端退出
System.err.println("client address : " + client.getRemoteAddress());
key.cancel();
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void acceptHandler(SelectionKey key) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
System.err.println(Thread.currentThread().getName() + " : acceptHandler");
try {
sgt.nextWorkSelector(server.accept());
} catch (IOException e) {
e.printStackTrace();
}
}
}