四Netty组件类--1Channel通道

四Netty组件类--1Channel通道

16.1 Channel功能说明

Netty中channel是socket连接的抽象,为用户提供关于底层socket状态(连接还是断开),以及对socket的读写等操作。

父子channel:

channel有父子channel的概念。server端负责链接监听的channel,叫做parentChannel;对应于每个socket连接的channel,叫做childChannel。(child是在建立连接成功后,由NioServerSocketChannel创建的,所以前者为parent,后者为child)

16.1.1 Channel提供的功能

  • 通道状态:open、close、connected、active(激活);
  • 通道IO操作:read、write、connect、bind;
  • 所有的IO操作都是异步:read、write、connect、bind异步执行,返回channelFuture;
  • channel具有父子关系
  • 在使用channel完毕后,调用close,释放channel占用的资源
public interface Channel extends AttributeMap, Comparable<Channel> {
		//	返回全局唯一channelID
    ChannelId id();

    /**返回channel所注册的eventLoop*/
    EventLoop eventLoop();

    Channel parent();

    /**返回channel的配置 */
    ChannelConfig config();

    boolean isOpen();

    /**返回该channel是否注册在eventLoop上*/
    boolean isRegistered();

    /** true:channel是激活状态,且连接
     * Return {@code true} if the {@link Channel} is active and so connected.
     */
    boolean isActive();


    /**本地绑定的address*/
    SocketAddress localAddress();
    SocketAddress remoteAddress();

    ChannelFuture closeFuture();

    /**是否可写,如果channel的写缓冲区未满,表示可以write,返回true*/
    boolean isWritable();

    /**返回只可以netty调用使用的unsafe对象*/
    Unsafe unsafe();

   //返回当前channel分配的pipeline(channel只有一个pipeline对应)
    ChannelPipeline pipeline();

    /**
     * Return the assigned {@link ByteBufAllocator} which will be used to allocate {@link ByteBuf}s.
     */
    ByteBufAllocator alloc();

    /**返回异步通知中的一个凭证,多线程操作中的典型模式*/
    ChannelPromise newPromise();
    ChannelProgressivePromise newProgressivePromise();
    ChannelFuture newSucceededFuture();
	  ChannelFuture newFailedFuture(Throwable cause);
    ChannelPromise voidPromise();

    //IO操作,返回channelFuture
    ChannelFuture bind(SocketAddress localAddress);
    ChannelFuture connect(SocketAddress remoteAddress);
    ChannelFuture disconnect();
    ChannelFuture close();
    ChannelFuture deregister();

    /**
     * Request to Read data from the {@link Channel} into the first inbound buffer, triggers an
     * {@link ChannelHandler#channelRead(ChannelHandlerContext, Object)} event if data was
     * read, and triggers a
     * {@link ChannelHandler#channelReadComplete(ChannelHandlerContext) channelReadComplete} event so the
     * handler can decide to continue reading.  If there's a pending read operation already, this method does nothing.
     * <p>
     * This will result in having the
     * {@link ChannelHandler#read(ChannelHandlerContext)}
     * method called of the next {@link ChannelHandler} contained in the  {@link ChannelPipeline} of the
     * {@link Channel}.
     */
    Channel read();

    /**
     * Request to write a message via this {@link Channel} through the {@link ChannelPipeline}.
     * This method will not request to actual flush, so be sure to call {@link #flush()}
     * once you want to request to flush all pending data to the actual transport.
     */
    ChannelFuture write(Object msg);

    /**
     * Request to write a message via this {@link Channel} through the {@link ChannelPipeline}.
     * This method will not request to actual flush, so be sure to call {@link #flush()}
     * once you want to request to flush all pending data to the actual transport.
     */
    ChannelFuture write(Object msg, ChannelPromise promise);

    /**
     * Request to flush all pending messages.
     */
    Channel flush();

    /**
     * Shortcut for call {@link #write(Object, ChannelPromise)} and {@link #flush()}.
     */
    ChannelFuture writeAndFlush(Object msg, ChannelPromise promise);

    /**
     * Shortcut for call {@link #write(Object)} and {@link #flush()}.
     */
    ChannelFuture writeAndFlush(Object msg);

    /**
     * <em>Unsafe</em> operations that should <em>never</em> be called from user-code. These methods
     * are only provided to implement the actual transport, and must be invoked from an I/O thread except for the
     * following methods:
     * <ul>
     *   <li>{@link #invoker()}</li>
     *   <li>{@link #localAddress()}</li>
     *   <li>{@link #remoteAddress()}</li>
     *   <li>{@link #closeForcibly()}</li>
     *   <li>{@link #register(EventLoop, ChannelPromise)}</li>
     *   <li>{@link #deregister(ChannelPromise)}</li>
     *   <li>{@link #voidPromise()}</li>
     * </ul>
     */
    interface Unsafe {

        /**
         * Return the assigned {@link RecvByteBufAllocator.Handle} which will be used to allocate {@link ByteBuf}'s when
         * receiving data.
         */
        RecvByteBufAllocator.Handle recvBufAllocHandle();

        /**
         * Returns the {@link ChannelHandlerInvoker} which is used by default unless specified by a user.
         */
        ChannelHandlerInvoker invoker();

        /**
         * Return the {@link SocketAddress} to which is bound local or
         * {@code null} if none.
         */
        SocketAddress localAddress();

        /**
         * Return the {@link SocketAddress} to which is bound remote or
         * {@code null} if none is bound yet.
         */
        SocketAddress remoteAddress();

        /**
         * Register the {@link Channel} of the {@link ChannelPromise} and notify
         * the {@link ChannelFuture} once the registration was complete.
         * <p>
         * It's only safe to submit a new task to the {@link EventLoop} from within a
         * {@link ChannelHandler} once the {@link ChannelPromise} succeeded. Otherwise
         * the task may or may not be rejected.
         * </p>
         */
        void register(EventLoop eventLoop, ChannelPromise promise);

        /**
         * Bind the {@link SocketAddress} to the {@link Channel} of the {@link ChannelPromise} and notify
         * it once its done.
         */
        void bind(SocketAddress localAddress, ChannelPromise promise);

        /**
         * Connect the {@link Channel} of the given {@link ChannelFuture} with the given remote {@link SocketAddress}.
         * If a specific local {@link SocketAddress} should be used it need to be given as argument. Otherwise just
         * pass {@code null} to it.
         *
         * The {@link ChannelPromise} will get notified once the connect operation was complete.
         */
        void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise);

        /**
         * Disconnect the {@link Channel} of the {@link ChannelFuture} and notify the {@link ChannelPromise} once the
         * operation was complete.
         */
        void disconnect(ChannelPromise promise);

        /**
         * Close the {@link Channel} of the {@link ChannelPromise} and notify the {@link ChannelPromise} once the
         * operation was complete.
         */
        void close(ChannelPromise promise);

        /**
         * Closes the {@link Channel} immediately without firing any events.  Probably only useful
         * when registration attempt failed.
         */
        void closeForcibly();

        /**
         * Deregister the {@link Channel} of the {@link ChannelPromise} from {@link EventLoop} and notify the
         * {@link ChannelPromise} once the operation was complete.
         */
        void deregister(ChannelPromise promise);

        /**
         * Schedules a read operation that fills the inbound buffer of the first {@link ChannelHandler} in the
         * {@link ChannelPipeline}.  If there's already a pending read operation, this method does nothing.
         */
        void beginRead();

        /**
         * Schedules a write operation.
         */
        void write(Object msg, ChannelPromise promise);

        /**
         * Flush out all write operations scheduled via {@link #write(Object, ChannelPromise)}.
         */
        void flush();

        /**
         * Return a special ChannelPromise which can be reused and passed to the operations in {@link Unsafe}.
         * It will never be notified of a success or error and so is only a placeholder for operations
         * that take a {@link ChannelPromise} as argument but for which you not want to get notified.
         */
        ChannelPromise voidPromise();

        /**
         * Returns the {@link ChannelOutboundBuffer} of the {@link Channel} where the pending write requests are stored.
         */
        ChannelOutboundBuffer outboundBuffer();
    }
}

16.2 Channel源码分析

16.2.1 channel主要继承关系类图

image-20220922230511963

channel主要的功能接口:

image-20220926000700676

16.2.2 channel中事件流

image-20230310154714248

channel注册完成后,事件ChannelRegistered;然后注册成功且绑定端口后,事件ChannelActive;fireChannelActive把感兴趣的事件注册到nioEventLoop上的selectionKey上。然后,eventLoop的selector.select()开始阻塞的轮询操作,轮询到就绪操作,就fireChannelXXX。

16.2.3 SelectionKey中对监听位设置

image-20220925131127235

Read:1 Write:4 Connect:8 Accept=16

16.3 ServerSocketChannelImpl(原生channel)

image-20221205131959541

16.3.1 SelectableChannel

当前类两个作用:

1 当前channel,表示channel是支持selector多路复用的channel---提供register方法,可以将当前channel注册到指定selector上,并注册当前channel关心的事件intops。

2 此外,该channel是支持阻塞或非阻塞模式的,可以通过configureBlocking(boolean block)设置------channel异步时,connect、read、write等操作,不会阻塞当前线程。

public abstract class SelectableChannel extends AbstractInterruptibleChannel implements Channel {

  	//返回创建当前channel的SelectorProvider
    public abstract SelectorProvider provider();

  	//查看当前channel支持的事件类型集合set,需要再注册时指定事件类型
    public abstract int validOps();
 
  	//将当前channel注册到指定selector上,并设置关注的事件为ops、channel属性att。注册后返回SelectionKey(代表当前channel、selector的关系)
    public abstract SelectionKey register(Selector sel, int ops, Object att)
        throws ClosedChannelException;

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

    //设置当前channel的阻塞类型--可以阻塞或者异步的类型
    public abstract SelectableChannel configureBlocking(boolean block)
        throws IOException;
    public abstract boolean isBlocking();
}

int validOps()方法:

返回当前channel所支持的事件集合。例如netty通信框架中使用的JDK的NIO底层channel类中,对当前channel所支持的事件类型进行如下定义:

public abstract class ServerSocketChannel extends AbstractSelectableChannel implements NetworkChannel

  	//server端channel只支持OP_ACCEPT操作
    public final int validOps() {
        return SelectionKey.OP_ACCEPT;
    }
    
public abstract class SocketChannel extends AbstractSelectableChannel implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, NetworkChannel {
  
  	//socketChannel端支持read、write、connect的操作
    public final int validOps() {
        return (SelectionKey.OP_READ
                | SelectionKey.OP_WRITE
                | SelectionKey.OP_CONNECT);
    }

serversocketchannel支持accept操作;而socketchannel支持read、write、connect的操作。在channel.register向指定selector上注册关心事件时,事件需要符合当前channel支持的事件集validOps。

16.3.2 NetworkChannel

public interface NetworkChannel extends Channel
{
   
  	//绑定当前channel的socket,到local address
    NetworkChannel bind(SocketAddress local) throws IOException;
    SocketAddress getLocalAddress() throws IOException;

  	//设置当前socket的属性选项option值
    <T> NetworkChannel setOption(SocketOption<T> name, T value) throws IOException;
}

NetworkChannel接口代表channel是个网络字节流的连接,使用bind(socketChannel)将channel绑定在本地端口,进行字节流的操作(读或写)。

16.3.3 ServerSocketChannelImpl(NIO原生)

当前channel只支持ACCEPT类型的事件,用于监听是否有新连接建立。

image-20221205140616947

这是JDK原生NIO的serversocketchannel,Netty的NioServerSocketChannel依赖当前channel实现网络通信功能。并且实现SelectableChannel、NetworkChannel类和接口,具有selector的选择器注册功能,并且能够在本地网络端口进行字节流的操作。

class ServerSocketChannelImpl extends ServerSocketChannel implements SelChImpl {


16.3.4 SocketChannel(NIO原生)

image-20230310154753243

当前类socketchannel实现writable、readable接口,当前channel具有read、write的字节流的read、write操作。

class SocketChannelImpl extends SocketChannel implements SelChImpl {

posted @ 2023-03-10 17:21  LeasonXue  阅读(128)  评论(0编辑  收藏  举报