模拟NettyGroupEvent

以下图则是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();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值