基於多路複用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));
            }
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章