In-depth understanding of NIO (c)

Welcome back to the source to see the explosion Gan ™ Series

After watching the first two series, I believe we have a certain understanding of the NIO, then we take a deep source code to interpret it, here is my version of OpenJDK-8u60, also suggest that you put next years and I ide look would be better understood together. (This introduces the Selector, Buffer first article mentioned that, Channel but also some method of operation Buffer only, not mentioned here, we are interested can see for yourself)

 

open()

// 1. Create Selector 
Selector Selector = Selector.open ();

First, we analyze the open method:

// Selector 
public  static Selector Open () throws IOException {
     // here the static method provider will use DefaultSelectorProvider.create (); method of selecting a system based on SelectorProvider
     // is WindowsSelectorProvider windows platform, then,
     // Linux platform is a EPollSelectorProvider, here analysis of major Linux platform
     // the openSelector method after (a'll see below) will return as a EPollSelectorImpl achieve Selector, we generally refer to the Selector is it 
    return SelectorProvider.provider () the openSelector ().;
}

// EPollSelectorProvider
public AbstractSelector openSelector() throws IOException {
    return new EPollSelectorImpl(this);
}

Followed EPollSelectorImpl constructor:

EPollSelectorImpl(SelectorProvider sp) throws IOException {
    super(sp);
    long pipeFds = IOUtil.makePipe(false);
    fd0 = (int) (pipeFds >>> 32);
    fd1 = ( int ) pipeFds;
     // other I also do not understand, we go directly to the constructor of this EPollArrayWrapper 
    pollWrapper = new new EPollArrayWrapper ();
    pollWrapper.initInterrupt(fd0, fd1);
    fdToKey = new HashMap<>();
}

// EPollArrayWrapper 
EPollArrayWrapper () throws IOException {
     // direct look here, here calling out a package of Linux-api: epoll_create, this thing can probably be understood as a selector, detailed in the next chapter we explain 
    epfd = epollCreate () ;
}

 

So in fact Selector method is probably on a package epoll_create () method, of course, also call for a moment epoll_ctl () , I also do not understand why call it, has not found any data, not analyzed

 

register()

// 5. The channel registered on the selector, listen for connection event 
serverSocketChannel.register (selector, SelectionKey.OP_ACCEPT);

Next, we analyze the channel registration method to register on Selector

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

// AbstractSelectableChannel
public final SelectionKey register(Selector sel, int ops,
                                   Object to)
        throws ClosedChannelException
{
    // 212 rows, the remaining deleted 
    K = ((the AbstractSelector) SEL) .register ( the this , OPS, ATT);
                
}

// SelectorImpl
protected final SelectionKey register(AbstractSelectableChannel ch,
                                      int ops,
                                      Object attachment)
{
    IF ((CH! the instanceof SelChImpl))
         the throw  new new IllegalSelectorException ();
     // generate SelectorKey hashmap stored in the total after acquiring 
    SelectionKeyImpl K = new new SelectionKeyImpl ((SelChImpl) CH, the this );
     // the attach of the user wants to store Object 
    k.attach (Attachment);
     // call implRegister subclass, the next go where 
    the synchronized (publickeys) {
        implRegister(k);
    }
    // set the focus of the Option 
    k.interestOps (OPS);
     return k;
}

 

protected void implRegister(SelectionKeyImpl ski) {
        if (closed)
            throw new ClosedSelectorException();
        CH SelChImpl = ski.channel;
         // get Channel corresponding to fd, because under linux socket will be treated as a file, there will be fd 
        int fd = Integer.valueOf (ch.getFDVal ());
        fdToKey.put(fd, ski);
        // call pollWrapper add method to add the channel to the monitoring list of fd 
        pollWrapper.add (fd);
         // save to the HashSet, keys are the member variable SelectorImpl 
        keys.add (ski);
}

 

Call the registermethod does not involve EpollArrayWrappernative method epollCtlcall, because they will call this method to defer to the Selectprocess went.

 

select()

// Get the number of available channel 
int readyChannels the selector.select = ();

Next, we analyze the select () method

// SelectorImpl
public int select(long timeout)
        throws IOException
{
    . . . .
    return lockAndDoSelect((timeout == 0) ? -1 : timeout);
}

// SelectorImpl
private int lockAndDoSelect(long timeout) throws IOException {
    . . . .
    return doSelect(timeout);
}
// EPollSelectorImpl
protected int doSelect(long timeout) throws IOException {
    .....
    try {
        ....
        // call poll method, called the bottom and the native epollCtl epollWait method 
        pollWrapper.poll (timeout);
    } finally {
        ....
    }
    ....
    // update selectedKeys, selectedKeys function after preparing for 
    int numKeysUpdated = updateSelectedKeys ();
    ....
    return numKeysUpdated;
}
// EPollArrayWrapper 
int poll ( Long timeout) throws IOException {
     // realize there is call epoll_ctl () method to register fd and interest previously stored in the register method Channel of event types 
    updateRegistrations ();
     // Here is the call epollWait method waits generate interest in the event, leading thread blocks 
    Updated = epollWait (pollArrayAddress, NUM_EPOLLEVENTS, timeout, epfd);
    . . . .
}

 

epollCtl and epollWait method mentioned above, we will talk about in detail in the next chapter, do not speak here first.

In short we can know Selector is actually the api Linux package provided by it, that is epollCreate , epollCtl and epollWait method.

 

selectedKeys()

// Get the available channel set 
Set <SelectionKey> selectionKeys = selector.selectedKeys ( );

Next we look at selectedKeys () method:

// SelectorImpl
 // by Util.ungrowableSet generated, can not be added, can reduce the 
Private the Set <the SelectionKey> publicSelectedKeys;
 public the Set <the SelectionKey> the selectedKeys () {
    ....
    return publicSelectedKeys;
}

Very strange ah, how directly returned publicSelectedKeys , is it in the process of implementation of the select function has been modified this variable it? PublicSelectedKeys this object is actually selectedKeys a copy of the variable, you can SelectorImpl find them both in the constructor relations, we look back at updateSelectedKeys select the method:

Private  int updateSelectedKeys () {
     // update the number of keys, or the number of said generated event 
    int entries It = pollWrapper.updated; 
     int numKeysUpdated 0 = ;
     for ( int I = 0; I <entries It; I ++ ) {
         // Channel fd corresponding to the 
        int nextFD = pollWrapper.getDescriptor (I);
         // find the corresponding through the SelectionKey fd 
        SelectionKeyImpl Ski = fdToKey.get (Integer.valueOf (nextFD));
         IF ! (Ski = null ) {
             int ROPS = pollWrapper.getEventOps (I);
             //SelectedKey update variables, and notifies the channel response processing in response to do 
            IF (selectedKeys.contains (Ski)) {
                 IF (ski.channel.translateAndSetReadyOps (ROPS, Ski)) {
                    numKeysUpdated++;
                }
            } else {
                ski.channel.translateAndSetReadyOps(rOps, ski);
                if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
                    selectedKeys.add(ski);
                    numKeysUpdated++;
                }
            }
        }
    }
    return numKeysUpdated;
}

 

I do not know if you are aware, if we do not first call to select (), direct selectedKeys () is not going to get any Channel, because there is no method of updating publicSelectedKeys

 

Why Netty own and from one side to achieve a new relevant NIO underlying native method? Listen founder Netty is how to say it links .

Because the level-triggered mode using the Java version of epoll, and Netty wants to use edge-triggered mode, and the Java version is not exposed epoll part of the configuration items out, for example TCP_CORK and SO_REUSEPORT.

 

 

 

 


 

 

References:

https://segmentfault.com/a/1190000017798684?utm_source=tag-newest

Guess you like

Origin www.cnblogs.com/fatmanhappycode/p/12355316.html