Netty 为每种传输的实现都暴露了相同的API,所以无论选用哪一种传输的实现,你的代码都仍然几乎不受影响。在所有的情况下,传输的实现都依赖于 interface Channel 、ChannelPipeline 和 ChannelHandler。
传输 API 的核心是 interface Channel,它被用于所有的I/O操作。
每个 Channel 都将会被分配一个 ChannelPipeline 和 ChannelConfig。ChannelConfig 包含了该 Channel 的所有配置设置,并且支持热更新。由于特定的传输可能具有独特的设置,所以它可能会实现一个 ChannelConfig 的子类型。
由于 Channel 是独一无二的,所以为了保证顺序将 Channel 声明为 java.lang.Comparable 的一个子接口。因此,如果两个不同的 Channel 实例都返回了相同的散列码,那么 AbstractChannel 中 compareTo() 方法的实现将会抛出一个 Error。
ChannelPipeline 持有所有将应用于入站和出战数据以及事件的 ChannelHandler 实例,这些 ChannelHandler 实现了应用程序用于处理状态变化以及数据处理的逻辑。
ChannelHandler 的典型用途包括:
- 将数据从一种格式转换为另一种格式;
- 提供异常的通知;
- 提供 Channel 变为活动的或者非活动的通知;
- 提供当 Channel 注册到 EventLoop 或者从 EventLoop 注销时的通知;
- 提供有关用户自定义事件的通知。
ChannelPipeline 实现了一种常见的设计模式——拦截过滤器(Intercepting Filter)。
你也可以根据需要通过添加或者移除 ChannelHandler 实例来修改 ChannelPipeline。通过利用 Netty 的这项能力可以构建出高度灵活的应用程序。例如,每当 STARTTLS 的协议请求时,你可以简单地通过向 ChannelPipeline 添加一个适当地 ChannelHandler (SslHandler) 来按需地支持 STARTTLS 的协议。
Channel 的方法:
- eventLoop:返回分配给 Channel 的 EventLoop
- pipeline:返回分配给 Channel 的 ChannelPipeline
- isActive:如果 Channel 是活动的,则返回 true。活动的意义可能依赖于底层的传输。例如,一个 Socket 传输一旦连接到了远程节点便是活动的,而一个 Datagram 传输一旦被打开便是活动的。
- localAddress:返回本地的 SocketAddress
- remoteAddress:返回远程的 SocketAddress
- write:将数据写到远程节点。这个数据将被传递给 ChannelPipeline ,并且排队直到它被冲刷
- flush:将之前已写的数据冲刷到底层传输,如一个 Socket
- writeAndFlush:一个简便的方法,等同于调用 write() 并接着调用 flush()
写数据并将其冲刷到远程节点这样的常规任务。
Channel channel = new NioServerSocketChannel();
// 创建持有要写数据的ByteBuf
ByteBuf buf = Unpooled.copiedBuffer("your data",CharsetUtil.UTF_8);
// 写数据并冲刷它
ChannelFuture cf = channel.writeAndFlush(buf);
// 添加 ChannelFutureListener 以便在写操作完成后接收通知
cf.addListener(new ChannelFutureListener(){
@Override
public void operationComplete(ChannelFuture future){
// 写操作完成,并且没有错误发生
if(future.isSuccess()){
System.out.println("Write successful");
}else{
System.err.println("Write error");
future.cause().printStackTrace();
}
}
});
Netty 的 Channel 实现是线程安全的,因此你可以存储一个到 Channel 的引用,并且每当你需要向远程节点写数据时,都可以使用它,即使当时许多线程都在使用它。
// 从多个线程使用同一个 Channel
final Channel channel = new NioServerSocketChannel();
// 创建持有要写数据的 ByteBuf
fianl ByteBuf buf = Unpooled.copiedBuffer("your data",CharsetUtil.UTF_8).retain();
// 创建将数据写到 Channel 的 Runnable
Runnable writer = new Runnable(){
@Override
public void run(){
channel.writeAndFlush(buf.duplicate());
}
};
// 获取到线程池 Executor 的引用
Executor executor = Executors.newCachedThreadPool();
// write in one thread
// 递交写任务给线程池以便在某个线程中执行
executor.execute(writer);
// write in another thread
// 递交另一个写任务以便在另一个线程中执行
executor.execute(writer);
内置的传输
Netty 内置了一些可开箱即用的传输。因为并不是它们所有的传输都支持每一种协议,所以你必须选择一个和你的应用程序所使用的协议相容的传输。
Netty 所提供的传输:
- NIO : io.netty.channel.socket.nio 使用 java.nio.channels 包作为基础——基于选择器的方式
- Epoll : io.netty.channel.epoll 由 JNI 驱动的 epoll() 和非阻塞 IO。这个传输支持只有在 Linux 上可用的多种特性,如 SO_REUSEPORT,比 NIO 传输更快,而且是完全非阻塞的
- OIO : io.netty.channel.socket.oio 使用 java.net 包作为基础——使用阻塞流
- Local : io.netty.channel.local 可以在 VM 内部通过管道进行通信的本地传输
- Embedded : io.netty.channel.embedded Embedded 传输,允许使用 ChannelHandler 而又不需要一个真正的基于网络的传输。这在测试你的 ChannelHandler 实现时非常有用
来源:oschina
链接:https://my.oschina.net/u/3843989/blog/4354941