当前位置: 首页 > news >正文

Netty详解-02

Netty详解-02

Netty详解-01

先随便聊聊

其实是我遇到的很多疑问的总结:

要netty干嘛?

就一个在线聊天平台,通过springboot + websocket可以快速开发

(在我的其他文章里有Websocket讲解和案例哦)

但他会有很多缺点:

  • 高并发扛不住
  • 延迟高
  • 无法实现复杂需求(清理僵尸用户等)
  • 消息同步困难(分布式)

这些是因为默认用到了tomcat,底层虽然也是nio,但tomcat只提供了WebSocket的基础通信能力

因此就要用netty来开发

tomcat和netty都基于nio,不是tomcat基于netty

后端项目中可让tomcat处理传统http请求,netty处理websocket长连接

Websocket是网络应用层协议(和http一层)

不是说netty可以 替代 Websocket实现在线聊天,而是用netty 结合 Websocket可以让效果更好

netty要实现长连接基于Websocket(不过WebSocket只是Netty支持的其中一种长连接方案,并非只有Websocket才能实现长连接)

长连接的本质是TCP连接不主动关闭

netty可以基于TCP自定义长连接,更底层

请求与连接

注意请求和连接的区别:

连接:本质是TCP连接(如HTTP短连接、WebSocket长连接),是客户端与服务端之间的通信通道(对应 Netty 的Channel

请求:是连接上传输的业务数据单元(如HTTP的一次GET/POST、WebSocket的一条聊天消息)

要发送请求→ 建立连接→ 传输请求(因请求诞生连接,连接上跑请求)

连接由IO线程管理,分发给工作线程处理

IO线程少(CPU 核心 ×2)

工作线程多(20~100 个,按需调整)

TCP是面向连接、保证可靠传输但实时性稍低的协议,UDP是无连接、不保证可靠传输但实时性极高的协议

IO线程管连接,连接(http短连接(跑一次请求),websocket长连接(跑n次请求))上跑请求

工作线程管业务

IO线程调用工作线程,前者不阻塞,后者容易阻塞

请求传输流程

  1. 前端通常通过axios发送请求,axios基于(封装)XHR(XmlHttpRequest)
  2. XHR包装请求数据(请求路径、请求头、请求体)
  3. 浏览器通过Http协议将请求数据转为Http请求报文(二进制,包含请求行、请求头、请求体)
  4. 浏览器调用操作系统的网络模块,让TCP给Http报文加上TCP头并传给电脑网卡
  5. 网络层模块给这个TCP段(TCP头+Http报文)添加IP头
  6. 网卡将二进制数据转为电信号,并通过网线传输
  7. 到达路由器,路由器解析目标IP,判断是否要发到外网
  8. 若需要,路由器则将电信号传给光猫(光纤宽带)
  9. 光猫将电信号转为光信号并传给外部(小区分光箱、城域网、互联网骨干网(国家级网络高速路))
  10. 互联网骨干网根据目标IP将光信号不断转发到对应机房
  11. 机房光模块将光信号转回电信号,再传回网卡
  12. 网卡将电信号再转为二进制数据交给操作系统
  13. 操作系统根据TCP头中的目标端口(比如 8080),把二进制数据交给正在监听该端口的应用层服务器(Tomcat/Netty)
  14. Tomcat/Netty解析二进制数据中的Http报文,提取出请求路径、参数、请求体,分发到对应的后端业务代码(Controller/Servlet)
  15. 业务代码处理请求(查库、逻辑计算),生成响应数据
  16. Tomcat/Netty把响应数据包装成Http响应报文(二进制),交给服务器操作系统 + TCP
  17. 响应报文通过原物理链路(机房→骨干网→光猫→路由器→客户端网卡)转回电信号,再转为二进制数据
  18. 客户端操作系统 + TCP 把二进制数据交给浏览器,浏览器解析Http响应报文,提取响应体
  19. 浏览器通过XHR把响应体回传给axios,axios转换为JSON后,交给前端代码处理(比如渲染页面)

前端代码 -> 浏览器 + Http -> 客户端操作系统 + TCP/IP -> 网卡 -> 路由器 -> 光猫 -> 外部网络 -> 机房 -> 网卡 -> 服务端操作系统 -> 服务器(netty)-> 后端代码 -> 服务端操作系统 -> 原物理链路 -> 客户端操作系统 -> 浏览器 -> 前端代码(axios)

  1. 应用层(HTTP):包装请求数据→HTTP报文(二进制)
  2. 传输层(TCP):给HTTP报文加TCP头(含目标端口、源端口等)→TCP段
  3. 网络层(IP):给TCP 段加IP头(含目标IP、源IP等)→IP数据报
  4. 数据链路层(网卡):给IP数据报加帧头→数据帧,转为电信号 / 光信号传输

Netty总体流程结构:!!!

重点:

  1. 配置(IO线程池、Channel、Pipeline(Handler))、启动

    Bootstrap(一个EventLoopGroup(WorkerGroup))配置客户端

    ServerBootstrap(两个EventLoopGroup(BossGroup(接收连接)、WorkerGroup(处理IO)))配置服务器

    EventLoop就是IO线程 + Selectot + 任务队列(存放轻量的非IO任务),EventLoopGroup是EventLoop集合

  2. 一个IO线程对应一个Selector(通常1:1,也可以1:n)

  3. 一个Selector监控多个Channel

  4. 每个Channel绑定Pipline

  5. 每个Pipline对应多个Handler(Pipeline是Handler的双向链表)

  6. Buffer存放具体数据,通过Channel发送

  7. 连接到来时,BossGroup中的IO线程建立连接,并将Channel注册到WorkGroup中的某个IO线程的Selector下

  8. 当有Channel就绪时(连接建立、可读(来数据)、可写(有对象))(就绪不代表Buffer有数据,不要局限)

  9. Selector告知IO线程(WorkGroup)

  10. IO线程调用对应Channel的Pipline,依次执行所有Handler

  11. IO线程自己执行轻量级操作(解码、编码)

  12. IO线程将业务逻辑Handler交给工作线程池(非IO线程)处理

  13. 处理结果(对象)在服务器一侧编码为二进制字节流,再存入Buffer(例如ByteBuf),通过Channel传给客户端

  14. 客户端(浏览器Http客户端 或者 netty客户端)一侧重复8~13(netty客户端并非刚需,只有我们不想使用浏览器这种情况时,才自定义客户端,netty客户端和浏览器作用相同)

在开始下面的详解前,一定要先自己了解一下nio、netty核心组件(我的另一篇文章有哦!)

然后好好理清楚上面13条的流程结构,我觉得一定一定对你有所帮助!!!

NIO详解

netty底层就是nio,所以,得学

以前java基础中的io操作中,FileInputStream这种就是BIO(阻塞的)

其他基本概念可查看Netty详解-01

三大组件

Channel

Channel是双向通道,FileInputStream这种是单向的

常见:

  • FileChannel
  • SocketChannel
  • ServcerSocketChannel
Buffer

Buffer负责临时存储输入Channel或者从Channel输出的数据

常见:

  • ByteBuffer
    • MappedByteBuffer
    • DirectByteBuffer
    • HeapByteBuffer
  • IntBuffer
  • CharBuffer
Selector

服务器设计演化:

  1. 单线程版本:所有连接共用一个线程(完全不并发)

  2. 多线程版本:每个连接对应一个线程(无节制创建线程)

  3. 线程池版本:复用线程

  4. selector版本:多路复用优化

    selector充当监控的作用,一个selector监控多个channel,只要有channel传来了数据,selector将其交给IO线程处理

  5. 主从Reactor版本

接下来根据nio中常用组件进行讲解

注意:

nio中buffer、channel都有很多种,但是在netty使用中不用特别关心用哪种(你也可以直接去看Netty详解

关于Buffer:Netty只用ByteBuf,且默认选好了实现

关于Channel:Netty按场景自动绑定

服务端用ServerBootstrap配置时,指定NioServerSocketChannel

客户端:用Bootstrap配置时,指定NioSocketChannel

后续Netty详解会给出一个netty案例,到时候你可以再来这里回味一下

NIO示例

曾经的FileInputStream(BIO):

public class FileInputStreamDemo {public static void main(String[] args) {String filePath = "test.txt";byte[] buf = new byte[1024]; // 缓冲区大小(1KB,可根据文件大小调整,如 4096)int readLen; // 实际读取的字节数try (FileInputStream fis = new FileInputStream(filePath)) {// 循环读取:每次最多读 1024 字节,存入 bufwhile ((readLen = fis.read(buf)) != -1) {// 字节数组转字符串(参数:数组、起始索引、实际长度,避免读取到缓冲区残留数据)System.out.print(new String(buf, 0, readLen));}} catch (IOException e) {e.printStackTrace();}}
}

基于ByteBuffer + FileChannel(NIO)

public class ByteBuffer_demo {public static void main(String[] args) {try(FileChannel channel = new FileInputStream("data.txt").getChannel()){ByteBuffer buffer = ByteBuffer.allocate(10);int len;while ((len = channel.read(buffer)) != -1){System.out.println("read " + len + " bytes");buffer.flip();while (buffer.hasRemaining()){byte b = buffer.get();System.out.println((char)b);}buffer.clear();//                // 直接把缓冲区有效字节转成字符串(无需逐个字节读)
//                System.out.print(new String(buffer.array(), 0, len, "UTF-8"));
//                buffer.clear(); // 切换回写模式}}catch (IOException e){e.printStackTrace();}}
}

对比这两段代码,你会感觉到基础文件操作中,BIO、NIO操作类似,只是后者多加了几个步骤(可控事件更多)

维度BIO(FileInputStream)NIO(FileChannel+ByteBuffer)
核心模型「流模型」:数据是 “流动的字节流”,只能 “从头到尾读”,不能回退、不能跳着读「块模型」:数据是 “块级存储”,缓冲区支持回退(position--)、随机访问(position(100))、部分读取
控制权黑盒封装:底层缓冲区、数据拷贝、读写切换都由框架处理,你只能 “被动接收数据”显式掌控:缓冲区的读写模式、读取位置、剩余数据都由你控制,能 “主动操作数据”
额外能力(复杂场景)几乎没有:无法处理跨缓冲区数据、无法随机访问、无法避免二次拷贝核心能力:支持随机访问(channel.position(100) 直接读第 100 字节)、跨缓冲区数据解析、直接缓冲区(避免二次拷贝)、非阻塞读取(网络 I/O 场景)
适用场景简单需求:小文件读取、文本打印、简单复制(不需要复杂字节操作)复杂需求:大文件处理、自定义协议解析、随机访问文件、网络高并发(和 Netty 等框架配合)

简单来说,BIO这套有很多是框架定好的,NIO允许我们做更加底层丰富的定义

例如,上面我们只是定义了ByteBuffer的大小,但还可以通过 ByteBuffer 的 API 实现位置控制、范围限制、数据压缩、批量读写、直接缓冲区等复杂操作

ByteBuffer概念

FileChannel概念

NIO具体代码后面Netty详解-03再讲吧

现在感觉理清楚概念、组件顺序就好了

Netty详解

就先来一点开胃小菜吧

理不清楚时一定要再去看之前的执行流程!!!

算了我直接粘过来吧:

请添加图片描述

netty服务端编码:

public class HelloServer {public static void main(String[] args) {// 启动器new ServerBootstrap()// 创建线程组(理论上需要:BossEventLoop、WorkerEventLoop用于分配处理连接和处理IO的线程)// 此处只创建BossEventLoop// NioEventLoopGroup:多个NioEventLoop线程// NioEventLoop:是一个IO线程+Selector+任务队列.group(new NioEventLoopGroup())// 选择服务器的ServerSocketChannel实现.channel(NioServerSocketChannel.class)// 添加处理器.childHandler(// 创建一个通道初始化对象new ChannelInitializer<NioSocketChannel>() {@Overrideprotected void initChannel(NioSocketChannel ch) throws Exception {// 通道绑定Pipline(处理器链)ch.pipeline().addLast(new StringDecoder());ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {@Override//父类方法public void channelRead(ChannelHandlerContext ctx, Object msg)//因此不能用protected void channelRead(ChannelHandlerContext ctx, Object msg)//子类不能比父类还保守public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {System.out.println(msg);}});}}).bind(8080);}
}

netty客户端编码:

public class HelloClient {public static void main(String[] args) throws InterruptedException{
//        IO线程 -> Selector -> channel -> Pipline// 启动器new Bootstrap()// 线程组EventLoop.group(new NioEventLoopGroup())// 通道Channel.channel(NioSocketChannel.class)// 处理器链Pipline.handler(new ChannelInitializer<NioSocketChannel>() {@Overrideprotected void initChannel(NioSocketChannel ch) throws Exception {ch.pipeline().addLast(new StringDecoder());}}).connect(new InetSocketAddress("localhost", 8080)).sync().channel().writeAndFlush("hello world");}
}

可以先看看这两段代码

重点理清楚使用时,我们要:

IO线程 -> Selector -> channel -> Pipline

其中IO线程 + Selectot 属于EventLoop

因此:

   ch.pipeline().addLast(new StringDecoder());}}).connect(new InetSocketAddress("localhost", 8080)).sync().channel().writeAndFlush("hello world");
}

}


可以先看看这两段代码重点理清楚使用时,我们要:IO线程 -> Selector -> channel -> Pipline其中IO线程 + Selectot 属于EventLoop因此:**EventLoop -> Channel -> Pipline**
http://www.dtcms.com/a/598246.html

相关文章:

  • 快手网站题怎么做做直播哪个网站好
  • 脚本:使用AWR快照原始数据评估存储性能
  • 嵌入式C语言中指针详解
  • 网站建设要学多久wordpress能否解析万网的域名
  • stm32 printf重定向到USART
  • npu环境docker部署vllm
  • 建站广告爱山东app下载安装健康码
  • 网站网站做员工犯法吗企业建设网站的目的( )
  • SpringBoot面试题11-Bean的生命周期
  • 个人网站建设策划书怎么写经济技术开发区人才网
  • AI搜索优化技术特点与服务模式客观剖析,比较代表性公司优势
  • 网站制作服务公司网站建设具备什么条件
  • c2c网站开发策划别墅外观设计网站推荐
  • 免费建站搜索引擎 网站推广 举例
  • 梧州论坛看点重庆seo网站设计
  • 【SPIE出版丨往届已EI检索】第二届遥感技术与图像处理国际学术会议(RSTIP 2025)
  • 1-Linux驱动开发-内核模块介绍
  • 汽车品牌推广方案知名seo网站优化公司
  • 滕州英文网站建设网络推广营销工具
  • 网站建设太金手指六六二八宿州做网站公司
  • 国外做网站公司能赚钱电商培训方案
  • 比较还做的调查网站桂林网站制作公司
  • 南昌企业网站建设泉州做网站设计公司
  • 做购物网站流程一个人能建网站吗
  • 数字孪生云渲染终极指南(二):从实时云渲染到像素流技术解析
  • 山西 旅游 英文 网站建设怎么快速开发一个网站
  • 网站打开空白页面山西太原网络推广
  • GNN应用:网站结构建模(一)
  • pc网站增加手机站光遇网页制作素材
  • 网站怎么建立视频大连企业网站建设公司