一、初识Netty

  • Netty 是一一个提供了易于使用的API的客户端/服务器框架
  • 并发高- NIO (非阻塞IO )
  • 传输快-零拷贝

二、阻塞与非阻塞

  • 线程访问资源,该资源是否准备就绪的一种处理方式
    阻塞:线程访问资源时,如遇到资源正在处理,则等待该资源处理完毕
    非阻塞:线程访问资源时,如遇到资源正在处理,则等待访问其它资源,以此类推
    在这里插入图片描述

三、同步与异步

  • 同步和异步是指访问数据的一种机制
    同步:线程在访问数据的时候,等待数据处理完毕返回结果
    异步:线程在访问数据时,不会等待数据处理结果,直接处理下一个数据,数据处理完成后异步通知

四、BIO、NIO、AIO

  • BIO:同步阻塞IO,Block IO
    在这里插入图片描述
  • NIO:同步非阻塞IO,New IO ( Non-Block IO )
    在这里插入图片描述
  • AIO:异步非阻塞IO

生活实例

  • BIO:去上厕所,坑全满,此时我一直光等着,主动观察哪个坑位好了,只要有坑位释放了,我就立马去占坑
  • NIO :厕所坑全满,此时我跑出去抽烟或者做别的事, 然后时不时再主动的去厕所有没有坑释放,如果有坑了自己去占坑
  • 异步阻塞:我在厕所里,等有人好了之后来通知后,然后再去占坑
  • AIO :我在厕所外抽眼玩手机,等有人好了之后来通知我去占坑
    在这里插入图片描述

五、Reactor线程模型

  • 单线程模型 :所有的IO操作都由同一-个NIO线程处理的
  • 多线程模型:由一组NIO线程处理IO操作
    在这里插入图片描述
  • 主从线程模型:一组线程池接受请求, -组线程池处理io
    在这里插入图片描述

六、根据主从线程模型编写Netty的一个小Demo

需求:实现客户端发送一个请求,服务器返回hello netty
步骤:

  1. 首先编写启动类
public class HelloServer {
    public static void main(String[] args) throws InterruptedException {
        //定义一对线程组
        //主线程组,用于接受客户端的连接,但是不做任何处理,跟老板一样,不做事
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        //从线程组,老板线程组会把任务丢给他,让手下线程组去做任务
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            //netty服务器的创建,ServerBootstrap是一个启动类
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)//设置主从线程组
                    .channel(NioServerSocketChannel.class)//设置nio双向通道
                    .childHandler(new HelloServerInitializer());//子处理器,用于处理workerGroup
            //启动server,并且设置8088为启动的端口号,同时启动的方式为同步
            ChannelFuture channelFuture = serverBootstrap.bind(8088).sync();
            //监听关闭的channel,设置为同步方式
            channelFuture.channel().closeFuture().sync();
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }
}
  1. 编写初始化器,channel注册后,会执行里面的相应的初始化方法
public class HelloServerInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel channel) throws Exception {
        //通过SocketChannel获取相应的管道
        ChannelPipeline pipeline = channel.pipeline();
        //通过管道,添加handler
        //HttpServerCodec是由netty自己提供的一个助手类,可以理解为拦截器
        //当请求到服务端时,我们需要做编码,响应到客户端做编码
        pipeline.addLast("HttpServerCodec",new HttpServerCodec());
        //添加自定义的助手类,返回"hello netty"
        pipeline.addLast("customHandler",new CustomHandler());
    }
}
  1. 编写自定义助手类,请求进来后,会执行我们自定义的操作,这里是返回一个"Hello Netty"
public class CustomHandler extends SimpleChannelInboundHandler<HttpObject> {
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, HttpObject httpObject) throws Exception {
        //获取channel
        Channel channel = channelHandlerContext.channel();
        if(httpObject instanceof HttpRequest){
            //显示客户端的远程地址
            System.out.println(channel.remoteAddress());
            //定义发送的数据消息
            ByteBuf content = Unpooled.copiedBuffer("Hello Netty", CharsetUtil.UTF_8);
            //构建一个http response
            FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,content);
            //为响应增加数据类型和长度
            response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");
            response.headers().set(HttpHeaderNames.CONTENT_LENGTH,content.readableBytes());
            //把响应刷到客户端
            channelHandlerContext.writeAndFlush(response);
        }
    }
}
  1. 运行代码后,在浏览器输入http://localhost:8088/即可看到打印出来的"Hello Netty"
    在这里插入图片描述
    Demo源码地址:https://github.com/xiaohuoban00/HelloNetty

Q.E.D.


愿你编码半生,归来仍是少年