- Netty是什么?
- Netty是Jboss提供的一个Java 开源框架,主要针对TCP协议的高并发场景
- Netty本质是对Java NIO做了封装的网络通信框架,主要作用是Java NIO基本接口的封装,提供了网络通信中线程同步,编解码,粘包拆包,闪断重连等问题的封装,方便我们利用API方便的开发;
- 提供了完整的ssl/tsl支持;
- 另外Netty解决了NIO中的selector空轮训的Bug;
- Netty 线程模型为多reactor多线程模型-1+n+m,但是Netty提供了灵活配置,也可以实现单reactor单线程,单reactor多线程模型;
- Netty的启动流程
- 先上代码
public class HelloServer {
public static void main(String[] args) {
NioEventLoopGroup bossGroup=new NioEventLoopGroup(1);
NioEventLoopGroup workGroup=new NioEventLoopGroup();
new ServerBootstrap()
//1、绑定线程池组
.group(bossGroup,workGroup)
//2、定义主reactor线程处理Handler
.handler(new LoggingHandler(LogLevel.DEBUG))
//3、选择服务器的ServerSocketChannel实现
.channel(NioServerSocketChannel.class)
//4、boss:负责处理连接;worker:处理读写,决定了worker(child)能执行哪些操作(handler)
.childHandler(
//5、Channel代表和客户端进行数据读写的通道,Initializer初始化器,负责添加别的handler
new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
//添加具体的handler
ch.pipeline().addLast(new StringDecoder()); //17、将ByteBuf转换为字符串,然后给下一个处理器
ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { //自定义handler
@Override //读事件
//18、执行channelRead()方法,打印hello
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("WorkGroup thread name----"+Thread.currentThread().getName());
System.out.println(msg);
System.out.println(ctx.pipeline().names());
}
});
}
})
//6、绑定监听端口
.bind(8888);
}
}
- Netty提供了启动引导类ServerBootstrap,使用Builder模式来帮助构建启动Netty服务器程序,提供了灵活的配置需求;
- 基本说明--
- Netty启动过程就是加载配置项--主从reactor执行线程池组,socketchannel的Handler,监听端口;
- 然后创建serversocketchannel注册到主reactor线程上,监听新连接事件,将新的连接分发到从reactor线程的eventloop中;
- 这里Netty对serversocketchannel提供了默认的Handler实现对新连接创建socketchannel并分发给从reactor的逻辑;
- 首先通过group方法指定了主从reactor线程池组,bossGroup对应主reactor线程,负责监听端口处理连接请求,新连接请求将创建socketchannel并分发注册到workerGroup中的eventloop上,由workerGroup中的eventloop监听IO事件并调用相应的Handler来处理IO事件;
- 每一个eventloop对应一个单例线程池,对应一个selector对象,接受一个或多个channel注册,监听读写事件;
- Netty启动并初始化的核心逻辑在体现在bind()方法中,bind方法创建serversocketchannel并注册到bossGroup中的eventloop上,并为serversocketchannel提供默认用来创建新连接的Handler----ServerBootstrapAcceptor
- 总体来说,网络通信的基本过程为---
- 创建serversocketchannel监听端口,处理connect事件
- 创建socketchannel监听连接,处理IO事件
- 而Netty启动则完成了第一步;
- Netty中的核心类型说明
- NioEventLoop
Netty启动首先创建了两个nioeventloopgroup对象,这两个对象字面理解就是两个nioEventLoop数组,所以核心是NioEventLoop,看一下源码--
public final class NioEventLoop extends SingleThreadEventLoop {
private Selector selector;
private SelectedSelectionKeySet selectedKeys;
private final SelectorProvider provider;
private final SelectStrategy selectStrategy;
//注册socketchannel到selector
public void register(final SelectableChannel ch, final int interestOps, final NioTask<?> task);
//重新构建selector--JDK NIO中的selector的空轮训Bug解决方案
public void rebuildSelector();
//eventloop运行主逻辑
protected void run();
}
NioEventLoop可以说是Netty的reactor核心逻辑的实现,主要继承了抽象类SingleThreadEventLoop,单线程处理NIO事件循环通知;而SingleThreadEventLoop的继承和实现关系如下:
代码实例中只写了极少一部分体现核心逻辑的方法和实例属性,主要为了概念上说明NioEventLoop的工作机制,具体详细的实现在后续专门说明;
NioEventLoop的工作原理-
- EventLoop核心是一个线程处理事件循环;
- NioEventLoop则是运行selector方法,完成对注册在selector上的channel的网络事件监听,这也就是reactor模型的基本实现----IO多路复用和事件监听;
- 另外NioEventLoop继承了SingleThreadEventLoop,除了监听selector之外还可以监听通过父类的execute()方法提交的任务和schedule方法提交的定时任务;
- rebuildSelector()方法是NioEventLoop对JDK中的selector空轮训的Bug实现的解决方案----空轮训次数超过默认512次后重新构建一个新的selector对象;
- register()方法用于在新连接建立后向EventLoop中的selector注册连接对应的socketchannel;
- run()方法则是一个死循环,对selector和注册的其他异步任务进行轮训,监听到事件发生时则执行对应的Handler来处理事件;
2.NioEventLoopGroup
NioEventLoopGroup 是一个线程数组,继承了MultithreadEventLoopGroup,
主要提供了对NioEventLoop 初始化的参数,用来创建NioEventLoop实例,默认创建CPU核数*2个线程(EventLoop)--
另外MultithreadEventLoop继承了EventExecutorChooser选择器的实现,选择器用来做任务分发----NioEventLoopGroup 是一个线程池,当向NioEventLoopGroup注册一个新的channel的时候具体分发给哪一个EventLoop的selector来监听该channel上的IO事件;这里对选择器的实现机制不多做解释,大概对NioEventLoopGroup的主要功能逻辑做一个说明;
3.ChannelHandler
channelHandler是事件处理器的实现,netty中通过责任链模式实现对事件的层层处理,责任链模式的主体对象是pipeline,相当于一个双向链表,分别对应出站(从服务端到客户端)和入站(从客户端向服务端)方向的事件处理,这里出站和入战是相对的,对本netty服务来说,接收外部的其他服务请求即为入站,反之主动向其他netty服务发出请求即为出站,简单理解为接收数据即为入站,发送数据即为出站;当事件发生的时候,EventLoop就会调用对应的channel的Handler来处理具体的逻辑--底层的ByteBuffer的读写,上层业务逻辑处理等等;
总结:netty通过EventLoop单线程执行selector来监听注册在其上的网络IO事件和用户在Handler中提交的异步任务,然后对不同的事件调用不同的Handler来处理;而netty的主体功能此时就体现出来了,第一,实现了reactor线程模型,第二,封装很多网络通信中底层数据的处理逻辑,用户可以通过简单的调用或者继承即可实现相应的功能,从而屏蔽了网络通信底层逻辑的复杂性;