An overview of the

As we saw in file IO, when you read a file, you can create a Channel and then read ByteBuffer into the Channel. ByteBuffer is either direct memory or heap memory, and it relates to the number of copies. But in real tests,BIO and NIO performance didn’t differ that much, so why bother with NIO? The reason is the NETWORK IO level. The advantages of non-blocking IO are explained in the IO model derivation, and here’s how JAVA is implemented in detail.

Channel

Start with Channel. Network channels are divided into server Channel ServerSocketChannel and client SocketChannel

ServerSocketChannel

First, the Channel of the server is implementedNetworkChannel, you can bind a port

public interface NetworkChannel
    extends Channel
{
    NetworkChannel bind(SocketAddress local) throws IOException;
}
Copy the code

Let’s look at the implementation on the other side, SelectableChannel

public abstract class SelectableChannel
    extends AbstractInterruptibleChannel
    implements Channel
{# register oneSelector
    public abstract SelectionKey register(Selector sel, int ops, Object att)
        throws ClosedChannelException; Set blocking modepublic abstract SelectableChannel configureBlocking(boolean block)
        throws IOException;
}
Copy the code

So what a Selector is, if you’ve seen the IO model, it’s a multiplexer, and I’m going to skip over it, and the one that sets the blocking mode for this channel. Next, ServerSocketChannel

public abstract class ServerSocketChannel
    extends AbstractSelectableChannel
    implements NetworkChannel
{# create an implementation class for ServerSocketChannelpublic static ServerSocketChannel open(a) throws IOException {
        returnSelectorProvider.provider().openServerSocketChannel(); } # bind portpublic abstract ServerSocketChannel bind(SocketAddress local, int backlog)
        throws IOException; # Accept clientpublic abstract SocketChannel accept(a) throws IOException;
}
Copy the code

The ServerSocketChannel on the server side is summed up as one

  1. Binding portbind-> NetworkChannel
  2. Register the multiplexer and set the blocking modelRegister, configureBlocking -> SelectableChannel
  3. Accept connections from clientsaccept-> ServerSocketChannel

Unlike file IO, channels read and write data through ByteBuffer.

SocketChannel

Now look at the Channel on the client side

ReadableByteChannel, WritableByteChannel, must be associated with reading and writing ByteBuffer.

public interface ReadableByteChannel extends Channel {
    public int read(ByteBuffer dst) throws IOException;
}
public interface WritableByteChannel extends Channel
{
    public int write(ByteBuffer src) throws IOException;
}
Copy the code

Take a look at SocketChannel source code

public abstract class SocketChannel
    extends AbstractSelectableChannel
    implements ByteChannel.ScatteringByteChannel.GatheringByteChannel.NetworkChannel
{# create onesocketchannel
    public static SocketChannel open(a) throws IOException {
        returnSelectorProvider.provider().openSocketChannel(); } # connect to remote serverpublic abstract boolean connect(SocketAddress remote) throws IOException; # to read and writepublic abstract int write(ByteBuffer src) throws IOException;

    public abstract int read(ByteBuffer dst) throws IOException;
}
Copy the code

SocketChannel of the client

  1. Connecting to the Server connect -> SocketChannel
  2. Read and writebytebuffer -> ReadableByteChannel,WritableByteChannel

Selector

Having looked at socketchannels in general for clients and service sheets, let’s take a look at what kind of Selector the server needs to register.

public abstract class Selector implements Closeable {

    public static Selector open(a) throws IOException {
        returnSelectorProvider.provider().openSelector(); } # return IO eventsselectionKey
    public abstract Set<SelectionKey> selectedKeys(a); Blocking waits for a set of selectionkeys until one or more of them have I/O eventspublic abstract int select(a) throws IOException;

}
Copy the code

It doesn’t inherit any classes, it’s just an object that’s waiting to return a set of data, and there’s another class called SelectionKey. The idea behind SelectionKey is to bind a Channel to a Selector, right

public abstract class SelectionKey {
    
    public abstract SelectableChannel channel(a);

    public abstract Selector selector(a);

    public abstract int interestOps(a);
    
    private volatile Object attachment = null;

    public static final int OP_READ = 1 << 0;

    public static final int OP_WRITE = 1 << 2;

    public static final int OP_CONNECT = 1 << 3;

    public static final int OP_ACCEPT = 1 << 4;
}
Copy the code

The register process

The essence of a register is to create a SelectionKey, and then each selector and Channel holds a copy.Recall that Register is an abstract method of SelectableChannel. When a Channel calls register

public final SelectionKey register(Selector sel, int ops,
                                   Object att)
    throws ClosedChannelException
{
    synchronized (regLock) {
        if(! isOpen())throw new ClosedChannelException();
        if((ops & ~validOps()) ! =0)
            throw new IllegalArgumentException();
        if (blocking)
            throw newIllegalBlockingModeException(); SelectionKey k = findKey(sel);if(k ! =null) {
            k.interestOps(ops);
            k.attach(att);
        }
        if (k == null) {
            // New registration
            synchronized (keyLock) {
                if(! isOpen())throw newClosedChannelException(); K = ((AbstractSelector)sel).register(AbstractSelector)this, ops, att); # add one yourselfselectionKey
                addKey(k); }}returnk; }}Copy the code

So let’s look at the code for the register in selector

protected final SelectionKey register(AbstractSelectableChannel var1, int var2, Object var3) {
    if(! (var1instanceof SelChImpl)) {
        throw new IllegalSelectorException();
    } else{# create a selectionKey, bind channel and SelectionKeyImpl var4 =new SelectionKeyImpl((SelChImpl)var1, this); var4.attach(var3); The system call is dependent and varies by operating systemsynchronized(this.publicKeys) {
            this.implRegister(var4);
        }

        var4.interestOps(var2);
        returnvar4; }}Copy the code