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
- Binding port
bind-> NetworkChannel
- Register the multiplexer and set the blocking model
Register, configureBlocking -> SelectableChannel
- Accept connections from clients
accept-> 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
- Connecting to the Server
connect -> SocketChannel
- Read and write
bytebuffer -> 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