了解完前面的知识块,也就是最开始的文章中说的
* EventLoop和EventLoopGroup
* ChannelHandler与ChannelPipeline
* ByteBuf与ByteBufAllocator
这些大块以后,我们可以看下最核心的模块:Channel。基本所有重要的工作,注册、获取连接、读写都是Channel在执行。
本文主要对Channel接口的基本功能进行介绍,对其相关实现类进行简单介绍。后面会专门提供两篇文章来聊下我们最关心的NioServerSocketChannel和NioServerSocketChannel。
1.Channel接口基本方法该Channel是Netty提供的,全限定名为io.netty.channel.Channel。JDK NIO中也提供了一个Channel,全限定名为java.nio.channels.Channel,这个Channel作为一个通道与网络或文件进行操作。
而Netty中提供的Channel,我们也可以理解为一个通道,只不过这个通道的功能比较强大。
// A nexus to a network socket or a component which is capable of I/O operations
// such as read, write, connect, and bind.
package io.netty.channel;
public interface Channel extends AttributeMap, ChannelOutboundInvoker, Comparable {
// 编号
ChannelId id();
// 当前channel所属EventLoop,归哪个线程来执行
EventLoop eventLoop();
// 基本属性
ChannelConfig config();
// channel所绑定的本地地址
SocketAddress localAddress();
// channel绑定的远程地址
SocketAddress remoteAddress();
// 很重要的Unsfae对象,一个Channel对应一个Unsafe
Unsafe unsafe();
// 所属pipeline
ChannelPipeline pipeline();
// 所属ByteBuf分配器
ByteBufAllocator alloc();
/** 状态相关 */
boolean isOpen();
boolean isRegistered();
boolean isActive();
boolean isWritable();
/** 方法相关 */
Channel read();
Channel flush();
// 内部接口类Unsafe
interface Unsafe {
// 主要方法如下
void register(EventLoop eventLoop, ChannelPromise promise);
void bind(SocketAddress localAddress, ChannelPromise promise);
void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise);
void write(Object msg, ChannelPromise promise);
}
}
而关于继承的ChannelOutboundInvoker,有以下方法提供,这个我们比较熟悉了。
方法返回都是ChannelFuture,基本都是异步执行
public interface ChannelOutboundInvoker {
ChannelFuture bind(SocketAddress localAddress);
ChannelFuture connect(SocketAddress remoteAddress);
ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress);
ChannelFuture disconnect();
ChannelFuture close();
ChannelFuture deregister();
ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise);
ChannelFuture connect(SocketAddress remoteAddress, ChannelPromise promise);
ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise);
ChannelFuture disconnect(ChannelPromise promise);
ChannelFuture close(ChannelPromise promise);
ChannelFuture deregister(ChannelPromise promise);
ChannelOutboundInvoker read();
ChannelFuture write(Object msg);
ChannelFuture write(Object msg, ChannelPromise promise);
ChannelOutboundInvoker flush();
ChannelFuture writeAndFlush(Object msg, ChannelPromise promise);
ChannelFuture writeAndFlush(Object msg);
}
这些方法综合起来,相当于Channel提供了一个全量的网络操作。
2.Channel的实现类结构图Channel作为一个接口类,它的实现类主要有以下这些
当然以上主要都是基于NIO的实现。除了NIO,还有其他实现,如下图(图片来自网络)
我们今天主要讨论NIO的相关实现。
2.1 SocketChannelSocketChannel作为客户端的Channel接口类,主要提供了以下方法
/**
* A TCP/IP socket {@link Channel}.
*/
public interface SocketChannel extends DuplexChannel {
@Override
ServerSocketChannel parent();
@Override
SocketChannelConfig config();
// 就是返回类编程实现类了
InetSocketAddress localAddress();
@Override
InetSocketAddress remoteAddress();
}
// 主要的与Channel的不同点在于DuplexChannel
public interface DuplexChannel extends Channel {
// 对输入输出流的操作
boolean isInputShutdown();
ChannelFuture shutdownInput();
ChannelFuture shutdownInput(ChannelPromise promise);
boolean isOutputShutdown();
ChannelFuture shutdownOutput();
ChannelFuture shutdownOutput(ChannelPromise promise);
boolean isShutdown();
ChannelFuture shutdown();
ChannelFuture shutdown(ChannelPromise promise);
}
所以,SocketChannel相对于Channel而言,主要是提供了关闭输入输出流的API
2.2 ServerSocketChannel/**
* A TCP/IP {@link ServerChannel} which accepts incoming TCP/IP connections.
*/
public interface ServerSocketChannel extends ServerChannel {
@Override
ServerSocketChannelConfig config();
// 就是返回对象变成了实体类
InetSocketAddress localAddress();
@Override
InetSocketAddress remoteAddress();
}
// 一个标记接口
public interface ServerChannel extends Channel {
// This is a tag interface.
}
这个接口貌似就没什么特别的API了
3.Unsafe内部接口类Channel.Unsafe就是一个比较神奇的设计了。有点类似于JDK中sun.misc.Unsafe类。这个类官方不建议直接调用,而是让我们使用它的封装类来间接调用。
而这个Unsafe也是,Netty中也不建议我们直接使用它,而是实现它的封装类。我们来看下它的注解,就知道官方的良苦用心了。
/**
* Unsafe operations that should never 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:
*/
interface Unsafe {}