jdk的selector(1)

在java中如过需要用到Selector来处理Nio的情况下,需要先使用SelectorProvider的provider()方法来取得相应的SelectorProvider。

 

public static SelectorProvider provider() {
    synchronized (lock) {
        if (provider != null)
            return provider;
        return AccessController.doPrivileged(
            new PrivilegedAction<SelectorProvider>() {
                public SelectorProvider run() {
                        if (loadProviderFromProperty())
                            return provider;
                        if (loadProviderAsService())
                            return provider;
                        provider = sun.nio.ch.DefaultSelectorProvider.create();
                        return provider;
                    }
                });
    }
}

 

首先,会从系统属性当中去尝试取得相应的SelectorProvider,如果没有取得,如果在规定路径下写了相应的配置文件,则会通过ServiceLoader去尝试加载用户定义的实现类,如果也没有配置,则会采用默认的DefaultSelectorProvider的creat()方法来获取默认的SelectorProvider。

 

public static SelectorProvider create() {
    return new WindowsSelectorProvider();
}

这里直接返回了的是WindowsSelectorProvider,也就是说如果没有进行任何的配置,则会采用的是WindowsSelectorProvider,其构造方法就是空的,并没有任何实现。在获得了相应的SelectorProvider之后,调用openSelector()获得相应的Selector。以默认情况为例子。

public AbstractSelector openSelector() throws IOException {
    return new WindowsSelectorImpl(this);
}

这里也就说明,默认情况下,采用的就是这个WindowsSelectorImpl。
 

private final Pipe wakeupPipe = Pipe.open();

WindowsSelectorImpl(SelectorProvider var1) throws IOException {
    super(var1);
    this.wakeupSourceFd = ((SelChImpl)this.wakeupPipe.source()).getFDVal();
    SinkChannelImpl var2 = (SinkChannelImpl)this.wakeupPipe.sink();
    var2.sc.socket().setTcpNoDelay(true);
    this.wakeupSinkFd = var2.getFDVal();
    this.pollWrapper.addWakeupSocket(this.wakeupSourceFd, 0);
}

从构造方法可以看出,首先会需要用到wakeupPipe,而这个成员的取得需要Pipe调用open()方法。

public static Pipe open() throws IOException {
    return SelectorProvider.provider().openPipe();
}

 

直接调用了SelectorProvider的openPipe()方法。

 

public Pipe openPipe() throws IOException {
    return new PipeImpl(this);
}

openPipe()方法实现在了WindowsSelectorProvider的父类SelectorProviderImpl类中。

openPipe()的实现调用了pipeImpl的构造方法。

static {
    Util.load();
    byte[] var0 = new byte[8];
    boolean var1 = IOUtil.randomBytes(var0);
    if(var1) {
        rnd = new Random(ByteBuffer.wrap(var0).getLong());
    } else {
        rnd = new Random();
    }

}


PipeImpl(SelectorProvider var1) throws IOException {
    try {
        AccessController.doPrivileged(new PipeImpl.Initializer(var1));
    } catch (PrivilegedActionException var3) {
        throw (IOException)var3.getCause();
    }
}

首先,在PipeImpl的静态块中会产生一个随机数保存。

然后在其构造方法中,只是通过AcessController调用了doPrivileged()方法会new一个PipeImpl中内部类Initializer。这个方法会调用传入的类所实现的run()方法,并保证其内部所涉及的权限问题。那么,可以看到其run()方法。

public Void run() throws IOException {
    ServerSocketChannel var1 = null;
    SocketChannel var2 = null;
    SocketChannel var3 = null;

    try {
        InetAddress var4 = InetAddress.getByName("127.0.0.1");

        assert var4.isLoopbackAddress();

        var1 = ServerSocketChannel.open();
        var1.socket().bind(new InetSocketAddress(var4, 0));
        InetSocketAddress var20 = new InetSocketAddress(var4, var1.socket().getLocalPort());
        var2 = SocketChannel.open(var20);
        ByteBuffer var6 = ByteBuffer.allocate(8);
        long var7 = PipeImpl.rnd.nextLong();
        var6.putLong(var7).flip();
        var2.write(var6);

        while(true) {
            var3 = var1.accept();
            var6.clear();
            var3.read(var6);
            var6.rewind();
            if(var6.getLong() == var7) {
                PipeImpl.this.source = new SourceChannelImpl(this.sp, var2);
                PipeImpl.this.sink = new SinkChannelImpl(this.sp, var3);
                return null;
            }

            var3.close();
        }
    } catch (IOException var18) {
        try {
            if(var2 != null) {
                var2.close();
            }

            if(var3 != null) {
                var3.close();
            }
        } catch (IOException var17) {
            ;
        }

        IOException var5 = new IOException("Unable to establish loopback connection");
        var5.initCause(var18);
        throw var5;
    } finally {
        try {
            if(var1 != null) {
                var1.close();
            }
        } catch (IOException var16) {
            ;
        }

    }
}

在其run()方法中,首先会尝试去构造两条SocketChannel来来联通成一条ServerSocketChannel。首先,会调用ServerSocketChannel的open()方法,其中会通过刚刚的SelectorProvider的openServerSocketChannel()来打开一个,其方法的具体实现写在了SelectorProviderImpl中,直接返回了一个ServerSocketChannelImpl的构造方法。

ServerSocketChannelImpl(SelectorProvider var1) throws IOException {
    super(var1);
    this.fd = Net.serverSocket(true);
    this.fdVal = IOUtil.fdVal(this.fd);
    this.state = 0;
}

 

在其构造方法中,会新建一个socket并且得到他的fd和fdVal。

 

之后该ServerSocketChannelImpl新生成的socket会绑定本机的0号端口。之后会根据这个socket的ip和端口去生成一个新的SocketChannel,在两者都创建完毕之后,会将一开始PipeImpl的静态块中生成的随机数从第二个SocketChannel发送到第一个,之后会在不断地循环中去等待第一个接收到信息并与发送的随机数验证,如果无误,说明一条Pipe被成功建立起来。

在成功建立起来之后,回到WindowsSelectorImpl的构造方法,将会保存PipeImpl的sink端的socket的fdVal,而将会把source端的fdVal保存在pollWrpper中。

Selector的创建完毕。

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值