Netty入门
1、Netty优势
Netty VS NIO,工作量大,bug多
- 需要自己构建协议
- 解决TCP传输问题,如黏包,半包
- epoll空轮询导致cpu 100%
- 对API进行增强,ThreadLocal-->FastThreadLocal,ByteBuffer-->ByteBuf
2、Hello World
-
服务端
public class HelloServer { public static void main(String[] args) throws InterruptedException { //1. 启动器,负责组装netty组件,启动服务器 new ServerBootstrap() //2. BootEventLoop WorkerEventLoop(selector,thread),group组 .group(new NioEventLoopGroup()) //3. 选择服务器的ServerSocketChannel实现 .channel(NioServerSocketChannel.class) //4. boss负责处理连接,worker(child)负责处理读写,决定了worker(child)能执行哪些操作(handler) .childHandler( //5. channel代表和客户端进行读写的通道,Initializer初始化器,负责添加别的handler new ChannelInitializer<NioSocketChannel>() { @Override //与客户端建立连接后被调用 protected void initChannel(NioSocketChannel channel) throws Exception { //6. 添加具体的handler channel.pipeline() //将传输过的ByteBuf转换为字符串 .addLast(new StringDecoder()) //添加自己的业务处理,自定义的handler .addLast(new ChannelInboundHandlerAdapter(){ @Override //读事件 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { //打印转换好后的字符串 System.out.println(msg); } }); } }) //7. 绑定监听端口 .bind(8080).sync(); } }
-
客户端
public class HelloClient { public static void main(String[] args) throws InterruptedException { //1. 启动类 new Bootstrap() //2. 添加EventLoop .group(new NioEventLoopGroup()) //3. 选择客户端channel实现 .channel(NioSocketChannel.class) //4. 添加处理器 .handler(new ChannelInitializer<NioSocketChannel>() { @Override //在连接建立后被调用 protected void initChannel(NioSocketChannel channel) throws Exception { //编码器,将要发送的消息转为ByteBuf channel.pipeline().addLast(new StringEncoder()); } }) //5. 连接到服务器 .connect(new InetSocketAddress(8080)) //阻塞方法,知道连接建立 .sync() //代表连接对象 .channel() //6. 向服务端发送数据 .writeAndFlush("hello server"); } }
-
执行流程
-
概念理解
- 把 channel 理解为数据的通道
- 把 msg 理解为流动的数据,最开始输入是 ByteBuf,但经过 pipeline 的加工,会变成其它类型对象,最后输出又变成 ByteBuf
- 把 handler 理解为数据的处理工序
- 工序有多道,合在一起就是 pipeline,pipeline 负责发布事件(读、读取完成...)传播给每个 handler, handler 对自己感兴趣的事件进行处理(重写了相应事件处理方法)
- handler 分 Inbound 和 Outbound 两类
- 把 eventLoop 理解为处理数据的工人
- 工人可以管理多个 channel 的 io 操作,并且一旦工人负责了某个 channel,就要负责到底(绑定)
- 工人既可以执行 io 操作,也可以进行任务处理,每位工人有任务队列,队列里可以堆放多个 channel 的待处理任务,任务分为普通任务、定时任务
- 工人按照 pipeline 顺序,依次按照 handler 的规划(代码)处理数据,可以为每道工序指定不同的工人