01--Netty--001、Netty初认识

第一节,Netty初认识

Netty的优势
  • 网络应用框架的关注点:
    • I/O模型,线程模型和事件处理模型
    • 易用性API接口
    • 对数据协议、序列化的支持
IO模型
  • IO请求分为两个阶段,调用阶段和执行阶段
    • IO调用阶段:用户进程向内核发起系统调用,即请求数据发出的过程
    • IO执行阶段:内核等待IO请求处理完成(包括网络IO和磁盘IO)返回。又可分为两个阶段
      • 等待数据就绪,写入内核缓存区,即你需要的数据,已经写入的内存中,但是无法给用户来使用
      • 将内核缓存区数据拷贝到用户态缓存区,此过程正是将数据拷贝到用户可以使用的内存中,让用户使用
  • 五种IO模型
    • 同步阻塞IO
    • 同步非阻塞IO
    • IO多路复用
    • 信号驱动IO:内核通过信号通知用户态可以获取结果,用户态发起请求,获取结果
    • 异步IO:数据处理完成,直接从内核缓冲区拷贝到用户缓冲区,无需由用户缓存区,再发起一次获取数据的请求
  • Netty的IO模型
    • 基于非阻塞IO模型,底层依赖的是JDK NIO框架的多路复用器Selector,一个多路复用器Selector可以同时轮询多个Channel,采用epoll模式后,只需要一个线程负责Selector的轮询,就可以接入成千上万的客户端
    • 当数据准备就绪时,需要一个事件分发器,有两种设计模式
      • Reactor:采用同步IO,适合处理耗时短的场景,对于耗时长的IO操作容易造成阻塞
      • Proactor:采用异步IO,实现逻辑复杂
  • Netty相比于JDK NIO的优势
    • 易用性,JDK NIO很多复杂的概念,Netty进行了封装
    • 稳定性
    • 可扩展性
      • 可定制化线程模型(源码重点)
      • 可扩展的事件驱动模型,将框架层和业务层的关注点分离(额。。。,后面关注源码看看)
    • 更低的资源消耗
      • 对象池复用技术
      • 零拷贝技术

第二节、Netty开始

Netty整体架构
  • 三部分:Protocol负责服务之间的协议定义,相当于语言,而Transport用于将数据进行传递,而核心逻辑有Core服务提供支持
    • Core核心层
      • 提供了底层网络通信的通用抽象和实现,包括可扩展的事件模型、通用的通信API、支持零拷贝的ByteBuf等
    • Protocol Support协议支持层
      • 基本上支持了主流协议的编码实现
    • Transport Service传输服务层
      • 提供了网络传输能力的定义和实现方法。支持Socket HTTP隧道
  • 那么Netty如何分层呢???
Netty的逻辑处理架构
  • 为典型的网络分层架构设计
    • 网络通信层
    • 事件调度层
    • 服务编排层
网络通信层
  • 核心组件
    • BootStrap
    • ServerBootStrap
    • Channel
BootStrap & ServerBootStrap
  • BootStrap是引导的意思,主要负责整个Netty程序的启动、初始化、服务器连接等过程,相当于一条主线,串联了Netty的其他核心组件
  • BootStrap用于连接远端服务器,只绑定一个EventLoopGroup
  • ServerBootStrap用于服务端启动绑定本地端口,会绑定两个EventLoopGroup,通常称为Boss和Worker
    • Boss用来不断接受新的连接
    • Worker用来进行做事情
Channel
  • 通道,是指网络通信的载体,提供了基本的API用于网络I/O操作,提供了与底层Socket交互的能力。
  • 存在多个状态:连接建立,连接注册,数据读写,连接销毁,所以,对于连接而已就是通道,就是Channel相关的状态,随着状态的变化,Channel处于不同的生命周期中,每一个状态都会有一个绑定的回调事件
  • 那么Channel在不同生命周期时,具体执行的业务逻辑,或者谁来执行Channel所绑定的事件呢???答案就是事件调度层来执行
事件调度层
  • 事件调度层就是执行Channel中绑定的事件,职责是通过Reactor线程模型对各类事件进行聚合处理,通过Selector主循环线程集成多种事件(I/O事件、信号事件、定时事件等),实际的业务处理逻辑是交由服务编排层相关的Handler完成。
  • 核心组件:EventLoopGroup、EventLoop
EventLoopGroup & EventLoop
  • EventLoopGroup本质是一个线程池,负责接收I/O请求,并分配线程执行处理请求
  • EventLoopGroup、EventLoop、Channel的关系
    • 一个EventLoopGroup往往包含一个或者多个EventLoop.EventLoop用于处理Channel生命周期内的所有I/O事件,如accept、connect等I/O事件
    • EventLoop同一时间会与一个线程绑定,每个EventLoop负责处理多个Channel
    • 当一个连接到达时,Netty 就会注册一个 Channel,然后从 EventLoopGroup 中分配一个 EventLoop 绑定到这个Channel上,在该Channel的整个生命周期中都是由这个绑定的 EventLoop 来服务的。
事件编排层
  • 职责:负责组装各类服务,是Netty的核心处理链,用以实现网络事件的动态编排和有序传播(感觉有点责任链的样子呀,后面看看具体的源码逻辑)
  • 核心组件
    • ChannelPipeline
    • ChannelHandler
    • ChannelHandlerContext
ChannelPipeline
  • ChannelPipeline负责组装各种ChannelHandler,实际数据的操作交由ChannelHandler进行处理完成。ChannelPipeline可以理解为ChannelHandler的实例列表–内部通过双向链表将ChannelHandler链接在一起
  • ChannelPipeline是线程安全的,因为每一个新的Channel都会对应绑定一个新的ChannelPipeline。一个ChannelPipeline关联一个EventLoop,一个EventLoop仅会绑定一个线程
ChannelHandler & ChannelHandlerContext
  • 没创建一个Channel就会绑定一个新的ChannelPipeline,ChannelPipeline中每加入一个ChannelHandler都会绑定一个ChannelHandlerContext。那么为何要绑定呢
  • ChannelHandlerContext用于保存ChannelHandler上下文,通过ChannelHandlerContext
    • 可以知道ChannelPipeline和ChannelHandler的关联关系(源码看看)
    • ChannelHandlerContext可以实现ChannelHandler之间的交互
    • ChannelHandlerContext包含了ChannelHandler生命周期的所有时间,如connect,bind,read等等

第三节、客户端和服务端启动都干了啥???

基本案例
  • 流程分为:
    • 创建引导器
    • 配置线程模型
    • 通过引导器绑定业务逻辑处理器
    • 配置一些网络参数
    • 绑定端口
  • 代码
    • 启动类
    public class HttpServer {
    
        public void start(int port) throws Exception {
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            try {
                ServerBootstrap b = new ServerBootstrap();
    
                //1. 配置线程池
                b.group(bossGroup, workerGroup)
    
                        //2. 设置Channel
                        //2.1 设置Channel类型
                        .channel(NioServerSocketChannel.class)
                        .localAddress(new InetSocketAddress(port))
    
                        //2.2 设置ChannelPipeline和ChannelHandler
                        .childHandler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            public void initChannel(SocketChannel ch) {
                                ch.pipeline()
                                        .addLast("codec", new HttpServerCodec())                  // HTTP 编解码
                                        .addLast("compressor", new HttpContentCompressor())       // HttpContent 压缩
                                        .addLast("aggregator", new HttpObjectAggregator(65536))   // HTTP 消息聚合
                                        .addLast("handler", new HttpServerHandler());             // 自定义业务逻辑处理器
                            }
                        })
                        .childOption(ChannelOption.SO_KEEPALIVE, true);
    
                //3. 绑定端口
                ChannelFuture f = b.bind().sync();
                System.out.println("Http Server started, Listening on " + port);
                f.channel().closeFuture().sync();
            } finally {
                workerGroup.shutdownGracefully();
                bossGroup.shutdownGracefully();
            }
        }
        public static void main(String[] args) throws Exception {
            new HttpServer().start(8088);
        }
    }
    
    • 逻辑处理类
    public class HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
            String content = String.format("Receive http request,uri:%s,method:%s,content:%s%n",msg.getUri(),msg.getMethod(),msg.content().toString(CharsetUtil.UTF_8));
            FullHttpResponse response = new DefaultFullHttpResponse(
                    HttpVersion.HTTP_1_1,
                    HttpResponseStatus.OK,
                    Unpooled.wrappedBuffer(content.getBytes()));
            ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
        }
    }
    
Netty服务端启动
  • 启动三个步骤
    • 配置线程池
    • Channel初始化
    • 端口绑定
配置线程池
单线程模式
  • Reactor单线程模型所有I/O操作都由一个线程完成,所以只需要启动一个EventLoopGroup即可
  • 代码
    EventLoopGroup group = new NioEventLoopGroup(1);
    ServerBootstrap b = new ServerBootstrap();
    b.group(group)
    
  • 问题:
    • 所有I/O都是一个线程完成,所以单线程模型有非常严重的性能瓶颈
多线程模型
  • 因为Reactor单线程存在问题,那么多线程就出现了,在Netty中使用Reactor多线程模型与单线程模型非常相似,区别在于NioEventLoopGroup可以不需要任何参数,他默认会启动2倍的CPU核数的线程,当然,也可以自定义线程数
  • 代码
    EventLoopGroup group = new NioEventLoopGroup();
    ServerBootstrap b = new ServerBootstrap();
    b.group(group)
    
主从多线程模式
  • 主从多线程Reactor模型。Boss是主Reactor,Worker是从Reactor。他们分别使用不同的NioEventLoopGroup,主Reactor负责处理Accept,然后把Channel注册到从Reactor上,从Reactor主要负责Channel生命周期内的所有I/O事件。
  • 代码
    EventLoopGroup bossGroup = new NioEventLoopGroup();
    EventLoopGroup workerGroup = new NioEventLoopGroup();
    ServerBootstrap b = new ServerBootstrap();
    b.group(bossGroup, workerGroup)
    
Channel初始化
设置Channel类型
  • NIO模型是Netty中最成熟且被广泛使用的模型,因此,推荐Netty服务端小勇NioServerSocketChannel作为Channel类型,客户端采用NioSocketChannel。
注册ChannelHandler
  • Netty中通过ChannelPipeline去注册多个ChannelHandler,每个ChannelHandler各司其职,这样就可以实现最大化的代码复用
  • 如何通过引导器添加多个ChannelHandler或者说是,如何添加ChannelPipeline呢???
    • Channel初始化时都会绑定一个Pipeline,它主要用于服务编排。Pipeline管理了多个ChannelHandler。I/O事件依次在ChannelHandler中传播,ChannelHandler负责业务逻辑处理。
设置Channel参数
端口绑定
  • 代码:bind方法会真正触发启动,sync方法则会阻塞,直至整个启动过程完成
    ChannelFuture f = b.bind().sync();
    
Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值