1、channel
channel 相当于一个socket。channel的基本I/O操作bind()、connect()、read()和write()依赖顶层网络传输所提供的原语。netty中的接口的类层级如下:
如我们在 netty基本概念及入门示例代码 中的客户端配置的NioSocketChannel及服务端的NioServerSocketChannel
b.group(group)
.channel(NioSocketChannel.class)
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
2、EventLoop接口
EventLoop定义了Netty的核心抽象,用于处理连接的生命周期中所发生的事件。下图可以说明EventLoop与Channel、Thread、EventLoopGroup之间的关系
这些对应的关系为:
- 1、一个EventLoopGroup中可以包含一个或者多个EventLoop
- 2、一个EventLoop在它的生命周期内只和一个Thread绑定
- 3、所有的EventLoop处理的I/O事件都将在它专有的Thread上被处理
- 4、一个Channel在它的生命周期内只注册到一个EventLoop(这样保证了channel的线程安全)
- 5、一个EventLoop上可能会被分配给一个或者多个Channel(这样导致我们不能愉快的使用ThreadLocal来保存线程范围内的信息)
对实际编程中,我们常用到NioEventLoop的UML结构如上图所示,其实质就是一个单线程的线程池:
3、channelFuture
netty所有的I/o操作都是异步的,不能立即得知消息是否被正确处理。我们可以注册一个监听,当i/o操作执行失败或者成功后自动触发注册的监听事件。该接口的定义如下:
可以看到我们能够向一个channelFuture中注册/移除监听器及获取绑定的channel、执行同步阻塞sync()等。
public interface ChannelFuture extends Future<Void> {
/**
* Returns a channel where the I/O operation associated with this
* future takes place.
*/
Channel channel();
@Override
ChannelFuture addListener(GenericFutureListener<? extends Future<? super Void>> listener);
@Override
ChannelFuture addListeners(GenericFutureListener<? extends Future<? super Void>>... listeners);
@Override
ChannelFuture removeListener(GenericFutureListener<? extends Future<? super Void>> listener);
@Override
ChannelFuture removeListeners(GenericFutureListener<? extends Future<? super Void>>... listeners);
@Override
ChannelFuture sync() throws InterruptedException;
@Override
ChannelFuture syncUninterruptibly();
@Override
ChannelFuture await() throws InterruptedException;
@Override
ChannelFuture awaitUninterruptibly();
/**
* Returns {@code true} if this {@link ChannelFuture} is a void future and so not allow to call any of the
* following methods:
* <ul>
* <li>{@link #addListener(GenericFutureListener)}</li>
* <li>{@link #addListeners(GenericFutureListener[])}</li>
* <li>{@link #await()}</li>
* <li>{@link #await(long, TimeUnit)} ()}</li>
* <li>{@link #await(long)} ()}</li>
* <li>{@link #awaitUninterruptibly()}</li>
* <li>{@link #sync()}</li>
* <li>{@link #syncUninterruptibly()}</li>
* </ul>
*/
boolean isVoid();
}
4、ChannelHandler
站在我们应用程序开发人员的角度来看,netty最主要的组件是ChannelHandler,它充当了所有处理入站和出站数据的应用程序逻辑的容器。channelhandler可以处理channel被激活
可以看到ChannelHandler主要分为入站的Handler(ChannelInboudHandler)及出站的handler(CHannelOutboudHandler)
5、Pipeline
ChannelPipeline 为ChannelHandler链提供了容器,并定义了用于在该链上传播入站和出站事件流的API.当Channel被创建的时候,它会被自动的分配它专属的ChannelPipeline。
ChannelHandler安装到ChannelPipeline中的过程如下:
出站和入站操作是不同的,将两个不同类别的ChannelHandler都混合添加到同一个ChannelPipeline中会发生什么。但是netty能够区分ChannelInboudHandler和ChannelOutboundHandler,并确保数据直会在相同类型的ChannelHandler之间传递。
当ChannelHandler被添加到ChannelPipeline的时候,它将会被分配一个ChannelHandlerContext,其代表了ChannelHandler和ChannelPipeline之间的绑定。
在netty中,有两种发送消息的方式
- 直接写到Channel:会导致从ChannelPipeline的尾端开始流动。
- 写入跟ChannelHandler相关联的ChannelHandlerContext对象中
:从ChannelPipeline中的下一个ChannelHandler开始流动
6、引导类 bootStrap和ServerBootStrap
netty的引导类为应用程序的网络层配置提供了容器,者涉及将一个进程绑定到某个指定接口(ServerBootStrap)或者将一个进程连接到服务器上(BootStrap)。
两个不同引导类的区别:
类别 | BootStrap | ServerBootStrap |
---|---|---|
网络编程中的作用 | 连接到远程主机和端口 | 绑定到本地端口并监听连接 |
EventLoopGroup的数量 | 1` | 2 |
上表为我们显示了两个不同区别:
- 1、ServerbootStrap将绑定到一个端口,因为服务端必须监听连接,而Bootstrap则是由想要连接到远程节点的客户端应用程序所使用的。
- 2、BootStrap只需要一个EventLoopGroup,而一个ServerBootStrap需要两个(也可以是同一个)
因为服务器需要两组不同的Channel。第一组只需要包含一个SeverChannel,代表服务器自身绑定到某个端口的正在监听的套接字。而第二组包含所有已经创建的用来处理传入客户端连接的Channel。
与ServerChannel
相关联的EventLoopGroup
将分配一个负责为传入连接请求创建Channel
的EventLoop
。一旦连接被接受,第二个EventLoopGroup
就会给它的Channel
分配一个EventLoop
。