四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主要继承关系类图
channel主要的功能接口:
16.2.2 channel中事件流
channel注册完成后,事件ChannelRegistered;然后注册成功且绑定端口后,事件ChannelActive;fireChannelActive把感兴趣的事件注册到nioEventLoop上的selectionKey上。然后,eventLoop的selector.select()开始阻塞的轮询操作,轮询到就绪操作,就fireChannelXXX。
16.2.3 SelectionKey中对监听位设置
Read:1 Write:4 Connect:8 Accept=16
16.3 ServerSocketChannelImpl(原生channel)
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类型的事件,用于监听是否有新连接建立。
这是JDK原生NIO的serversocketchannel,Netty的NioServerSocketChannel依赖当前channel实现网络通信功能。并且实现SelectableChannel、NetworkChannel类和接口,具有selector的选择器注册功能,并且能够在本地网络端口进行字节流的操作。
class ServerSocketChannelImpl extends ServerSocketChannel implements SelChImpl {
16.3.4 SocketChannel(NIO原生)
当前类socketchannel实现writable、readable接口,当前channel具有read、write的字节流的read、write操作。
class SocketChannelImpl extends SocketChannel implements SelChImpl {