Netty是一个异步的、基于事件驱动的网络应用框架,用于快速开发可维护、高性能的网络服务器和客户端。(这里的异步和异步io不是一个概念)
一、Netty的优势
使用NIO开发网络应用,会面临很多困难:
1.工作量大,bug多。
2.需要解决TCP传输的问题,比如粘包、半包等。
3.NIO的epoll有bug,会空轮训导致cpu占用100%,Netty的作者用其他方法解决了这个问题。
4.对api进行了增强。
二、Netty的简单示例
2.1 client发送数据给服务端
服务器代码:
public static void main(String[] args) {
//1.启动器,负责组装netty组件,启动服务器
new ServerBootstrap()
//2.多个EventLoop,处理不同的事件
.group(new NioEventLoopGroup())
//3.选择服务器的ServerSocketChannel实现
.channel(NioServerSocketChannel.class)
//4.worker逻辑处理
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
//5.将bytebuffer转为字符串
nioSocketChannel.pipeline().addLast(new StringDecoder());
nioSocketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter(){
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println(msg);
}
});
}
}).bind(8080);
}
客户端代码:
public static void main(String[] args) throws InterruptedException {
//1.启动器,负责组装netty组件,启动服务器
new Bootstrap()
//2.添加EventLoop
.group(new NioEventLoopGroup())
//3.选择客户端的SocketChannel
.channel(NioSocketChannel.class)
//4.worker逻辑处理
.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
//5.将字符串转为bytebuffer
nioSocketChannel.pipeline().addLast(new StringEncoder());
}
//6.连接服务器
}).connect(new InetSocketAddress("localhost", 8080))
//阻塞方法,连接建立才会执行
.sync()
//拿到连接对象
.channel()
//7.发送数据
.writeAndFlush("hello fucker!!!");
}
2.2 组件分析
- 把channel理解为数据的通道。
- 把 msg理解为流动的数据,最开始输入是ByteBuf,但经过pipeline的加工,会变成其它类型对象,最后输出又变成 ByteBuf。
- 把 handler理解为数据的处理工序。
工序有多道,合在一起就是pipeline,pipeline负责发布事件(读、读取完成…)传播给每个handler,handler对自己感兴趣的事件进行处理(重写了相应事件处理方法)。
handler 分Inbound和Outbound两类。 - 把eventLoop理解为处理数据的工人
工人可以管理多个channel的io操作,并且一旦工人负责了某个channel,就要负责到底(绑定)。工人既可以执行io操作,也可以进行任务处理,每位工人有任务队列,队列里可以堆放多个channel的待处理任务,任务分为普通任务、定时任务。
工人按照pipeline顺序,依次按照handler的规划(代码)处理数据,可以为每道工序指定不同的工人。
2.3 eventloop
EventLoop本质是一个单线程执行器(同时维护了一个Selector),里面有run方法处理Channel上源源不断的io 事件。它的继承关系比较复杂:
- 一条线是继承自j.u.c.ScheduledExecutorService因此包含了线程池中所有的方法
- 另—条线是继承netty自己的 OrderedEventExecutor,提供了boolean inEventLoop(Thread thread)方法判断一个线程是否属于此EventLoop,还提供了parent方法来看看自己属于哪EventLoopGroup。
EventLoopGroup是一组EventLoop,Channel一般会调用EventLoopGroup的register方法来绑定其中一个EventLoop,后续这个Channel上的io事件都由此EventLoop来处理(保证了io事件处理时的线程安全)。EventLoopGroup继承自netty自己的 EventExecutorGroup,实现了lterable接口提供遍历EventLoop的能力。另有next方法获取集合中下一个EventLoop。