Spring架构篇--2.5.2 远程通信基础Select 源码篇--window--sokcet.register

前言:通过Selector.open() 获取到Selector 的选择器后,服务端和客户的socket 都可以通过register 进行socker 的注册;

服务端 ServerSocketChannel 的注册:

  ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
  serverSocketChannel.configureBlocking(false);// 设置非阻塞
  serverSocketChannel.socket().bind(new InetSocketAddress(8080));
  // 连接事件注册到多路复用
  serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

ServerSocketChannel 的类关系:
1)ServerSocketChannelImpl extends ServerSocketChannel implements SelChImpl;
2)ServerSocketChannel extends AbstractSelectableChannel implements NetworkChannel;
3) SelChImpl extends Channe;

先看下ServerSocketChannel 实例的初始化: ServerSocketChannel.open()
ServerSocketChannel 类:

public static ServerSocketChannel open() throws IOException {
    return SelectorProvider.provider().openServerSocketChannel();
}

可以看到先拿到了Select.open() 时创建的SelectorProvider 实例,然后在调用openServerSocketChannel;
SelectorProviderImpl 类:

 public ServerSocketChannel openServerSocketChannel() throws IOException {
 	// 创建ServerSocketChannelImpl 实例
    return new ServerSocketChannelImpl(this);
}

public SocketChannel openSocketChannel() throws IOException {
    return new SocketChannelImpl(this);
}

ServerSocketChannelImpl 类:

 private static NativeDispatcher nd;
 private final FileDescriptor fd;
 private int fdVal;
 private volatile long thread = 0L;
 private final Object lock = new Object();
 private final Object stateLock = new Object();
 private static final int ST_UNINITIALIZED = -1;
 private static final int ST_INUSE = 0;
 private static final int ST_KILLED = 1;
 private int state = -1;
 private InetSocketAddress localAddress;
 private boolean isReuseAddress;
 ServerSocket socket;

 ServerSocketChannelImpl(SelectorProvider var1) throws IOException {
 	// 传递创建的 SelectorProvider 实例
     super(var1);
     this.fd = Net.serverSocket(true);
     this.fdVal = IOUtil.fdVal(this.fd);
     this.state = 0;
 }

可以看到 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();中 serverSocketChannel 实际指向的是其子类(ServerSocketChannelImpl)对象。
要说明的是:ServerSocketChannel ssc = ServerSocketChannel.open()创建的这个新的Channel中的Socket是最初的,必须对这个Socket通过bind方法绑定指定的地址之后才能接收连接;

再来看服务端socket 的建立: serverSocketChannel.socket().bind(new InetSocketAddress(8080));
serverSocketChannel.socket():
ServerSocketChannelImpl 类中:

public ServerSocket socket() {
  synchronized(this.stateLock) {
  		 // 加锁保证 同一个ServerSocketChannel socket 的唯一性
        if (this.socket == null) {
            this.socket = ServerSocketAdaptor.create(this);
        }

        return this.socket;
    }
}

serverSocketChannel.socket().bind() 绑定要监听的端口;

接下来看serverSocketChannel实例的注册:
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
SelectableChannel 类中register 方法返回注册的SelectionKey:

 public final SelectionKey register(Selector sel, int ops)
        throws ClosedChannelException
    {
        return register(sel, ops, null);
    }

调用: AbstractSelectableChannel 类中register 方法:

 public final SelectionKey register(Selector sel, int ops,
                                       Object att)
        throws ClosedChannelException
{
    synchronized (regLock) {
    	// 获取锁
        if (!isOpen())// serverSocketChannel 通道是否打开
            throw new ClosedChannelException();
        if ((ops & ~validOps()) != 0)// serverSocketChannel 的操作行验证
            throw new IllegalArgumentException();
        if (blocking)// 如果建立的serverSocketChannel 通道是阻塞的直接抛出异常
            throw new IllegalBlockingModeException();
        //  当前通道有没在 Selector进行过注册,如果已经注册则修改属性后直接返回
        SelectionKey k = findKey(sel);
        if (k != null) {
            k.interestOps(ops);
            k.attach(att);
        }
        // 当前通道没有在当前selector 注册
        if (k == null) {
            // New registration
            synchronized (keyLock) {
                if (!isOpen())
                    throw new ClosedChannelException();
                // 当前管道注册到selector 选择器上
                k = ((AbstractSelector)sel).register(this, ops, att);
                addKey(k);
            }
        }
        return k;
    }
}

validOps:

public final int validOps() {
    return SelectionKey.OP_ACCEPT;
}

再来看下 ((AbstractSelector)sel).register(this, ops, att):
实现将当前管道注册到当前的Selector 上并返回SelectionKey

protected final SelectionKey register(AbstractSelectableChannel var1, int var2, Object var3) {
  if (!(var1 instanceof SelChImpl)) {
        throw new IllegalSelectorException();
    } else {
    	// 新建 SelectionKeyImpl 赋值属性
        SelectionKeyImpl var4 = new SelectionKeyImpl((SelChImpl)var1, this);
        var4.attach(var3);
        synchronized(this.publicKeys) {
        	// 防止并发多个管道同时 向selector 注册的安全性问题
            this.implRegister(var4);
        }

        var4.interestOps(var2);
       // 返回新建的SelectionKey 对新
        return var4;
    }
}

SelectionKeyImpl的构造方法:可以看出将当前selector 和要注册的管道封装到了SelectionKeyImpl 对象中

final SelChImpl channel;
public final SelectorImpl selector;
 private int index;
 private volatile int interestOps;
 private int readyOps;

 SelectionKeyImpl(SelChImpl var1, SelectorImpl var2) {
     this.channel = var1;
     this.selector = var2;
 }

继续看 this.implRegister(var4) 具体的注册方法:
WindowsSelectorImpl类

 protected void implRegister(SelectionKeyImpl var1) {
 // 传入上一步封装的SelectionKeyImpl 
 synchronized(this.closeLock) {
 		// 获取selector 的关闭锁,防止正在注册的时候 ,selector关闭
        if (this.pollWrapper == null) {
            throw new ClosedSelectorException();
        } else {
        	// SelectionKeyImpl  管道数组是否需要进行扩容
            this.growIfNeeded();
            // 当前管道放入channelArray数组中
            this.channelArray[this.totalChannels] = var1;
            var1.setIndex(this.totalChannels);
            this.fdMap.put(var1);
            // publicKeys 增加注册的管道SelectionKey
            this.keys.add(var1);
            // 管道增加到 pollWrapper
            this.pollWrapper.addEntry(this.totalChannels, var1);
            // 管道数量增加
            ++this.totalChannels;
        }
    }
}

将管道放入到channelArray 和pollWrapper 中,并增加管道的数量;

growIfNeeded 扩容方法:

private void growIfNeeded() {
  if (this.channelArray.length == this.totalChannels) {
  		// 2 倍扩容
        int var1 = this.totalChannels * 2;
        SelectionKeyImpl[] var2 = new SelectionKeyImpl[var1];
        System.arraycopy(this.channelArray, 1, var2, 1, this.totalChannels - 1);
        this.channelArray = var2;
        this.pollWrapper.grow(var1);
    }
	// 辅助线程的数量,当注册到selector 的数量每次达到1024个,就将辅助线程+1
    if (this.totalChannels % 1024 == 0) {
        this.pollWrapper.addWakeupSocket(this.wakeupSourceFd, this.totalChannels);
        ++this.totalChannels;
        ++this.threadsCount;
    }

}

通过register 可以看出,它的作用就是将管道注册到selector上,selector 中的publicKeys 记录所有注册的SelectionKey;

再来看下客户端的注册:

  SocketChannel socketChannel = SocketChannel.open();
 socketChannel.configureBlocking(false);
 socketChannel.connect(new InetSocketAddress(8080));
 // 连接事件注册到多路复用
 socketChannel.register(selector, SelectionKey.OP_CONNECT);

SocketChannel.open() 打开连接:

public static SocketChannel open() throws IOException {
    return SelectorProvider.provider().openSocketChannel();
}

SelectorProviderImpl 类中获取socket:

public SocketChannel openSocketChannel() throws IOException {
    return new SocketChannelImpl(this);
}

SocketChannelImpl 的构造方法:

private static NativeDispatcher nd;
    private final FileDescriptor fd;
    private final int fdVal;
    private volatile long readerThread = 0L;
    private volatile long writerThread = 0L;
    private final Object readLock = new Object();
    private final Object writeLock = new Object();
    private final Object stateLock = new Object();
    private boolean isReuseAddress;
    private static final int ST_UNINITIALIZED = -1;
    private static final int ST_UNCONNECTED = 0;
    private static final int ST_PENDING = 1;
    private static final int ST_CONNECTED = 2;
    private static final int ST_KILLPENDING = 3;
    private static final int ST_KILLED = 4;
    private int state = -1;
    private InetSocketAddress localAddress;
    private InetSocketAddress remoteAddress;
    private boolean isInputOpen = true;
    private boolean isOutputOpen = true;
    private boolean readyToConnect = false;
    private Socket socket;

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

可以看到 new SocketChannelImpl(this)也仅仅是做了初始化,所以返回的SocketChannel 要有自己建立连接的操作;
继续看 socketChannel.register(selector, SelectionKey.OP_CONNECT);
同样调用AbstractSelectableChannel 的register 完成注册:

 public final SelectionKey register(Selector sel, int ops,
                                       Object att)
        throws ClosedChannelException
    {
        synchronized (regLock) {
            if (!isOpen())//  检查SocketChannel  是否建立连接
                throw new ClosedChannelException();
            if ((ops & ~validOps()) != 0)// 检查SocketChannel 的操作符
                throw new IllegalArgumentException();
            if (blocking)// 检查SocketChannel  通道是否阻塞
                throw new IllegalBlockingModeException();
                // 当前SocketChannel 通道是否已经注册到 当前的selector 对象上
            SelectionKey k = findKey(sel);
            if (k != null) {
                k.interestOps(ops);
                k.attach(att);
            }
            if (k == null) {
                // New registration
                synchronized (keyLock) {
                    if (!isOpen())
                        throw new ClosedChannelException();
                    k = ((AbstractSelector)sel).register(this, ops, att);
                    addKey(k);
                }
            }
            return k;
        }
    }

总结:
1 服务端 ServerSocketChannel.open() 和客户端的SocketChannel.open() 只是做了初始化,它们的连接并没有建立;
2 register 方法用来将当前的通道注册到selector对象上,selector 的WindowsSelectorImpl 实例记录了注册的通道信息;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值