netty4.0.x Source Analysis-channel__java

Source: Internet
Author: User
Tags throwable volatile

Note: The analysis of this article is based on the Netty 4.0.9final version, only the analysis of NIO, because I am more interested in socket programming. 1, channel overall organization Chart

The overall structure of the NIO channel is as follows:

2, key classes and interface analysis 2.1 Analysis based on Nioserversocketchannel

1) Channel

Channel is the top-level interface that inherits the AttributeMap, Channeloutboundinvoker, channelpropertyaccess, Comparable<channel> It is provided to developers as a specific IO capability component, including read, write, connect, and bind operations. It also provides the functionality of the channel configuration and the ability to obtain the EventLoop that channel resides in.


2) Abstractchannel

Abstractchannel implementation of the channel interface, the key code is as follows:

    Private final Channel parent;
    Private final Long hashcode = Threadlocalrandom.current (). Nextlong ();
    Private final Unsafe Unsafe;
    Private final Defaultchannelpipeline pipeline;
    Private final Channelfuture succeededfuture = new Succeededchannelfuture (this, null);
    Private final Voidchannelpromise voidpromise = new Voidchannelpromise (this, true);
    Private final Voidchannelpromise unsafevoidpromise = new Voidchannelpromise (this, false);

    Private final Closefuture closefuture = new Closefuture (this);
    private volatile socketaddress localaddress;
    private volatile socketaddress remoteaddress;
    private volatile eventloop eventloop;

    Private volatile Boolean registered;
    /** Cache for the string representation to this channel/private Boolean strvalactive;
     Private String strval;<pre name= "code" class= "java" >/** * Creates a new instance. * * @param parent of this channel. {@code null} if THere ' s no parent.
        * * Protected Abstractchannel (Channel parent) {this.parent = parent;
        unsafe = Newunsafe ();
    Pipeline = new Defaultchannelpipeline (this); }
The more important objects are pipeline and unsafe, which provide specific implementations of read,write,bind and other operations.


3) Abstractniochannel

Abstractniochannel inherits Abstractchannel, starting with the JDK socket from this class, refer to the following key code:

    Private final Selectablechannel ch;
    protected final int readinterestop;
    private volatile Selectionkey Selectionkey;
Private volatile Boolean inputshutdown; <pre name= "code" class= "Java" > @Override protected void Doregister () throws Exception {Boolean Selec
        Ted = false; for (;;)
                {try {Selectionkey = Javachannel (). Register (EventLoop (). Selector, 0, this);
            Return catch (Cancelledkeyexception e) {if (!selected) {//Force the Selector to select n  ow as the "canceled" Selectionkey may still is//cached and not removed because no select.select (..)
                    Operation was called yet.
                    EventLoop (). Selectnow ();
                selected = true;
                    else {//We forced a select operation on the selector before but the Selectionkey is still cached For whatever reason. JDK bug?
                Throw e; }
            }
        }
    }

/** * Create A new instance * * @param parent The parent {@link Channel} by which this instance is created. May is {@code null} * @param ch The underlying {@link Selectablechannel} on which it operates * @param readinterestop the OPS to set to receive data from the {@link Selectablechannel} */protected Abstractniochannel (Channel parent, Selectablech Annel ch, int readinterestop) {super (parent); this.ch = ch; this.readinterestop = readinterestop; try {Ch.configureblock ing (false); catch (IOException e) {try {ch.close ();} catch (IOException E2) {if (logger.iswarnenabled ()) {Logger.warn ("Failed To close a partially initialized socket. ", E2); } throw new Channelexception ("Failed to enter non-blocking mode.", e); } }
From the above code can be seen, here defines the real socket Channel (Selectablechannel), the event of concern, registered key. Set the socket to non-blocking, which is the key to all asynchronous Io, that is, no matter how good the framework, the underlying foundation will not change, can be seen to learn the importance of the foundation, ^_^. Focus here on the register function, which is the key to associating channel and event loops. Each event loop has its own selector,channel is actually registered in the corresponding EventLoop selector, which is also the basis for NIO socket programming.

From this class you can see how the channel of the Netty is associated with the NIO channel of the socket, and how channel is associated with the EventLoop.


4) Abstractniomessagechannel

This class inherits Abstractniochannel, primarily by providing a Newunsafe method that returns an instance of the Niomessageunsafe object (the Read method is implemented). The Doreadmessages and dowritemessage two abstract methods are also defined.


5) Serversocketchannel and Serverchannel

The two interfaces are primarily defined as a config method and a way to get the network address.


6) Nioserversocketchannel

Nioserversocketchannel inherits Abstractniomessagechannel, implements Serversocketchannel, and it is a concrete class that is provided to developers to use.

/** * A {@link Io.netty.channel.socket.ServerSocketChannel} implementation which uses * NIO selector based
 N to accept new connections. * * public class Nioserversocketchannel extends Abstractniomessagechannel implements Io.netty.

    Channel.socket.ServerSocketChannel {private static final channelmetadata METADATA = new Channelmetadata (false);

    Private static final Internallogger logger = internalloggerfactory.getinstance (Nioserversocketchannel.class);
        private static Serversocketchannel Newsocket () {try {return serversocketchannel.open (); catch (IOException e) {throw new Channelexception ("Failed to open a server socket.", E
        );

    } private final Serversocketchannelconfig config; /** * Create A new instance */Public Nioserversocketchannel () {super (NULL, Newsocket (), Selectionk ey.
        Op_accept); Config = new DefaultserverSocketchannelconfig (this, Javachannel (). socket ()); } @Override protected Serversocketchannel Javachannel () {return (Serversocketchannel) Super.javachannel (
    ); @Override protected void Dobind (SocketAddress localaddress) throws Exception {Javachannel (). socket (). b
    IND (LocalAddress, Config.getbacklog ());
    @Override protected void Doclose () throws Exception {Javachannel (). Close (); @Override protected int doreadmessages (list<object> buf) throws Exception {Socketchannel ch = ja

        Vachannel (). Accept ();
                try {if (ch!= null) {Buf.add (new Niosocketchannel (this, ch));
            return 1;

            } catch (Throwable t) {Logger.warn ("Failed to create a new channel from a accepted socket.", t);
            try {ch.close (); catch (Throwable T2) {Logger.warn ("Failed to close a socket.", T2);
            } return 0; }//Unnecessary stuff @Override protected Boolean doconnect (SocketAddress remoteaddress, Socket
    Address localaddress) throws Exception {throw new unsupportedoperationexception (); @Override protected void Dofinishconnect () throws Exception {throw new Unsupportedoperationexception ()
    ;
    @Override protected socketaddress RemoteAddress0 () {return null;
    @Override protected void Dodisconnect () throws Exception {throw new unsupportedoperationexception ();
        @Override protected Boolean dowritemessage (Object msg, channeloutboundbuffer in) throws Exception {
    throw new Unsupportedoperationexception ();
 }
}
From this specific class, we can see that the JDK function Serversocketchannel.open () is invoked, and the underlying Serversocketchannel object is generated. Nioserversocketchannel and Serversocketchannel are associated, and events of interest are passed op_accept to the parent class. Realize the Doreadmessage function, is actually accept a socketchanel.

2.2 analysis based on Niosocketchannel

The classes and interfaces introduced in Nioserversocketchannel are not described here. It's about the same as Nioserversocketchannel, but it's based on byte.

1) Abstractniobytechannel

This class inherits Abstractniochannel and provides a Newunsafe method that returns an instance of the Niobyteunsafe object (the Read method is implemented). The doreadbytes and dowritebytes two abstract methods are also defined.


2) Socketchannel

This interface inherits the channel interface, defines multiple shutdown methods, and a parent method that returns the corresponding Serversocketchannel of the Socketchannel.


3) Niosocketchannel

This class inherits Abstractniobytechannel and implements the Socketchannel interface, which is a concrete class that is provided for developers to use.

/** * {@link Io.netty.channel.socket.SocketChannel} which uses NIO selector based. * * public class Niosocketchannel extends Abstractniobytechannel implements Io.netty.channel.socket.SocketChannel {PR

    Ivate static final Channelmetadata METADATA = new Channelmetadata (false);
        private static Socketchannel Newsocket () {try {return socketchannel.open ();
        catch (IOException e) {throw new Channelexception ("Failed to open a socket.", e);

    } private final Socketchannelconfig config;
    /** * Create A new instance * * Niosocketchannel () {This (Newsocket ());
     }/** * Create A new instance using the given {@link Socketchannel}.
    * * Public Niosocketchannel (Socketchannel sockets) {This (null, socket); /** * Create A new instance * * @param parent the {@link Channel} which created this instance or {@code NULL} if it was createdBy the user * @param socket the {@link Socketchannel} which'll be used/public Niosocketchannel (Chann
        El Parent, Socketchannel socket) {Super (parent, socket);
    Config = new Defaultsocketchannelconfig (this, socket.socket ());
    @Override protected Socketchannel Javachannel () {return (Socketchannel) Super.javachannel ();
        @Override public boolean isactive () {Socketchannel ch = javachannel ();
    Return Ch.isopen () && ch.isconnected ();
    @Override public boolean Isinputshutdown () {return super.isinputshutdown ();
    @Override public inetsocketaddress localaddress () {return (inetsocketaddress) super.localaddress (); @Override public inetsocketaddress remoteaddress () {return (inetsocketaddress) super.remoteaddress (
    ); @Override public boolean Isoutputshutdown () {return Javachannel (). Socket (). Isoutputshutdown () | |!IsActive ();
    @Override public channelfuture Shutdownoutput () {return shutdownoutput (Newpromise ()); @Override Public channelfuture shutdownoutput (final channelpromise promise) {EventLoop loop = Eventloo
        P ();
                if (Loop.ineventloop ()) {try {Javachannel (). Socket (). Shutdownoutput ();
            Promise.setsuccess ();
            catch (Throwable t) {promise.setfailure (t); 
                    } else {Loop.execute (new Runnable () {@Override public void run () {
                Shutdownoutput (Promise);
        }
            });
    return promise;  @Override protected Boolean doconnect (socketaddress remoteaddress, socketaddress localaddress) throws Exception
        {if (localaddress!= null) {Javachannel (). Socket (). bind (localaddress);
        Boolean success = false; try {
            Boolean connected = Javachannel (). connect (remoteaddress);
            if (!connected) {Selectionkey (). Interestops (Selectionkey.op_connect);
            } success = true;
        return connected;
            finally {if (!success) {doclose (); @Override protected void Dofinishconnect () throws Exception {if!javachannel (). Finish
        Connect ()) {throw new Error ();
    } @Override protected void Dodisconnect () throws Exception {doclose ();
    @Override protected void Doclose () throws Exception {Javachannel (). Close (); @Override protected int doreadbytes (Bytebuf bytebuf) throws Exception {return bytebuf.writebytes (JavaC
    Hannel (), bytebuf.writablebytes ()); @Override protected int dowritebytes (Bytebuf buf) throws Exception {final int expectedwrittenbytes = b Uf.readablebytES ();
        Final int writtenbytes = Buf.readbytes (Javachannel (), expectedwrittenbytes);
    return writtenbytes; @Override protected Long Dowritefileregion (Fileregion region) throws Exception {final long position =
        Region.transfered ();
        Final Long writtenbytes = Region.transferto (Javachannel (), position);
    return writtenbytes; } @Override protected void Dowrite (Channeloutboundbuffer in) throws Exception {for (;;)
            {//Do non-gathering write to a single-buffer case.
            Final int msgcount = In.size ();
                if (Msgcount <= 1) {super.dowrite (in);
            Return
            }//Ensure the pending writes are made of Bytebufs only.
            bytebuffer[] niobuffers = In.niobuffers ();
                if (niobuffers = = null) {super.dowrite (in);
            Return
         int niobuffercnt = In.niobuffercount ();   Long expectedwrittenbytes = In.niobuffersize ();
            Final Socketchannel ch = javachannel ();
            Long writtenbytes = 0;
            Boolean done = false; for (int i = config (). Getwritespincount ()-1; I >= 0; I-) {final Long localwrittenbytes = Ch.write (
                Niobuffers, 0, niobuffercnt);
                if (localwrittenbytes = = 0) {break;
                } expectedwrittenbytes-= Localwrittenbytes;
                Writtenbytes + = Localwrittenbytes;
                    if (expectedwrittenbytes = = 0) {done = true;
                Break } if (done) {//Release all buffers for (int i = Msgcount; I & Gt 0;
                I--) {in.remove ();
                //Finish The Write loop if no new messages were flushed by In.remove (). if (In.isempty ()) {CLEAropwrite ();
                Break
                } else {//Did not write all buffers completely.

                Release the fully written buffers and update the indexes of the partially written buffer.
                    for (int i = Msgcount i > 0; I-) {final Bytebuf buf = (bytebuf) in.current ();
                    Final int readerindex = Buf.readerindex ();

                    Final int readablebytes = Buf.writerindex ()-Readerindex;
                        if (Readablebytes < writtenbytes) {in.progress (readablebytes);
                        In.remove ();
                    Writtenbytes-= readablebytes;
                        else if (Readablebytes > Writtenbytes) {buf.readerindex (readerindex + (int) writtenbytes);
                        In.progress (writtenbytes);
                    Break
  else {//readablebytes = Writtenbytes                      In.progress (readablebytes);
                        In.remove ();
                    Break
                } setopwrite ();
            Break
 }
        }
    }
}
As you can see from the code, the Socketchannel.open () is invoked, the Socketchannel object is created, and the Niosocketchannel and Socketchannel are associated. The main is to implement the Dowrite function of sending data.

3, Summary

Niosocketchannel and Nioserversocketchannel are the two specific classes that are available to developers. From the above analysis, it can be seen that in fact they are related to the bottom of the JDK Socketchannel and Serversocketchannel. The Netty socket channel is an encapsulation of the JDK socket channel, which associates channel with the Loop and handles channel event notifications in the loop.

Note: Channel is the core data structure of Netty, this article simply analyzes the socket section of channel, but it's basically been able to understand how Netty is associating its channel with the previous event. And how it associates the channel with JDK's channel.





Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.