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

Linux下的I/O复用技术之epoll

I/O多路复用

指在单个线程或进程中,同时处理多个I/O操作的技术。

旨在提高程序处理多个并发I/O操作的能力,避免程序因等待某个I/O操作而被阻塞。在传统的I/O模型中当程序进行I/O操作时(如读取文件、接受网路数据等),如果数据还未准备好,程序会被阻塞,直到I/O操作完成,这会导致效率低下,尤其是在需要处理大量并发连接的网络应用中。I/O复用技术的核心理念是允许一个进程或线程同时处理多个I/O操作,而不是等待某一个操作完成后再去处理其他任务。通过则何种方式,程序能够在多个I/O之间切换,充分利用系统资源,避免每个I/O事件都创建一个新的线程或进程,从而大大提高效率。在linux中相关技术有select()、poll()、epoll(),程序会通过上述机制同时监控多个I/O事件,并在其中某个文件描述符(或I/O操作)就绪时,进行相应的处理。这样即使有多个I/O操作正在进行,程序也可以及时响应,并继续进行其他任务,从而达到“非阻塞”的效果。

epoll涉及到的系统调用函数

epoll_create()

用于创建一个epoll示例,返回一个文件描述符,程序通过这个文件描述符与epoll实例进行交互。他为事件提供一个内核空间的数据结构,并为之后的epoll_ctl()和epoll_wait()调用提供一个有效的上下文。

int epoll_create(int size);

size:指定内核事件表的初始大小。这个参数在现代linux系统中已没有什么作用,通常   设置为1即可,因为内核会动态调整。

返回值:创建成功返回一个非负值,表示epoll实例的文件描述符,创建失败返回-1,      并设置errno为相应的错误代码。

int epoll_create1(int flags);

flags:创建时指定的额外选项

传入0代表不指定额外选项

EPOLL_CTL_ADD:添加新的文件描述符及其事件EPOLL_CTL_MOD:修改已经注册的文件描述符的事件EPOLL_CTL_DEL:删除文件描述符的注册

传入EPOLL_CLOEXEC:设置文件描述符为执行时关闭,以确保在exec系列函数调用后自动关闭该文件的文件描述符。

epoll_ctl()

用于控制epoll实例中的事件,包括向epoll注册、修改或删除文件                          描述符的I/O事件。

int epoll_ctl(int epfd, int op,int fd, struct epoll_event* event);

epfd:由epoll_create()返回的epoll文件描述符,用于标识epoll实例。

op:操作类型,指示所执行的操作。

EPOLL_CTL_ADD:添加新的文件描述符及其事件EPOLL_CTL_MOD:修改已经注册的文件描述符的事件EPOLL_CTL_DEL:删除文件描述符的注册

fd:需要注册、修改或删除的文件描述符

event:struct epoll_event类型的指针,表示与文件描述符关联的事件类型,这个结构体参数的作用不仅仅是保存文件描述符,他还包含了与该文件描述符关联的事件类型、以及其他用于标识和处理时间的数据

返回值:成功返回0,失败返回-1,并设置errno为相应的错误代码。

..................................................................................................................................................

补:epoll_event数据结构

该结构体定义了与文件描述符关联的事件类型及其他数据

struct epoll_event {uint32_t  events;  //事件类型epoll_data_t data;  //与文件描述符关联的数据,通常为文件描述符或指针
};

其中:

events:表示该文件描述符的事件类型,注意这些事件类型是可以a|b的混合注册的

data:是一个联合体epoll_data_t,用于存储与文件描述符相关的自定义数据,通常用于存储文件描述符本身或替他数据

epoll_data_t可以是:int fd(文件描述符);  void* ptr(指向用户数据的指针)等

..................................................................................................................................................

示例:

struct epoll_event ev;
ev.event = EPOLLIN;  //设置为读取事件
ev.data.fd = server_fd;  //设置文件描述符
int res = epoll_create(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev);

epoll_wait()

用于等待已注册的文件描述符上的事件发生。该函数会阻塞直到至少一个事件发生或者超时。等待并返回已发生的事件。

int epoll_wait(int epfd, struct epoll_event* event, int maxevents, int timeout);

epfd:由epoll_create返回的epoll文件描述符

events:指向epoll_event结构体数组的指针,用于接收已发生的事件。

event是一个数组,用于存储epoll_event类型的结构体,即用于接收发生的事件event。这里的事件是指,在epoll_ctl阶段注册到epoll中的事件event,并且他得已经发生,已经发生的意思是指已注册的文件描述符的状态满足了你注册的事件条件(如:在epoll_ctl阶段为某个文件描述符fd注册了EPOLLIN,当fd上有数据可读时,例如socket接收到网络数据了,那么这个fd上就有数据可以读取了,这个事件就被认为已经发///或者为某个文件描述符注册的EPOLLOUT,当fd可以用来写数据时,比如socket的发送缓冲区有空闲空间时,那么这个fd就可以进行写,这个事件被认为已经发生了)。

epoll_wait()的作用可以这样理解,它的作用就是监听在epoll_ctl注册到epfd中的事件集合,然后将发生的事件传入events数组中,通过遍历这个events可以得到event,通过event的fd和events成员可以得知该fd可以进行events对应操作了(比如:struct epoll_event ev;  ev.fd = fd1;  ev.events = EPOLLOUT,那么我们可以对fd1进行写操作了,write(fd, ....))。

maxevents:指定events数组的大小,即一次最多返回的事件数

timeout:指定等待的超时时间(单位:毫秒)。设置为-1时表示无限等待,设置为0表示                非阻塞,其他正值表示最大等待时间。

返回值:成功则返回已就绪的事件数,即发生的事件数量,失败则返回-1,并设置errno          为相应的错误代码。

示例:

struct epoll_event events[10];
int nfds = epoll_wait(epfd, events, 10, -1);
for (int i = 0; i < nfds; ++i) {if (events[i].events & EPOLLIN) {// 处理可读事件}if (events[i].events & EPOLLOUT) {// 处理可写事件}
}

 综合使用简单示例:

// 创建一个 epoll 实例,返回 epoll 文件描述符
int epfd = epoll_create(1);// 定义一个 epoll_event 结构体变量,用于描述要监听的事件
struct epoll_event ev;// 设置事件类型为 EPOLLOUT,表示监听 "可写" 事件
ev.events = EPOLLOUT;// 绑定要监听的文件描述符(socketfd)到 ev 的 data.fd 字段
ev.data.fd = socketfd;// 将指定的文件描述符(socketfd)注册到 epoll 实例 epfd 中,监听可写事件
epoll_ctl(epfd, EPOLL_CTL_ADD, socketfd, &ev);// 定义一个数组,用来接收 epoll_wait 返回的就绪事件
struct epoll_event events[10];// 调用 epoll_wait,阻塞等待内核检测 epfd 中注册的事件
// -1 表示永远等待,直到有事件发生
int nfds = epoll_wait(epfd, events, 10, -1);// 遍历所有返回的就绪事件
for (int i = 0; i < nfds; ++i) {// 检查当前事件是否包含 EPOLLOUT,可写事件if (events[i].events & EPOLLOUT) {// 取出就绪的文件描述符int fd = events[i].data.fd;// 定义要发送的消息内容const char* message = "hello";// 使用 write 将消息写入到对应的文件描述符ssize_t bytes_written = write(fd, message, strlen(message));// 这里没有做错误检查,实际项目中最好检查 bytes_written 是否出错}
}
// 创建 epoll 实例,返回 epoll 文件描述符
int epfd = epoll_create1(0);// 注意:这里通过一个 open 打开了一个文件,得到一个文件描述符,但它不一定满足下面的 EPOLLIN 事件,
// 只有当 example 文件中有数据时,它才可以被读,才满足该 fd 监听的 / 感兴趣的事件 EPOLLIN,
// 它才可以在 epoll_wait 的时候被添加到 events 中。
int fd = open("example.txt", O_RDONLY);  // 注意:这里应该是 O_RDONLY,不是 0_RDONLY// 定义一个 epoll_event 结构体变量
struct epoll_event ev;// 设置监听的事件类型为 EPOLLIN(可读事件)
ev.events = EPOLLIN;// 将文件描述符 fd 保存到 ev.data.fd 中
ev.data.fd = fd;// 调用 epoll_ctl,将 fd 注册到 epoll 实例 epfd 中,关注可读事件
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);// 定义一个数组,用来存放 epoll_wait 返回的就绪事件
struct epoll_event events[10];// 调用 epoll_wait,阻塞等待 epfd 中注册的文件描述符上有事件发生
int nfds = epoll_wait(epfd, events, 10, -1);// 遍历所有返回的就绪事件
for (int i = 0; i < nfds; ++i) {// 如果当前事件是 EPOLLIN(可读事件)if (events[i].events & EPOLLIN) {// 在这里处理对应的可读文件描述符}
}

epoll底层实现原理

核心组件

①红黑树

epoll内部维护了一颗红黑树,通过红黑树来管理(增加、删除、修改)所有被监控的文件描述符;当调用epoll_ctl增加、删除或修改监控事件时,会在红黑树中插入、移除或更新相应的节点;红黑树的高效查找和插入特性(时间复杂度为O(Logn))使得epoll在管理大量文件描述符时性能优越。

②就绪链表(双向链表)

epoll使用一个就绪链表来保存当前已经触发事件的文件描述符;当某个文件描述符变为就绪状态时(例如数据可读或可写),其对应的事件会被添加到就绪链表中;这使得epoll_wait调用只需直接扫描这个链表,从而避免了向poll或select那样逐个遍历所有的文件描述符。

与内核的交互

epoll是依赖内核中的事件通知机制来工作的,通常通过文件系统(如proc文件系统等)监控文件描述符的状态;每个文件描述符在内核中都有一个对应的事件回调函数,当事件发生时(即通过epoll_ctl添加到红黑树中的event对应的fd满足注册的事件状态时),会触发这个回调函数,将事件添加到就绪链表中,当调用epoll_wait时,内核将扫描就绪链表,并返回链表中的数据。

触发机制

在epoll中,触发机制决定了epoll_wait如何返回文件描述符的事件。这直接影响事件的通知方式和应用程序对文件描述符的处理策略,epoll支持两种触发机制:水平触发和边缘触发。

①水平触发(level triggered

这是epoll默认的触发方式。文件描述符只要处于就绪状态(可读或可写),epoll_wait就会一直返回该事件(调用该方法返回的int值大小中有它一席,并且传入给epoll_wait的events数组也会一直存入这个事件event);无论文件描述符的状态是否变化,只要其仍然满足条件(如缓冲区有数据可读),事件都会重复触发,直到应用程序对其处理完成。

优点:使用简单,适合大多数场景。不容易遗漏事件,即使处理稍有延迟,也可以通过多次调用读取剩余数据。

缺点:对于大量文件描述符,就绪事件可能被重新触发,导致处理效率较低。

struct epoll_event ev;
ev.events = EPOLLIN;  //水平触发是默认的

②边沿触发(edge triggered

事件只会在状态变化时触发(如从不可读变为可读,或从不可写变成可写);如果应用程序没有在事件触发时处理完数据,则不会再次触发,可能导致数据遗漏。

优点:减少了重复通知,提高了系统效率,适合大规模并发场景,支持高性能的非阻塞模式。

缺点:复杂性高,必须一次性读取或写入尽可能多的数据,否则可能会遗漏数据。

struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET;	//设置为边沿触发

epoll工作流程

首先,用户通过调用epoll_create创建一个epoll实例,用于管理所有需要监听的文件描述符(每个epoll实例中都有一个独立的evetnepoll结构体,用于存放通过epoll_ctl方法向epoll对象中添加的事件)。接着,使用epoll_ctl向epoll内部的红黑树中添加、修改或删除需要监听的文件描述符及事件;最后,通过调用epoll_wait等待事件发生,内核会将已经触发的事件加入就绪链表,并将链表中的就绪文件描述符返回给用户程序,从而实现高效的事件驱动模型。

相较于selectpollepoll为什么高效?

以下几个差异导致epoll更高效

1.事件监听和管理方式的不同

select、poll:每次调用select、poll,都需要将所有文件描述符表传递给内核,内   核会对这些文件描述符逐一查其状态,这种查找是线性查找,时间复杂度是O(n), 导致性能开销大,尤其是在文件描述符数量较多时。

epoll使用一个红黑树来存储用户注册的文件描述符事件,文件描述符只需通过   epoll_ctl注册一次;每次epoll_wait时,内核只需检查红黑树上的事件,并通过 一个就绪链表直接返回有事件发生的文件描述符;事件分发是基于回调的机制,无 需线性扫描。

2.数据拷贝的效率

select、poll:每次调用select、poll都需要将文件描述符列表从用户态拷贝到内核 态,再从内核态返回结果到用户态,如果文件描述符很多,这个过程会占用大量的 cpu和内存带宽。

epoll采用共享内存机制,文件描述符只在epoll_ctl注册时传递给内核;内核和用 户空间之间通过共享的就绪链表来传递数据,避免每次调用时的大量拷贝。

3.支持更大的文件描述符集合

select文件描述符数量受到系统常量FD_SETSIZE的限制(通常是1024个)。超过限 制后无法使用。

poll支持更多的文件描述符,但依然需要遍历整个文件描述符列表

epoll支持的文件描述符数量只受限于系统的最大文件描述符数量,理论上可以达到   数十万甚至更多。即使文件描述符数量庞大,只关注有事件发生的文件描述符,效 率依然很高。

4.触发机制的差异

select、poll:只支持水平触发,即只要文件描述符的状态满足条件,每次都会返回, 可能会导致重复处理。

epoll支持水平触发和边缘触发,边缘触发模式下,只有当文件描述符的状态从未满   足到满足时,才会触发事件,进一步减少系统调用的次数,提高性能。

5.线程安全性

epoll是线程安全的(epoll_wait内存实现对共享的就绪事件列表有锁机制保活,确 保线程安全),多个线程可以同时调用epoll_wait,充分利用多核CPU提高并   发  能力。

select、poll:通常需要额外的同步机制来确保多线程访问同一个文件描述符集合时的 线程安全性。

相关文章:

Linux下的I/O复用技术之epoll

I/O多路复用 指在单个线程或进程中&#xff0c;同时处理多个I/O操作的技术。 旨在提高程序处理多个并发I/O操作的能力&#xff0c;避免程序因等待某个I/O操作而被阻塞。在传统的I/O模型中当程序进行I/O操作时(如读取文件、接受网路数据等)&#xff0c;如果数据还未准备好&…...

数据分析管理软件 Minitab 22.2.2 中文版安装包 免费下载

Minitab22.2.2 安装包下载链接: https://pan.baidu.com/s/1cWuDbvcWhYrub01C6QR81Q?pwd6666 提取码: 6666 Minitab软件是现代质量管理统计软件&#xff0c;全球六西格玛实施的共同语言。Minitab 已经在全球120多个国家&#xff0c;5000多所高校被广泛使用。...

chrony服务器(1)

简介 NTP NTP&#xff08;Network Time Protocol&#xff0c;网络时间协议&#xff09;是一种用于同步计算机系统时间的协议是TCP/IP协议族中的一个应用层协议&#xff0c;主要用于在分布式时间服务器和客户端之间进行时钟同步&#xff0c;提供高精准度的时间校正通过分层的时…...

2025.04.26-淘天春招笔试题-第三题

📌 点击直达笔试专栏 👉《大厂笔试突围》 💻 春秋招笔试突围在线OJ 👉 笔试突围OJ 03. 二进制信号转换器 问题描述 卢小姐是一位通信工程师,她设计了一种特殊的二进制信号处理装置。该装置可以对由 0 0 0...

腾讯二面:TCC分布式事务 | 图解TCC|用Go语言实现一个TCC

写在前面 前段时间&#xff0c;有同学反馈的一个面试问题&#xff0c;觉得分布式事务有点偏了&#xff0c;但其实也不算偏了&#xff0c;在java领域就有很火很成熟的seata分布式事务框架(阿里和蚂蚁的同学主导&#xff0c;目前在apache孵化)。 之前我们讲过了两阶段提交、三阶…...

如何在 Conda 环境中降级 Python 版本:详细指南

如何在 Conda 环境中降级 Python 版本&#xff1a;详细指南 Python 版本的管理在开发过程中至关重要&#xff0c;特别是在处理不同项目需求时。对于使用 Conda 环境的 Python 程序员来说&#xff0c;版本管理不仅仅是安装不同的 Python 版本&#xff0c;还涉及到依赖关系的兼容…...

MCP 协议解读:STDIO 高效通信与 JSON-RPC 实战

本文深度解析 MCP 协议的传输机制与消息格式&#xff0c;涵盖 stdio、SSE 及自定义传输方式&#xff0c;剖析 JSON-RPC 2.0 的请求、响应与通知设计。 结合 RooCode 开源实现与天气查询案例&#xff0c;揭秘如何通过 MCP 实现跨进程通信与高效服务集成&#xff0c;为开发者提供…...

AI心理健康服务平台项目面试实战

AI心理健康服务平台项目面试实战 第一轮提问&#xff1a; 面试官&#xff1a; 请简要介绍一下AI心理健康服务平台的核心技术架构。在AI领域&#xff0c;心理健康服务的机遇主要体现在哪些方面&#xff1f;如何利用NLP技术提升用户与AI的心理健康对话体验&#xff1f; 马架构…...

路由器重分发(OSPF+RIP),RIP充当翻译官,OSPF充当翻译官

路由器重分发&#xff08;OSPFRIP&#xff09; 版本 1 RIP充当翻译官 OSPF路由器只会OSPF语言&#xff1b;RIP路由器充当翻译官就要会OSPF语言和RIP语言&#xff1b;则在RIP中还需要将OSPF翻译成RIPOSPF 把RIP路由器当成翻译官&#xff0c;OSPF路由器就只需要宣告自己的ip&am…...

29-算法打卡-字符串-KMP算法理论2-第二十九天

1、KMP算法前缀表计算逻辑 可以查看上一章节的前缀表概念以及逻辑&#xff0c;KMP算法基础理论[基础概念、前缀、后缀、最长公共前后缀、前缀表] 2、KMP算法前缀表使用 当模式串和文本串匹配失败的时候&#xff0c;前缀表会告诉我们下一次的匹配中&#xff0c;模式串应该跳到…...

解锁生成式AI潜力的金钥匙

一、引言&#xff1a;生成式AI的浪潮与“提示词”的崛起 在短短几年内&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;以前所未有的速度席卷全球&#xff0c;从文字创作到图像生成&#xff0c;从代码辅助到科学研究&#xff0c;以ChatGPT、Midjourney、DALL…...

统计定界子数组的数组

前言&#xff1a;看到这个题目的时候&#xff0c;只想着怎么暴力枚举右端点&#xff0c;结合线段树还是会超时&#xff0c;没找到很好的处理方法 超时代码 class Tree1:def __init__(self,n):self.t [0]*(4*n)def update(self,o,l,r,index,va):if lr:self.t[o] vareturnmid …...

JAVA---字符串

ctrlN 搜索界面&#xff08;idea&#xff09; API和API帮助文档 API &#xff1a; 应用程序编程接口&#xff08;换句话说&#xff0c;就是别人已经写好了&#xff0c;我们不需要再编写&#xff0c;直接使用即可&#xff09; Java API &#xff1a;就是JDK中提供的各种功能…...

import tree # pip install dm_tree ModuleNotFoundError: No module named ‘tree‘

在导入tree包时&#xff0c;在python库里找了很久&#xff0c;一直以为是tree这个包没下载好&#xff0c;有的推荐执行 pip install dm_tree这是deepmind开发一个处理处理嵌套数据结构的库。它在某种程度上tree 概括了仅支持扁平序列的内置map函数&#xff0c;并允许将函数应用…...

Java ThreadLocal与内存泄漏

当我们利用 ThreadLocal 来管理数据时&#xff0c;我们不可避免地会面临内存泄漏的风险。 原因在于 ThreadLocal 的工作方式。当我们在当前线程的 ThreadLocalMap 中存储一个值时&#xff0c;一旦这个值不再需要&#xff0c;释放它就变得至关重要。如果不这样做&#xff0c;那么…...

Rule.resource作用说明

1. 说明 作用 Rule.resource 用于定义哪些文件需要被当前规则处理。它是对传统 test、include、exclude 的更底层封装&#xff0c;支持更灵活的匹配方式。 与 test/include/exclude 的关系 test: /.js$/ 等价于resource: { test: /.js$/ } include: path.resolve(__dirname, ‘…...

【Docker项目实战】使用Docker部署Caddy+vaultwarden密码管理工具(详细教程)

【Docker项目实战】使用Docker部署vaultwarden密码管理工具 前言一、vaultwarden介绍1.1 vaultwarden简介1.2 主要特点二、本次实践规划2.1 本地环境规划2.2 本次实践介绍三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本四、拉取镜像五、…...

代码随想录算法训练营第五十九天 | 1.ford算法精讲 卡码网94.城市间货物运输

1.Bellman_ford 算法精讲 题目链接&#xff1a;94. 城市间货物运输 I 文章讲解&#xff1a;代码随想录 思路&#xff1a; 使用dijkstra&#xff0c;要求图中边的权值都为正数。 带负权值的单源最短路问题&#xff0c;轮到Bellman_ford 算法。Bellman_ford算法的核心思想是对…...

shell(1)

1.shell变量介绍 i.Linux Shell中的变量分为,系统变量和用户自定义变量. ii.系统变量:$HOME,$PWD, $SHELL,$USER 例echo $HOME iii.显示当前shell中的所有变量--set 2.shell变量的定义 基本语法 1.定义变量:变量名值 注意 号左右也不能有空格 2.撤销变量:unset 变量 3.声…...

KEPServerEX 6与西门子1500PLC进行OPC通讯

仿真效果与真实环境效果一至&#xff1b; 环境&#xff1a; 西门子软件&#xff1a;博图V20、S7-PLCSIM Advanced V5.0 OPC软件&#xff1a;KEPServerEX 6 创建S7-PLCSIM Advanced V5.0仿真环境 西门子1500plc组态 添加一个1500cpu&#xff0c;注意点击项目文件&#xff0…...

【概念】什么是 JWT Token?

—什么是 JWT Token&#xff1f; JWT Token&#xff08;JSON Web Token&#xff09; 就是一张后端发给前端的小票&#xff0c;里面包含用户身份信息&#xff0c;用于做无状态认证&#xff08;Stateless Authentication&#xff09;。 每次前端访问后端接口&#xff0c;都拿着…...

【Castle-X机器人】一、模块安装与调试:机器人底盘

持续更新。。。。。。。。。。。。。。。 【ROS机器人】模块安装 一、Castle-X机器人底盘1.1 结构概述1.2 驱动执行结构1.3 环境传感器1.4 电气系统1.5 Castle-x机器人底盘测试激光雷达传感器测试及数据可视化超声波传感器实时数据获取防跌落传感器测试陀螺仪测试键盘控制测试…...

NSIS打包

以下是一篇详细的 NSIS 打包 EXE 的入门教程: NSIS 打包 EXE 入门教程 NSIS(Nullsoft Scriptable Install System)是一款开源的 Windows 安装包制作工具,支持脚本化定制安装流程。本教程将带你从零开始,创建一个简单的 EXE 安装程序。 1. 环境准备 1.1 下载 NSIS 访问官…...

62.不同路径

一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的路径&#xff1f; 示例 …...

前端开发中shell的使用场景

Shell语言基础概念 Shell是用户与操作系统内核之间的接口&#xff0c;它接收用户输入的命令并解释执行。在Linux/Unix系统中&#xff0c;Shell是最常用的命令行界面。 基本语法和常用命令 变量定义和使用 # 定义变量 name"张三" age25# 使用变量 echo $name echo…...

基于javaweb的SSM投票管理系统设计与实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…...

uml类关系(实现、继承,聚合、组合,依赖、关联)

drawio和EA是架构设计时经常使用的画图工具。 drawio学习门槛低&#xff0c;使用灵活&#xff0c;但是功能仅仅限于画图。 EA学习门槛高&#xff0c;但是功能更加的丰富&#xff1a; ①在画图方面&#xff0c;EA严格满足UML标准&#xff0c;EA中的图和类是关联的&#xff0c…...

力扣热题100题解(c++)—链表

160.相交链表 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&#xff0c;函数…...

MQ消息的不可靠性发生情况与解决方案

文章目录 问题&#xff1a;可能出现的情况&#xff1a; 解决流程与兜底方案第一个方面&#xff1a;确保生产者一定把消息发送到MQ1.生产者重试机制2.生产者确认机制 第二个方面&#xff1a;确保MQ不会将消息丢失数据持久化交换机持久化2.队列持久化3.消息持久化 LazyQueue控制台…...

线程池(五):线程池使用场景问题

线程池&#xff08;五&#xff09;&#xff1a;线程池使用场景问题 线程池&#xff08;五&#xff09;&#xff1a;线程池使用场景问题1 线程池使用场景CountDownLatch、Future1.1 CountDownLatch原理示例代码 1.2 案例一&#xff08;es数据批量导入&#xff09;需求分析实现步…...

第十六届蓝桥杯网安初赛wp

解题列表 根据提示一步一步走&#xff0c;经过猜测&#xff0c;测试出app.py 经过仔细研读代码&#xff0c;找到密钥 编写python代码拿到flag key secret_key9828 flagd9d1c4d9e0d6c29e9aad71696565d99bc8d892a8979ec7a69b9a6868a095c8d89dac91d19ba9716f63b5 newbytearray(…...

8.学习笔记-Maven进阶(P82-P89)

&#xff08;一&#xff09;Maven-08-配置文件加载属性 通过maven可以做版本的集中管理&#xff0c;所以能不能通过maven进行配置文件&#xff08;jdbc.properties&#xff09;的集中管理。 &#xff08;1&#xff09;resource-》jdbc.properties 可以识别$符号 因为只能…...

基于 IPMI + Kickstart + Jenkins 的 OS 自动化安装

Author&#xff1a;Arsen Date&#xff1a;2025/04/26 目录 环境要求实现步骤自定义 ISO安装 ipmitool安装 NFS定义 ks.cfg安装 HTTP编写 Pipeline 功能验证 环境要求 目标服务器支持 IPMI / Redfish 远程管理&#xff08;如 DELL iDRAC、HPE iLO、华为 iBMC&#xff09;&…...

Ubuntu20.04部署Ragflow(Docker方式)

Ubuntu20.04部署Ragflow&#xff08;Docker方式&#xff09; Ubuntu20.04 RagflowRunning RagflowRunning Ollama 由于写这篇博客的时候电脑还没装输入法&#xff0c;所以先用半吊子英文顶着了…关于最后运行ollama的部分可以无视&#xff0c;因为我修改了端口所以才需要这么运…...

【C++语法】类和对象(2)

4.类和对象&#xff08;2&#xff09; 文章目录 4.类和对象&#xff08;2&#xff09;类的六个默认成员函数(1)构造函数&#xff1a;构造函数特点含有缺省参数的构造函数构造函数特点&#xff08;续&#xff09;注意事项构造函数补充 前面总结了有关对象概念&#xff0c;对比 C…...

JDK 17 与 Spring Cloud Gateway 新特性实践指南

一、环境要求与版本选择 1. JDK 17 的必要性 最低版本要求&#xff1a;Spring Boot 3.x 及更高版本&#xff08;如 3.4&#xff09;强制要求 JDK 17&#xff0c;以支持 Java 新特性&#xff08;如密封类、模式匹配&#xff09;和性能优化。JDK 17 核心特性&#xff1a; 密封类…...

深入了解及掌握AppScan不同测试策略的区别

引言 在当今数字化时代,应用程序安全至关重要。IBM AppScan作为一款强大的应用安全测试工具,提供了多种测试策略以适应不同的测试场景和需求。理解这些测试策略的区别,能够帮助安全测试人员更精准地开展测试工作,发现应用程序中潜藏的安全漏洞。本文将结合实际案例,深入剖…...

【Linux】web服务器的部署和优化

目录 nginx的安装与启用--/usr/share/nginx/html默认发布目录 nginx的主配置文件--/etc/nginx/nginx_conf nginx的端口 nginx默认发布文件--index.html nginx默认发布目录 nginx的访问控制 基于IP地址的访问控制 基于用户认证的访问控制 nginx的虚拟主机--/etc/nginx/…...

20250426在ubuntu20.04.2系统上解决问题mkfs.exfat command not found

20250426在ubuntu20.04.2系统上解决问题mkfs.exfat command not found 2025/4/26 21:11 缘起&#xff0c;使用NanoPi NEO开发板&#xff0c;编译FriendlyCore系统&#xff0c;打包eMMC固件的时候报错。 ./build.sh emmc-img -pack sd-card image, used to write frie…...

IDE使用技巧与插件推荐

一、高效使用技巧 1. 快捷键与操作优化 VS Code: 快速导航:Ctrl+P(Windows/Linux)或Cmd+P(macOS)打开文件搜索,输入文件名快速定位。多光标编辑:按住Alt(Windows/Linux)或Option(macOS)点击多个位置,同时编辑多处代码。Zen 模式:Ctrl+K Z(Windows/Linux)或Cmd…...

防火墙规则配置错误导致的网络问题排查

# 防火墙规则配置错误导致的网络问题排查指南 防火墙规则配置错误是网络连接问题的常见原因之一。以下是一套系统的排查步骤和方法&#xff1a; ## 1. 初步症状确认 - **常见表现**&#xff1a; - 特定服务无法访问 - 网络连接时断时续 - 部分IP地址或端口无法通信 …...

线性代数(一些别的应该关注的点)

一、矩阵 矩阵运算&#xff1a;线性变换 缩放、平移、旋转 无所不能的矩阵 - 三维图形变换_哔哩哔哩_bilibili...

思科路由器重分发(静态路由+OSPF动态路由+RIP动态路由)

路由器重分发&#xff08;静态路由OSPF动态路由RIP动态路由&#xff09; 开通端口并配置IP地址 OSPF路由 R1 Router>en Router#conf t Router(config)#int g0/0 Router(config-if)#no shut Router(config-if)#no shutdown Router(config-if)#ip add 192.168.10.254 255.…...

2.3java运算符

运算符 1. 算术运算符 算术运算符用于执行基本的数学运算&#xff0c;像加、减、乘、除等。 运算符描述示例加法int a 5 3; // a 的值为 8-减法int b 5 - 3; // b 的值为 2*乘法int c 5 * 3; // c 的值为 15/除法int d 6 / 3; // d 的值为 2%取模&#xff08;取余&…...

元数据驱动的 AI 开发:从数据目录到模型训练自动化

元数据驱动的 AI 开发&#xff1a;从数据目录到模型训练自动化 一、引言 在人工智能技术蓬勃发展的当今时代&#xff0c;AI 开发已成为各行业实现创新的核心驱动力。然而&#xff0c;数据规模爆炸式增长、类型复杂多样、来源分散等问题&#xff0c;导致数据管理混乱、模型训练…...

从OpenAI收购实时数据引擎揭示AI数据库进化方向

第一章&#xff1a;一场技术并购背后的“数据战争” 1.1 OpenAI为何盯上Rockset&#xff1f; 当OpenAI宣布收购Rockset时&#xff0c;数据库圈层炸开了锅。这家成立于2016年的公司&#xff0c;其创始人团队堪称“数据库界梦之队”&#xff1a;CTO Dhruba Borthakur曾主导Face…...

Linux0.11内存管理:相关代码

ch13_2 源码分析 boot/head.s 页表初始化&#xff1a; 目标&#xff1a;初始化分页机制&#xff0c;将线性地址空间映射到物理内存&#xff08;前 16MB&#xff09;&#xff0c;为保护模式下的内存管理做准备。核心流程 分配页目录表和页表的物理内存空间&#xff08;通过 .…...

ShaderToy学习笔记 03.多个形状和旋转

1. 正方形和旋转 1.1. 正方形 要绘制一个正方形&#xff0c;我们需要定义一个点到正方形边界的距离函数。对于中心在原点的正方形&#xff0c;其数学表达式为&#xff1a; 对于一个点 p(x,y) 到正方形边界的距离函数可以表示为: d max(|x|, |y|) - r 其中: |x| 和 |y| 分…...

Arduino+ESP01S烧录

这种办法不使用与ThonnyMircopython 前言 这里我们使用烧录器烧录&#xff0c;淘宝十几块钱一个的东西&#xff0c;ESP01S做一个WIFI继电器还是蛮有用的&#xff0c;就是烧录起来不太方便&#xff0c;传统的办法接线麻烦&#xff0c;需多次上电&#xff0c;也可能因为电源问题…...

什么是Lua模块?你会如何使用NGINX的Lua模块来定制请求处理流程?

大家好&#xff0c;我是锋哥。今天分享关于【什么是Lua模块&#xff1f;你会如何使用NGINX的Lua模块来定制请求处理流程&#xff1f;】面试题。希望对大家有帮助&#xff1b; 什么是Lua模块&#xff1f;你会如何使用NGINX的Lua模块来定制请求处理流程&#xff1f; 1000道 互联…...