[Netty源码] 各个组件介绍 (一)
文章目录
- 1.Netty简单的demo
- 2.NIO的定式Api
- 3.组件介绍
- 3.1 EventLoop
- 3.2 Channel
- 3.3 ChannelHandler
- 3.4 ChannnelHandlerContext
- 3.5 ChannelPipeline
- 3.6 Bootstrap
- 3.7 ByteBuf
1.Netty简单的demo
Netty高并发高性能:
- 主从Reactor线程模型
- NIO多路复用非阻塞
- 无锁串行化设计思想
- 支持高性能序列化协议
- 零拷贝(直接内存的使用)
- ByteBuf内存池设计
- 灵活的TCP参数配置能力
- 并发优化
public class Server {
public static void main(String[] args) throws Exception{
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap()
.group(bossGroup, workGroup)
.channel(NioServerSocketChannel.class)
.childOption(ChannelOption.TCP_NODELAY, true)
.childAttr(AttributeKey.newInstance("childAttr"), "childAttrValue")
// 对应 .accept, 新连接介入
.handler(new ServerHandler())
.childHandler(new ChannelInitializer<ServerSocketChannel>() {
@Override
protected void initChannel(ServerSocketChannel ch) throws Exception {
ch.pipeline().addLast(new AuthHandler());
}
});
ChannelFuture f = b.bind(8080).sync();
f.channel().closeFuture().sync();
}finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
}
Netty线程模型图
2.NIO的定式Api
Selector selector = Selector.open();
ServerSocketChannel ssc = ServerSocketChannel.open();
InetSocketAddress address = new InetSocketAddress(1233);
ssc.configureBlocking(false);
ssc.bind(address);
ssc.register(selector, SelectionKey.OP_ACCEPT);
for (;;) {
int select = selector.select();
if (select > 0) {
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
iterator.remove();
if (selectionKey.isAcceptable()) {
SocketChannel channel = ssc.accept();
channel.configureBlocking(false);
channel.register(selector,SelectionKey.OP_READ);
}
if (selectionKey.isReadable()) {
ByteBuffer buffer = ByteBuffer.allocate(10);
SocketChannel channel = (SocketChannel)selectionKey.channel();
// 读取channel数据。。
channel.close();
}
}
}
}
nio的几个重要组件:
- Selector(事件选择器)
- Channel(通信通道)
- Buffer(通信载体)
3.组件介绍
netty就是基于nio做的一次优秀的封装
netty的几个重要组件:
-
NioEventLoop(线程组件), 对应一个Thread
-
Channel(通信通道,netty做了一层封装), 对应一个Socket连接
-
ChannelPipeline(消息通知链), 对应一个逻辑处理链 Logic Chain
-
ChannelHandler(真正触发事件干活的), 对应具体的逻辑 Logic
-
ChannelHandlerContext(对handler做了一层包装), 对逻辑的封装
-
ByteBuf: 数据流的读写基于ByteBuf操作的
-
Bootstrap: 可以让ChannalPipline、ChannelHandler和EventLoop一起有效组合成一个可以实际运行的应用程序
3.1 EventLoop
做的大部分和线程处理相关的事情, 无论是服务器线程还是客户端线程
NioEventLoop存在boss与work之分, boss代表一个总线程, work代表很多工作线程, 简而言之就是一个boss管理多个work。
EventLoopGroup和EventLoop和channel的关系:
EventLoopGroup的责任是将新的连接(也就是新的Channel)分配给EventLoopGroup内关联的EventLoop
NioEventLoop源码中表面了Reactor网络模型。
3.2 Channel
Channel对应的是Socket连接, 相当于一个Channel就是一个socket连接。
客户端创建一个连接或者服务端收到连接请求都会创建一个Channel,所有的I/O事件都由Channel产生,这些事件包含read、write、connet、accept、close。Channel为用户提供了:
- 当前网络连接通道的状态
- 网络连接的配置信息
- 异步的网络I/O操作,操作返回ChannelFuture实例,通过ChannelFuture可以操作异步的状态,例如取消、关闭等
不同的协议与不同的阻塞类型的连接都有与之对应的Channel类型,下面是常用的Channel类型:
- NioSocketChannel 异步的客户端 TCP Socket 连接。
- NioServiceSocketChannel 异步的服务器端 TCP Socket 连接。
- NioDatagramChannel 异步的 UDP 连接。
- NioSctpChannel 异步的客户端 Sctp 连接。
- NioSctpServiceChannel 异步的 Sctp 服务器端连接
- EpollSocketChannel 异步的客户端TCP Socket连接,底层使用epoll
- EpollServiceSocketChannel异步的服务器端 TCP Socket 连接,底层使用epoll
3.3 ChannelHandler
ChannelHandler是一个处理Channel事件的接口, 通过ChannelHandler可以处理任一的网络I/O事件与数据, 引导过程会使用ChannelPipeline将多个ChannelHandler串起来。
通常会通过继承ChannelInboundHandler与ChannelOutboundHandler两个子接口类型来处理业务逻辑, 这些业务逻辑包含数据的编码、解码、读取、写入以及事件传递等待事情。
3.4 ChannnelHandlerContext
将对应的ChannelHandler托管, 在ChannelPipeline中起到事件向下传递与调用ChannelHandler的作用,另外还存储着当前Channel的相关上下文信息等。
3.5 ChannelPipeline
它让Netty在处理各种各样的业务情况时有了很强扩展性与适应性, 使得业务可以在运行时对整个ChannelPipeline中的过滤器(这里的过滤器实现类型都是ChannelHandler)进行调整以支持不同的业务形态。
ChannelPipeline中使用一张链表存储着所有ChannelHandler, 会区分入站ChannelInboundHanndler和出站ChannelOutboundHanndler的类型。
3.6 Bootstrap
Bootstrap是一个应用程序中启动过程中的配置,通过这些配置让应用程序能正常的运行起来的一个过程。
这个概念有点像操作系统的启动过相近,操作系统的启动过程同样有一个引导的过程。
Bootstrap为客户端是引导, ServerBootstap为服务端的引导
3.7 ByteBuf
这里一个创建方式是直接内存一个是堆内存
ByteBuf buf1 = ByteBufAllocator.DEFAULT.buffer();
ByteBuf buf2 = ByteBufAllocator.DEFAULT.directBuffer();
ByteBuf buf3 = ByteBufAllocator.DEFAULT.heapBuffer();
直接内存对GC压力小,因为这部分内存不受JVM垃圾回收的管理,但也要注意及时主动释放
并且Netty的ByteBuf支持池化, 可以重用池中 ByteBuf实例, 内存分配算法提高分配效率, 并发时候可以减少内存溢出, 使得节约内存