《Scalable IO in Java》学习笔记--- Basic Reactor Design

Classic Service Designs

跳过传统的一个client连接就开启一个线程的模式

Basic Reactor Design



Reactor线程创建一个NIO的server,将Acceptor类放到SelectionKey的attach,interestOps(SelectionKey.OP_ACCEPT),selector.select();进行阻塞监听acceot,当client连接到server中,selector.select()放行,运行dispatch方法,dispatch方法中通过attachment获取存在Acceptor的类,会运行Acceptor类的run方法,Acceptor.run获取到SockerChannel以后实例化Handler,将SelectionKey的attach改成了Handler类,同时将interestOps(SelectionKey.OP_READ),监听SelectionKey(也就是client)的读事件。

当client发送数据时selector.select()放行,运行dispatch方法,dispatch方法中通过attachment获取存在Handler类(非连接时Acceptor),Handler.run方法判断读或者写就行读写操作。


package douglea;

import com.sun.xml.internal.stream.util.ThreadLocalBufferAllocator;

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;

/**
 * @author lzming
 * @create 2019-01-12 12:15
 */
public class BaseicReactorDesign {
    public static void main(String[] args) throws IOException {
        Thread thread=new Thread(new Reactor(8080));
        thread.start();//这里新建了一个线程

        while (true);//堵塞住防止程序运行完
    }
}

class Reactor implements Runnable {
    final Selector selector;
    final ServerSocketChannel serverSocket;
    Reactor(int port) throws IOException { //Reactor初始化
        selector = Selector.open();
        serverSocket = ServerSocketChannel.open();
        serverSocket.socket().bind(new InetSocketAddress(port));
        serverSocket.configureBlocking(false); //非阻塞
        SelectionKey sk = serverSocket.register(selector, SelectionKey.OP_ACCEPT); //分步处理,第一步,接收accept事件
        sk.attach(new Acceptor()); //attach callback object, Acceptor《=这里传入的是Acceptor
    }

    public void run() {
        try {
            while (!Thread.interrupted()) {
                selector.select();
                Set selected = selector.selectedKeys();
                Iterator it = selected.iterator();
                while (it.hasNext())
                    dispatch((SelectionKey)(it.next())); //Reactor负责dispatch收到的事件
                selected.clear();
            }
        } catch (IOException ex) { /* ... */ }
    }

    void dispatch(SelectionKey k) {
        Runnable r = (Runnable)(k.attachment()); //调用之前注册的callback对象
        if (r != null)
            r.run();//这里只运行,没有start新建线程
    }

    class Acceptor implements Runnable { // inner
        public void run() {
            try {
                SocketChannel c = serverSocket.accept();
                if (c != null)
                    new Handler(selector, c);
            }
            catch(IOException ex) { /* ... */ }
        }
    }
}

final class Handler implements Runnable {
    private static final int MAXIN = 100;
    private static final int MAXOUT = 100;
    final SocketChannel socket;
    final SelectionKey sk;
    ByteBuffer input = ByteBuffer.allocate(MAXIN);
    ByteBuffer output = ByteBuffer.allocate(MAXOUT);
    static final int READING = 0, SENDING = 1;
    int state = READING;

    Handler(Selector sel, SocketChannel c) throws IOException {
        socket = c; c.configureBlocking(false);
        // Optionally try first read now
        sk = socket.register(sel, 0);
        sk.attach(this); //《=将Handler作为callback对象
        sk.interestOps(SelectionKey.OP_READ); //第二步,接收Read事件
        sel.wakeup();
    }
    boolean inputIsComplete() { /* ... */ return true;}
    boolean outputIsComplete() { /* ... */ return true;}
    void process() { /* ... */ }

    public void run() {
        try {
            if (state == READING) read();
            else if (state == SENDING) send();
        } catch (IOException ex) { /* ... */ }
    }

    void read() throws IOException {
        input.clear();
        socket.read(input);
        if (inputIsComplete()) {
            process();
            state = SENDING;
            // Normally also do first write now
            sk.interestOps(SelectionKey.OP_WRITE); //第三步,接收write事件
        }
    }
    void send() throws IOException {
        output=input;
        output.flip();
        socket.write(output);
        if (outputIsComplete()) {
            //sk.cancel(); //write完就结束了, 关闭select key
            state = READING;
            // Normally also do first write now
            sk.interestOps(SelectionKey.OP_READ); //第三步,接收write事件
        }
    }
}


上面 的实现用Handler来同时处理Read和Write事件, 所以里面出现状态判断
我们可以用State-Object pattern来更优雅的实现
//class Handler { // ...
//    public void run() { // initial state is reader
//        socket.read(input);
//        if (inputIsComplete()) {
//            process();
//            sk.attach(new Sender());  //状态迁移, Read后变成write, 用Sender作为新的callback对象
//            sk.interest(SelectionKey.OP_WRITE);
//            sk.selector().wakeup();
//        }
//    }
//    class Sender implements Runnable {
//        public void run(){ // ...
//            socket.write(output);
//            if (outputIsComplete()) sk.cancel();
//        }
//    }
//}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值