Netty 相关问题
传统网络编程存在的问题
传统网络编程存在以下问题:
- 线程创建开销:在Java中,创建线程需要调用操作系统API,这会消耗资源和时间。
- 内存占用高:线程本身占用内存,创建过多线程会导致内存资源紧张。
- CPU使用率高:线程在等待时需要进行上下文切换,这会增加CPU的负担。
改进,使用线程池:
- 优点:可以减少线程频繁创建、销毁的开销。
- 缺点:线程池中的线程可能会因为客户端处理时间长而被阻塞,导致资源浪费。
再改进,使用 NIO 网络通信非阻塞编程。
- 优势:NIO 网络编程也是使用线程池,但是它是非阻塞的。这就解决了
线程池版网络编程中的阻塞问题。
BIO、NIO和AIO的区别?
BIO、NIO和AIO是Java中网络编程的三种不同的I/O模型,它们各自有不同的特点和适用场景。以下是它们的主要区别:
-
BIO(Blocking I/O,阻塞I/O):在BIO模型中,服务器为每个客户端连接都创建一个线程来处理,这意味着每个线程都是阻塞的,即在等待I/O操作完成时,线程会被挂起,直到操作完成。
-
优点是模型简单,易于理解和使用。
-
缺点是当客户端数量增多时,线程数量也会线性增加,这会导致资源消耗大,性能下降,特别是在高并发场景下。
-
-
NIO(Non-blocking I/O,非阻塞I/O):NIO是Java 1.4版本引入的,它支持面向缓冲区的I/O操作,可以更高效地处理数据。NIO使用缓冲区(Buffer)和通道(Channel)来进行数据的读写,而不是使用传统的流(Stream)。
-
它支持非阻塞模式,可以通过Selector来管理多个Channel,一个线程可以同时处理多个Channel的I/O请求。
-
优点是减少了线程的创建和销毁,提高了资源利用率和系统吞吐量。
-
-
AIO(Asynchronous I/O,异步I/O):AIO是Java 7版本引入的,它支持真正的异步I/O操作。
-
在AIO模型中,I/O操作是异步的,当发起一个I/O请求后,系统会立即返回,不会阻塞当前线程,当I/O操作完成时,系统会通过回调函数来通知应用程序。
-
优点是进一步提升了性能,减少了线程的阻塞时间,提高了系统的响应速度。
-
NIO 如何实现同步非阻塞的?
NIO 包含3个核心组件:Channel(通道)、Buffer(缓冲区)、Selector(选择器)监管者。

Channel
Channel:NIO 中的 Channel 是通信的管道,类似于InputStream、OutputStream。用于读取和写入数据。因为Channel没有方向性,所以Buffer为了区分读写,引入了读模式、写模式进行区分。
Channel本身不能直接访问数据,只能与Buffer进行交互,所有的数据都是通过Buffer进行交互的。
Buffer
Channel读取或者写入的数据,都要写到Buffer中,才可以被程序操作。因为Channel没有方向性,所以Buffer为了区分读写,引入了读模式、写模式进行区分。
- 最常用的是
ByteBuffer。
NIO包中有多种Channel的实现:
FileChannel:用于读取、写入、映射和操作文件的通道。DatagramChannel:能通过UDP读写网络中的数据。SocketChannel:能通过TCP读写网络中的数据。ServerSocketChannel:可以监听新进来的TCP连接,对每一个新进来的连接都会创建一个SocketChannel。
半包、粘包
在NIO中,Buffer是NIO中存放数据的地方。假设在客户端发送了三句话,服务端接收数据时,计算机无法理解文本本身的含义,它只会按照Buffer设置的容量来截断数据,此时就会出现粘包、半包问题。比如下图:

- 粘包(包含完整的一句话,但又包含了其他句子的部分):第一次读取的数据为
Hi sunshuai\nI l,发现此次接收的数据包含了第一句、第二句的部分,这种情况就是粘包。 - 半包(一句话只读取到了部分):第二次读取时,对于第二句
I love you\n,本次只读取了ove you\n;对于第三句Do you love me?\n只读取了Do you。像这种Buffer中包含第二句的结尾和第三句的开头,这就是半包。
处理办法:
- 将句子进行特殊处理,比如以
\n作为结束标志。在读取的时候读取到\n就知道是一句完整的话。 - 使用
compact()方法 进行处理,把第一次没有读取完的数据,向前移动和后面的内容进行整合。
Seletor(选择器)循环监听事件
在不使用Seletor时,需要不断的进行while()循环来进行监听客户端的连接、数据发送等动作。
而使用Seletor之后,Seletor就相当于一个监管者,它负责监控是否有客户端发送连接、客户端是否发送数据了。如果有,再去执行代码,这样就不用一直傻傻的where死循环了。
Seletor并不是时时刻刻都处于监管状态,而是达到某些特殊的状态时才会触发监管。这些特殊状态有(一般只在服务端使用):ACCEPT:即 服务端同意了客户端的连接,他们建立连接的时候。===》ServerSocketChannelREAD、WRITE:IO 通信的读写。===》SocketChannel 时
Selector 的主要操作:
-
创建监管者:
Selector selector = Selector.open(); -
指定被监控对象:(这里会监控
serverSocketChannel的ACCEPT 连接状态) -
SelectionKey selectionKey = serverSocketChannel.register(selector, 0, null); -
selectionKey.interestOps(SelectionKey.OP_ACCEPT); -
进入阻塞等待模式:
selector.select(); -
只有当监控到了 有实际的
连接或者读写操作 ,才会处理。

reactor 模式
上面的 selector 作为监管者,监控服务端的ServerSocketChannel、(所有)客户端的SocketChannel【多路复用】。对服务端进行读、写操作的监控。
会发现,selector 既要监控客户端的连接动作,还要监控 读、写动作,效率比较低。reactor 将连接器、读写操作分别使用不同线程来负责,这样效率就会提升。
- 主线程:负责连接器工作;
- 从(子)线程:负责与客户端进行读写的交互操作。
零拷贝
NIO 之所以快,主要是它使用了零拷贝。接下来讲讲零拷贝为什么快。
普通的IO操作
-
首先,要知道一个Java 程序在内存中是分为:用户区(存储用户程序用到的何种数据)、内核区(内核空间为内核保留,是与操作系统打交道的区域)。具体到 java 程序中,
JVM 中的内存对应用户区域的地址空间、操作系统中的内存就对应内核区的地址空间。
-
而Java程序在IO操作时,时需要4次数据拷贝的:
-
读取文件:【两次数据拷贝】
-
先调用驱动程序将 物理硬盘中的文件数据 拷贝到 操作系统的高速页缓存中;
-
然后再将 高速页缓存 中文件数据 拷贝到 用户地址空间的应用缓存 中。
-
-
通过网络 发送数据:【两次数据拷贝】
-
先将用户地址应用缓存的数据 写入(拷贝)至 操作系统的 socket 缓存中;
-
然后再将socket 缓存中的数据 写入(拷贝)至 网卡中。
-

-
改进:内存映射
在NIO中,可以调用内存映射相关的API。内存映射就是可以将 JVM 中的堆内存 与 操作系统内存 之间映射,此时 JVM 中 java 程序就直接操作的是 OS(操作系统)中的内存。

不足::内存映射只是优化了 读取 的操作。而写操作依然需要经过 JVM 内存 --> 操作系统内存 --> 网卡。
再改进:零拷贝
零拷贝是指没有 JVM 参与的拷贝。只有操作系统与硬件之间的拷贝,零拷贝是 linux 内核实现的功能。具体如下:

- linux2.1中的零拷贝
sendFile():物理硬盘---》高速页缓存--》socket 缓存--》网卡。进行了3次拷贝。 - linux2.4中的零拷贝
sendFile():物理硬盘---》高速页缓存--》网卡。只用2次拷贝。
因此,零拷贝速度快。
Netty
Netty是一个NIO客户服务器框架,它能够快速和容易地开发网络应用(如协议服务器和客户端)。它大大精简了网络编程(如TCP和UDP套接字服务器)。
Netty 是基于JAVA NIO类库,其架构特点是:异步非阻塞、基于事件驱动、高性能、高可靠性和高可定制性。
- 事件驱动:是指服务端监控不同的事件,如
accept、read、write。事件驱动的核心是依附于Selector来实现的。 - 异步:是指 Worker 处理客户端的请求(IO 操作)时,让其他线程来完成具体的任务,而 Worker 本身可以继续接收其他客户端的请求。 ==》这种设计思路提升了效率。
Netty的用途:在分布式系统中,通常是跨进程交互的,需要通过网络通信。NIO虽然可以进行网络通信,但是NIO存在以下问题:
- API复杂难用,比如
Buffer的“指针”需要来回切换。 - 存在半包、粘包问题。
- 网络拥塞需要自己解决。
Netty 的心跳机制
TCP中也有类似的机制:保活机制。
-
首先,开启保活机制。

-
探测过程:
- 如果在一段时间内没有数据传输,TCP 会发送一个保活探测报文给对端。这个探测报文通常是一个简单的 ACK 报文,不包含实际的数据。
- 如果对端正常存活,它会回复一个 ACK 报文。这样,连接就被认为是正常的,保活计时器会被重置。
- 如果对端没有回复,TCP 会在一定的时间间隔后再次发送探测报文。经过多次尝试后,如果仍然没有收到回复,TCP 就会认为对端已经断开连接,并关闭连接。
为什么有了TCP保活机制,还需要 Netty 的心跳机制呢?
答:
- 因为 TCP 保活机制 是作用在运输层的,心跳机制 是作用在 应用层上的。
- 如果运输层没问题,但应用层有问题就检测不出来。例如连接的双方网络正常(TCP 保活机制确保了双方是正常的),但是程序本身出现了问题(如死锁),导致双方无法通信。
- 因此才有了 Netty 的心跳机制。它作用在应用层,也就是说如果心跳机制检测双方处于活跃状态,就说明在 应用层、运输层 连接的双方都是活跃的。
Netty 的内存管理
Netty 中的内存相关是通过ByteBuf来实现的。Netty 中的ByteBuf 是对 NIO 的 ByteBuffer封装,Netty 网络通信过程中,底层数据是存储在ByteBuf中。

ByteBuf 的特点:
- 可以自动扩容;
- 提供读写的指针,方便操作。(
ByteBuffer中没有读写指针,所以才需要进行 读模式、写模式的切换) - 引入了内存的池化(类似于 连接池、线程池)
- 对
ByteBuf的操作中,引入了 零拷贝。(netty 中的零拷贝 不是不占用内存,而是尽可能的少占用内存)

- 创建
ByteBuf如果不指定大小,netty 会默认分配256字节。ByteBuf最大可为Integer.MAX_VALUE。- 在
ByteBuf中一个字符占 1 字节;一个 Int 类型占 4 字节。
ByteBuf 扩容规律
- 当容量小于 64 时,扩容规律为
4 的 n 次方。(其实也就是:4、16、64); - 当容量超过 64 时,扩容规律为
原有大小*2。但不可超过ByteBuf的最大值Integer.MAX_VALUE。
ByteBuf 的内存结构
ByteBuffer中需要来回切换 读、写模式。在ByteBuf中没有读、写模式了,不用来回切换。而是使用读、写指针。

ByteBuf 的内存释放
ByteBuf 的内存释放:①使用池化技术时,内存释放是将内存放回内存池中,并没有销毁;②不使用池化技术时,如果使用堆内存(而没使用直接内存),内存释放是否立即销毁 需要看 GC 的处理。
由于 Netty 在处理内存释放时,考虑到内存释放的情况复杂,Netty 让编程人员使用时,设计了统一的内存释放的接口。它是通过使用RefrenceCounted接口实现的。RefrenceCounted引用计数器,当ByteBuf的引用计数器为 0 时,表示ByteBuf可以被回收。
Netty 和 Tomcat 的区别?
-
功能定位:
- Netty:是一个异步事件驱动的网络应用程序框架,主要用于构建高性能的网络通信服务器和客户端。
- Tomcat:是一个 Java Web 应用服务器,主要用于运行 Java Servlet 和 JavaServer Pages(JSP)等 Web 应用程序。
-
处理协议:
- Netty:可以处理多种网络协议,不仅限于 HTTP,还包括自定义协议等。
- Tomcat:主要针对 HTTP 协议进行处理,也可以支持其他协议(可以通过插件等方式扩展),但对其他协议的支持相对较弱。
-
使用场景:
- Netty:适用于需要自定义网络通信协议、对性能要求极高的场景,如金融交易系统的通信中间件、游戏服务器等。
- Tomcat:主要用于部署和运行 Java Web 应用,如企业内部管理系统、电子商务网站等。
相关文章:
Netty 相关问题
传统网络编程存在的问题 传统网络编程存在以下问题: 线程创建开销:在Java中,创建线程需要调用操作系统API,这会消耗资源和时间。内存占用高:线程本身占用内存,创建过多线程会导致内存资源紧张。CPU使用率…...
JAVA中线程池的详解
1.概念 顾名思义,线程池就是管理一系列线程的资源池,其提供了一种限制和管理线程资源的方式。每个线程池还维护一些基本统计信息,例如已完成任务的数量。 这里借用《Java 并发编程的艺术》书中的部分内容来总结一下使用线程池的好处&#x…...
【PyTorch单点知识】深入了解 nn.ModuleList和 nn.ParameterList模块:灵活构建动态网络结构
文章目录 0. 前言1. 为什么需要 nn.ModuleList 和 nn.ParameterList?2. nn.ModuleList:管理模块的列表2.1 什么是 nn.ModuleList?2.2 创建 nn.ModuleList2.3 动态添加或删除层 3. nn.ParameterList:管理参数列表3.1 什么是 nn.Par…...
vscode创建Python虚拟环境无法激活问题处理
系统环境 win7环境,Python3.7,VScode1.70.3 问题报错: PS C:\Users\Administrator\PycharmProjects\websites> .\venv\Scripts\activate 无法加载文件 C:\Users\Administrator\PycharmProjects\websites\venv\Scripts\Activate.ps1,因为在此系统中禁止执行脚本。有关…...
【Go】Go语言中的基本数据类型与类型转换
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…...
【Python中导入Tkinter模块创建计算器界面】
使用Tkinter库创建计算器界面涉及布局多个控件(如按钮、输入框和标签)以形成一个用户友好的界面。以下是一个基本的步骤和示例代码,展示了如何使用Tkinter创建一个简单的计算器界面。 步骤 导入Tkinter库:首先,你需要…...
中关村科金推出得助音视频鸿蒙SDK,助力金融业务系统鸿蒙化提速
鸿蒙生态大势所趋,各种应用适配加速 近日,华为纯血鸿蒙系统(HarmonyOS NEXT)再度引发市场高度关注。据媒体消息,鸿蒙NEXT Beta版将在9月24日对Mate 60系列、X5系列、Pura70系列等16款旗舰机型进行推送,这已…...
如何实现视频数据的PES打包和传输?
实现视频的PES(Packetized Elementary Stream)打包和传输涉及多个步骤,主要包括视频数据的编码、PES打包、以及通过网络协议的传输。以下是大概的实现思路: 一、视频数据编码 原始视频数据获取: 获取需要传输的原始视…...
【软考】程序设计语言基础
【软考】程序设计语言基础 一.程序设计语言基础概念 计算机要通过程序或指令来控制才能完成各种任务。程序设计语言(计算机语言):人与机器交换信息的语言。 1.程序设计语言 计算机语言大致分为机器语言、汇编语言和高级语言三种。机器语言…...
野指针与空指针的异同
1、什么是野指针 在了解什么是野指针之前我们要知道什么是指针即指针的定义是什么。 指针:是一种特殊的变量类型,它存储的是一个内存地址,该地址指向另一个变量的位置。可以通过指针来间接访问和修改该地址所指向的变量的值。 PSÿ…...
虚拟存储器“大观”,讲解核心逻辑知识和408大题方法
虚拟存储器 写在前面:虚拟存储器(Virtual Memory)是计算机系统中用于管理内存的一种技术,它通过虚拟地址空间为进程提供比物理内存更大的地址空间,同时实现内存保护和进程隔离。 在408整个体系中计组和操作系统都有涉…...
【AI赋能医学】基于深度学习和HRV特征的多类别心电图分类
一、数据集简介 论文中使用了来自三类不同心电图记录的162条数据,这些数据来自三个公开的数据库: MIT-BIH 心律失常数据库 (ARR) 96条记录,主要包含不同类型的心律失常样本。 MIT-BIH 正常窦性心律数据库 (NSR) 36条记录,包含健…...
速盾:做外贸用高防cdn需要国外节点的吗?
在进行外贸业务时,使用高防CDN(Content Delivery Network)可以带来很多好处,如提高网站的访问速度、降低服务器负载、保护网站安全等。然而,是否需要国外节点的高防CDN则取决于具体的需求和情况。 高防CDN是通过在全球…...
单片机中为什么要使用5v转3.3v,不直接使用3.3V电压
5V和3.3V是常见的电压水平,在技术上都有其特定的应用场景。为了保护电路、提升效能和确保系统的稳定运行,经常需要将5V转换为3.3V。 1.为什么要5V来供电 使用5V是因为部分传感器需要5V的供电,并且我们数据线一般都输出5V电压,而…...
SpringBoot项目请求返回json空字段过滤
接口返回的json中有的字段可能是为空的,我们不希望他为空的还返回,如下例子: 解决方案:只需要加一个配置类就行: import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.Dese…...
linux下进程详解
在 Linux 系统中,进程是计算机执行程序的基本单位。理解进程的概念和管理方法对系统管理员和开发者都非常重要。下面是对 Linux 下进程的详细介绍: 进程的基本概念 进程:进程是程序在计算机上执行的一个实例。每个进程都有自己独立的内存空间…...
春招审核流程优化:Spring Boot系统设计
1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及,互联网成为人们查找信息的重要场所,二十一世纪是信息的时代,所以信息的管理显得特别重要。因此,使用计算机来管理大学生入学审核系统的相关信息成为必然。开…...
QT:音视频播放器
目录 一.播放器设计 二.需要使用的控件 三.选择视频 四.播放视频 五.暂停视频 六.关闭视频 七.播放状态设置 八.切换视频(上一首) 九.切换视频(下一首) 十.设置视频滑块 十一.更新滑块显示 十二.实现效果 十三.代码设计 1.mainwindow.h 2.mainwindow.cpp 一.播放…...
大模型入门 ch 03:注意力机制
本文是github上的大模型教程LLMs-from-scratch的学习笔记,教程地址:教程链接 Chapter 3: Attention Mechanism 本文首先从固定参数的注意力机制说起,然后拓展到可以训练的注意力机制,然后加入掩码mask,最后…...
STM32点亮第一个LED
还有第二个,并轮换。 准备入门STM32,于是拿出了买到手至少2年的洋桃M1板子,STM32F103C8T6 配置有3个LED,3个按钮,RS232,RS485,CAN,有JTAG,有RTC电池,IO口引…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...
【LeetCode】算法详解#6 ---除自身以外数组的乘积
1.题目介绍 给定一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O…...
6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础
第三周 Day 3 🎯 今日目标 理解类(class)和对象(object)的关系学会定义类的属性、方法和构造函数(init)掌握对象的创建与使用初识封装、继承和多态的基本概念(预告) &a…...
rm视觉学习1-自瞄部分
首先先感谢中南大学的开源,提供了很全面的思路,减少了很多基础性的开发研究 我看的阅读的是中南大学FYT战队开源视觉代码 链接:https://github.com/CSU-FYT-Vision/FYT2024_vision.git 1.框架: 代码框架结构:readme有…...
