基于多路复用IO的Reactor模型实现

对NIO的了解请看我上篇博客,此处不作过多叙述

https://blog.csdn.net/CSDNzhangtao5/article/details/103023972

Reactor模式是一种事件处理模式,单个或多个事件(Event)并发地投递到事件处理服务(Service Handler),事件处理服务将事件进行分离,同步的将他们分发到对应的事件处理器中去处理。把事件的产生于事件的处理分离,且完全异步,能最大性能的提升事件的响应与事件的处理能力

                                                                         Reactor模式:  

request都放在一个列队里,由对应的handler去各自消费。可以理解为基于事件驱动型的消息订阅    

大名鼎鼎的netty通信框架就是基于Reactor模型做的线程模型,能较好的支持高并发的通信请求。

netty线程模型:

简单的自己动手实现一个基于Reactor模型的通信服务端:基于阻塞队列,将连接的channel放入工作线程的队列里,由工作线程各自去消费自己的队列里的channel然后注册到系统内核,由各自工作线程处理channel的事件

import org.springframework.core.NestedExceptionUtils;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
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.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;


public class NIOTest {

    //指定ByteBuffer缓冲区大小
    static ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

    //储存io事件处理线程
    private static final Set<WorkThread> selectorThreads = new HashSet<>();

    static int defaultThreads;

    static {
        defaultThreads = Runtime.getRuntime().availableProcessors() * 2;
    }

    public static void main(String[] args) throws Exception {

        //开放服务端4003端口
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        ServerSocket serverSocket = serverSocketChannel.socket();
        serverSocket.bind(new InetSocketAddress(4003));
        
        //创建事件处理线程池,专门处理IO事件的读、写
        buildWorkThread(defaultThreads);
        start();

        //开辟一个线程专门处理线程的连接事件
        new Thread(() -> {


            Collection<WorkThread> workThreads = Collections.unmodifiableCollection(selectorThreads);
            Iterator<WorkThread> workThreadIterator = workThreads.iterator();

            try {
                //创建一个selector 查询器
                Selector selector = Selector.open();
                //将通道设置为非阻塞
                serverSocketChannel.configureBlocking(false);
                ///将端口的channel连接事件注册给selector 
                serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

                while (true) {
                    //向系统内核查询有连接事件的注册channel,若没有则阻塞
                    selector.select();
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    
                    //若工作事件池遍历完成,重头开始遍历工作线程池
                    if (!workThreadIterator.hasNext()) {
                        workThreadIterator = workThreads.iterator();
                    }

                    WorkThread workThread = workThreadIterator.next();
                      
                    //遍历系统内核返回的连接事件
                    Iterator<SelectionKey> iterator = selectionKeys.iterator();
                    while (iterator.hasNext()) {
                        iterator.next();
                        iterator.remove();
                        //拿到连接的channel,放到工作线程池里的队列
                        SocketChannel socket = serverSocketChannel.accept();
                        workThread.offer(socket);
                    }

                    workThread.wakeup();
                }

            } catch (IOException e) {
                System.out.println(e.getMessage());
            }
        }).start();

    }

    //创建若干工作线程
    static void buildWorkThread(int workNum) throws Exception {
        int i = 0;
        while (i++ < workNum) {
            selectorThreads.add(new WorkThread());
        }
    }
    
    //启动工作线程
    static void start() {
        Iterator<WorkThread> iterator = selectorThreads.iterator();
        while (iterator.hasNext()) {
            iterator.next().start();
        }
    }

    static class WorkThread extends Thread {

        private final Selector selector;
        private final BlockingQueue<SocketChannel> blockingQueue = new LinkedBlockingDeque<>();
        
        //对象实例化时,创建一个查询器
        WorkThread() throws Exception {
            selector = Selector.open();
        }

        public void wakeup() {
            selector.wakeup();
        }

        public void offer(SocketChannel socketChannel) {
            blockingQueue.offer(socketChannel);
        }

        @Override
        public void run() {
            try {

                while (true) {
                    
                    //从队列里取出连接channel
                    SocketChannel socket = blockingQueue.poll();
                    
                    //向系统内核注册读事件
                    if (null != socket) {
                        socket.configureBlocking(false);
                        socket.register(selector, SelectionKey.OP_READ);
                    }

                    selector.select();
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();

                    Iterator<SelectionKey> iterator = selectionKeys.iterator();
                    while (iterator.hasNext()) {
                        SelectionKey selectionKey = iterator.next();
                        selectionKeys.remove(selectionKey);
                        //获取有读事件的channel
                        if (selectionKey.isReadable()) {

                            SocketChannel channel = (SocketChannel) selectionKey.channel();

                            if (null != channel) {

                                byteBuffer.clear();
                                
                                //将刘数据读取到用户缓冲区
                                channel.read(byteBuffer);
                                
                                //将byteBuffer读取位置设置为0
                                byteBuffer.flip();
                                
                                //取出字节
                                int limit = byteBuffer.limit();
                                byte[] bytes = new byte[limit];
                                byteBuffer.get(bytes);

                                System.out.println(new String(bytes, "utf-8"));
                                 
                                //将关注事件设为可写状态
                                selectionKey.interestOps(SelectionKey.OP_WRITE);
                            }
                        }
                         
                        //开始向channel写入回复消息
                        if (selectionKey.isWritable()) {

                            SocketChannel channel = (SocketChannel) selectionKey.channel();

                            byteBuffer.clear();
                            byteBuffer.put("hello".getBytes());

                            byteBuffer.flip();
                            channel.write(byteBuffer);

                            selectionKey.interestOps(SelectionKey.OP_READ);
                        }

                    }
                }

            } catch (Exception e) {
                System.out.println(NestedExceptionUtils.getRootCause(e));
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/CSDNzhangtao5/article/details/103058530
今日推荐