libevent 梳理

C10K 背景

C10K问题:如何在一台物理机上同时服务 10000 个用户?这里 C 表示并发,10K 等于 10000?
C10K 问题本质上是一个操作系统问题,需要考虑:
1.文件句柄数:每个客户连接都代表一个文件描述符,一旦文件描述符不够用了,新的连接就会被放弃(可以用 root 权限修改 /etc/sysctl.conf 文件);
2.系统内存:假设每个连接需要 128K 的缓冲区,那么 1 万个链接就需要大约 1.2G 的应用层缓冲;
3.网络带宽:假设 1 万个连接,每个连接每秒传输大约 1KB 的数据,那么带宽需要 10000 x 1KB/s x8 = 80 Mbps。

C10K 问题解决之道
要想解决 C10K 问题,就需要从两个层面上来统筹考虑:
1.应用程序如何和操作系统配合,感知 I/O 事件发生,并调度处理在上万个套接字上的 I/O 操作?
2.应用程序如何分配进程、线程资源来服务上万个连接?

这两个层面的组合就形成了解决 C10K 问题的几种解法方案:
1.阻塞 I/O + 进程
每个连接通过 fork 派生一个子进程进行处理,因为一个独立的子进程负责处理了该连接所有的 I/O,所以即便是阻塞 I/O,多个连接之间也不会互相影响。但是这种方法效率不高,扩展性差,资源占用率高。
2.阻塞 I/O + 线程
进程模型占用的资源太大,还有一种轻量级的资源模型,这就是线程。通过为每个连接调用 pthread_create 创建一个单独的线程,也可以达到上面使用进程的效果。
因为线程的创建是比较消耗资源的,况且不是每个连接在每个时刻都需要服务,因此,可以预先通过创建一个线程池,并在多个连接中复用线程池来获得某种效率上的提升。
3.非阻塞 I/O + readiness notification + 单线程
应用程序其实可以采取轮询的方式来对保存的套接字集合进行挨个询问,从而找出需要进行 I/O 处理的套接字。(select/poll 需要每次 dispatch 之后,对所有注册的套接字进行逐个排查,效率并不是最高的,epoll 在 dispatch 调用返回之后只提供有 I/O 事件或者 I/O 变化的套接字)
4.非阻塞 I/O + readiness notification + 多线程
前面的做法是所有的 I/O 事件都在一个线程里分发,如果我们把线程引入进来,可以利用现代 CPU 多核的能力,让每个核都可以作为一个 I/O 分发器进行 I/O 事件的分发。这就是所谓的主从 reactor 模式。基于 epoll/poll/select 的 I/O 事件分发器可以叫做 reactor,也可以叫做事件驱动,或者事件轮询(eventloop)。

5.异步 I/O+ 多线程
异步非阻塞 I/O 模型是一种更为高效的方式,当调用结束之后,请求立即返回,由操作系统后台完成对应的操作,当最终操作完成,就会产生一个信号,或者执行一个回调函数来完成 I/O 处理。这就涉及到了 Linux 下的 aio 机制。

Linux网络编程 - C10K问题:高并发模型的设计初篇

libevent 简介

libevent 是一个轻量级的开源的高性能的事件触发的网络库,适用于 windows、linux、bsd 等多种平台,内部使用 select、epoll、kqueue 等系统调用管理事件机制。

1.跨平台支持,支持Windows、Linux、BSD和Mac OS;
2.统一事件源,libevent 对 I/O 事件、信号和定时事件提供统一的处理;
3.线程安全,libevent 使用 libevent_pthreads 库来提供线程安全支持。
4.基于 reactor 模式的实现。

libevent API 提供了一种机制,用于在文件描述符上发生特定事件或达到超时后执行回调函数。此外,libevent还支持由于信号或常规超时而导致的回调。
libevent 旨在替换在事件驱动的网络服务器中找到的事件循环。应用程序只需要调用 event_dispatch(),然后动态添加或删除事件,而无需更改事件循环。

libevent 功能

Libevent 提供了事件通知,io 缓存事件,定时器,超时,异步解析 dns,事件驱动的 http server 以及一个 rpc 框架。

  • 事件通知:当文件描述符可读可写时将执行回调函数。
  • IO缓存:缓存事件提供了输入输出缓存,能自动的读入和写入,用户不必直接操作IO。
  • 定时器:libevent 提供了定时器的机制,能够在一定的时间间隔之后调用回调函数。
  • 信号:触发信号,执行回调。
  • 异步的 dns 解析:libevent 提供了异步解析 dns 服务器的 dns 解析函数集。
  • 事件驱动的 http 服务器:libevent 提供了一个简单的,可集成到应用程序中的 HTTP 服务器。
  • RPC 客户端服务器框架:libevent 为创建 RPC 服务器和客户端创建了一个 RPC 框架,能自动的封装和解封数据结构。

总体架构

事件处理框架 - event_base

使用 libevent函数之前需要分配一个或者多个 event_base 结构体。每个event_base 结构体持有一个事件集合,可以检测以确定哪个事件是激活的。每个 event_base 都有一种用于检测哪种事件已经就绪的 “方法”。

event_base API函数

// 头文件
#include <event2/event.h>
// 操作函数
struct event_base * event_base_new(void;          //创建事件处理框架
void event_base_free(struct event_base * base);    //释放事件处理框架// 检查event_base的后端方法
const char** event_get_supported_methods(void;
const char *event_base_get_method(const struct event_base *base);

event_base 和 fork(进程)关系:
1.子进程创建成功之后,父进程可以继续使用 event_base;
2.子进程中 event_base 也会被复制,使用时需要用下面函数重新初始化:

int event_reinit(struct event_base* base);

事件循环

event_base 不停的检测委托的检测是实际是不是发生了,如果发生了,event_base 会调用对应的回调函数,这个回调函数的用户委托检测事件的时候给的。

设置事件循环

如果委托了 event_base 检测某些事件,不停的进行循环检测;
结束检测时间:所有要检测的事件都被触发,并且处理完毕。

// 头文件
#include <event2/event.h>// 操作函数
#define EVLOOP_ONCE 			0x01
#define EVLOOP_NONBLOCK 		0x02
#define EVLOOP_NO_EXIT_ON_EMPTY 0x04int event_base_loop(struct event_base *base, int flags);参数:- base: 通过 event_base_new(void)得到的- flags:- EVLOOP_ONCE: 一直检测某个事件, 当事件被触发了, 停止事件循环- EVLOOP_NONBLOCK: 非阻塞的方式检测, 当事件被触发了, 停止事件循环- EVLOOP_NO_EXIT_ON_EMPTY: 一直进行事件检测, 如果没有要检测的事件, 不退出int event_base_dispatch(struct event_base* base); 	// 一般使用这个函数参数:- base: 通过 event_base_new(void)得到的

终止事件循环

// 头文件
#include <event2/event.h>struct timeval {long    tv_sec;                    long    tv_usec;    // 微秒        
};// 在 tv 时长之后退出循环, 如果这个参数为空NULL, 直接退出事件循环
// 事件循环: 检测对应的事件是否被触发了
// 如果事件处理函数正在被执行, 执行完毕之后才终止
int event_base_loopexit(struct event_base * base, const struct timeval * tv);// 马上终止
int event_base_loopbreak(struct event_base * base);

事件

事件基本操作

事件的创建 event_new

//要检测事件   what:
#define EV_TIMEOUT 	0x01
#define EV_READ 	0x02
#define EV_WRITE 	0x04
#define EV_SIGNAL 	0x08
#define EV_PERSIST 	0x10	// 修饰某个事件是持续触发的
#define EV_ET 		0x20	// 边沿模式//回调函数格式:
typedef void (*event_callback_fn)(evutil_socket_t,shortvoid *);
参数:- 第一个参数: event_new的第二个参数- 第二个参数: 实际触发的事件- 第三个参数: event_new的最后一个参数// 创建事件
struct event* event_new(struct event_base * base,evutil_socket_t fd,short what,event_callback_fn cb,void * arg);
参数:- base: event_base_new得到的- fd: 文件描述符, 检测这个fd对应的事件- what: 监测fd的什么事件 - cb: 回调函数, 当前检测的事件被触发, 这个函数被调用- arg: 给回调函数传参

事件的释放

// 释放事件资源
void event_free(struct event * event);

事件的添加、删除
事件被 new 出之后, 不能直接被 event_base 进行检测,event_add 之后 event_base 就可以对事件进行检测

int  event_add(struct event * ev,const  struct timeval * tv);
参数: tv-> 超时时间, 如果这个值> 0, 比如 == 3检测fd的读事件, 在三秒之内没有触发该事件 -> 超时-> 超时之后, 事件对应的回调函数会被强制调用如果该参数为NULL, 不会做超时检测// 删除要检测的事件
int  event_del(struct event * ev);

事件的优先级设置

// EVENT_MAX_PRIORITIES == 256     最大的初始化事件优先级
int event_base_priority_init(struct event_base * base,int n_priorities);
参数:- n_priorities: 等级的个数, 假设 == 6也就是说有6个等级: 0,1,2,3,4,5, 0优先级最高
// 获取当前可用的等的个数
int event_base_get_npriorities(struct event_base * base);
// 给事件设置等级
int event_priority_set(struct event *event, int priority);
参数:- event: 创建的事件- priority: 要设置的等级

带缓冲区的事件

  1. bufferevent 理解:
    (1)是 libevent 为 IO 缓冲区操作提供的一种通用机制;
    (2)bufferevent 由一个底层的传输端口(如套接字),一个读取缓冲区和一个写入缓冲区组成。
    (3)与通常的事件在底层传输端口已经就绪,可以读取或者写入的时候执行回调不同的是,bufferevent 在读取或者写入了足够量的数据之后调用用户提供的回调。

  2. 每个 bufferevent 有两个数据相关的回调
    (1)读取回调:从底层传输端口读取了任意量的数据之后会调用读取回调(默认);
    (2)写入回调:输出缓冲区中足够量的数据被清空到底层传输端口后写入回调会被调用(默认)。

  • 创建/释放基于套接字的 bufferevent bufferevent_socket_new
struct bufferevent *bufferevent_socket_new(struct event_base *base,evutil_socket_t fd,enum bufferevent_options options); 
参数:- base: 处理事件的- fd: 通信的文件描述符- options: BEV_OPT_CLOSE_ON_FREE -> 自动释放底层资源
返回值: 得到带缓冲区的事件变量// 释放资源
void bufferevent_free(struct bufferevent *bev);
  • bufferevent 上启动连接服务器函数 bufferevent_socket_connect
    (1)如果还没有为bufferevent 设置套接字,调用函数将为其分配一个新的流套接字,并且设置为非阻塞的;
    (2)如果已经为 bufferevent 设置套接字,调用bufferevent_socket_connect() 将告知 libevent 套接字还未连接,直到连接成功之前不应该对其进行读取或者写入操作;
    (3)连接完成之前可以向输出缓冲区添加数据。
int bufferevent_socket_connect(struct bufferevent *bev, struct sockaddr *address, int addrlen); 
参数:- bev: 带缓冲区的事件, 里边封装 fd- address: 要连接的服务器的IP和端口- addrlen: address结构体的内存大小

bufferevent 读写缓冲区回调操作 bufferevent_setcb

//读、写事件触发之后的回调函数格式
typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);
参数:- bev: 从bufferevent_setcb函数中的第一个参数传入的- ctx: 从bufferevent_setcb函数中的最后第一个参数传入的//特殊事件的回调函数格式 		
typedef void (*bufferevent_event_cb)(struct bufferevent *bev, short events, void *ctx);
参数:- bev: 从bufferevent_setcb函数中的第一个参数传入的- events: 可以检测到的事件EV_EVENT_READING:读取操作时发生某事件,具体是哪种事件请看其他标志。BEV_EVENT_WRITING:写入操作时发生某事件,具体是哪种事件请看其他标志。BEV_EVENT_ERROR:操作时发生错误。关于错误的更多信息,请调用 EVUTIL_SOCKET_ERROR()。BEV_EVENT_TIMEOUT:发生超时。BEV_EVENT_EOF:遇到文件结束指示。BEV_EVENT_CONNECTED:请求的连接过程已经完成 void bufferevent_setcb(struct bufferevent *bufev, bufferevent_data_cb readcb, 		bufferevent_data_cb writecb, bufferevent_event_cb eventcb, void *cbarg
);
参数:- bufev: 带缓冲区的事件- readcb: 读事件触发之后的回调函数- writecb: 写事件触发之后的回调函数- eventcb: 特殊事件的回调函数- cbarg: 给回调函数传参
  • 禁用、启用缓冲区

可以启用或者禁用 bufferevent 上的 EV_READ、EV_WRITE 或者 EV_READ | EV_WRITE 事件。 没有启用读取或者写入事件时,bufferevent 将不会试图进行数据读取或者写入。

  • 写缓冲区默认是有效的,读缓冲区默认无效
// 设置某个事件有效
void bufferevent_enable(struct bufferevent *bufev, short events); // 设置某个事件无效
void bufferevent_disable(struct bufferevent *bufev, short events);// 获取缓冲区对应的有效事件
short bufferevent_get_enabled(struct bufferevent *bufev);
  • 操作bufferevent中的数据 bufferevent_write bufferevent_read
// 向bufferevent的输出缓冲区添加数据int bufferevent_write(struct bufferevent *bufev, const void *data, size_t size);// 从bufferevent的输入缓冲区移除数据size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);

链接监听器

  • 创建和释放 evconnlistener
#include <event2/listener.h> //回调函数格式typedef void (*evconnlistener_cb)(struct evconnlistener *listener,   evutil_socket_t sock,   struct sockaddr *addr, int len, void *ptr); 
参数:- listener: evconnlistener_new_bind 返回的地址- sock: 用于通信的fd- addr: 客户端的地址信息- ptr: 外部传进来的参数, evconnlistener_new_bind的第三个参数// 创建监听的套接字, 绑定, 设置监听, 等待并接受连接请求
struct evconnlistener *evconnlistener_new_bind(struct event_base *base,    evconnlistener_cb cb,	        // 接受新连接之后的回调函数void *ptr,                      // 回调函数参数unsigned flags, int backlog,                   // listen()中的第二参数,最多的监听数量,小于128的整数const struct sockaddr *sa,     // 本地的IP和端口int socklen				   // struct sockaddr结构体大小
);
参数:- flags:LEV_OPT_CLOSE_ON_FREE: 自动关闭底层套接字LEV_OPT_REUSEABLE: 设置端口复用
// 释放
void evconnlistener_free(struct evconnlistener *lev); 
  • 启用和禁用 evconnlistener

设置无效之后, 就不监听连接请求了

  #include <event2/listener.h> int evconnlistener_disable(struct evconnlistener *lev);int evconnlistener_enable(struct evconnlistener *lev);
  • 调整 evconnlistener 的回调函数
#include <event2/listener.h>
void evconnlistener_set_cb(struct evconnlistener *lev, evconnlistener_cb cb, void *arg);

总结

处理不带缓冲区的事件:

  • 创建事件处理框架event_base event_base_new()
  • 创建新事件event event_new()
  • 将事件添加到事件处理框架event_baseevent_add()
  • 启动事件循环检测 event_base_dispatch()
  • 循环结束之后释放资源 event_base_free()event_free()

处理带缓冲区的事件:
1、创建事件处理框架event_base event_base_new()
2、服务器端:

  • 创建连接监听器(在回调函数得到fdevconnlistener_new_bind()
  • 将通信fd包装 bufferevent_socket_new()
  • 使用bufferevent通信:给bufferevent读写缓冲区设置回调函数 bufferevent_setcb()
  • 设置读缓冲区可用 bufferevent_enable()
  • 对缓冲区数据操作 bufferevent_write()bufferevent_read()

3、客户端:

  • 创建通信用的fd并且使用 bufferevent 包装 bufferevent_socket_new()
  • 连接服务器 bufferevent_socket_connect()
  • 使用bufferevent通信:给 bufferevent 读写缓冲区设置回调函数 bufferevent_setcb()
  • 设置读缓冲区可用 bufferevent_enable()
  • 对缓冲区数据操作 bufferevent_write()bufferevent_read()

一般流程

创建event
注册到 event base 中
监听事件的发生
将event添加到激活队列中
遍历激活队列,调用event的回调函数

libevent 使用步骤

  1. 创建socket
  2. 创建事件集 event_base
  3. 创建event(socket, EV_READ, callback1) / event(socket, EV_WRITE, callback2)
  4. event添加到事件集event_base
  5. event_base_dispatch(evnet_base); event_base_loop();

注 意:
程序的最后调用event_base_dispatch(base);实现事件的循环处理

while()
{//调用多路复用event_base_dispatch(base);...
}

一篇文章搞懂Libevent网络库的原理与应用l
Linux c 开发 - libevent
libevent源码解读——简单工作流程

libevent 解决了网络编程哪些痛点?

1.高效的网络缓冲区
在内核中有读缓冲区和写缓冲区,减少用户态和内核态的切换。
用户态读缓冲区的存在是为了处理粘包的问题,因为网络协议栈是不知道用户界定数据包的格式,没法确定一个完整的数据包。
用户态写缓冲区的存在是因为用户根本不清楚内核写缓存区的状态,需要把没有写出去的数据缓存起来等待下次写事件时把数据写出去。

buffer 的设计有三种类型:
(1)固定数组,固定长度。限定了处理数据包的能力,没有动态伸缩的能力;需要频繁挪动数据。
(2)ring buffer。可伸缩性差。
(3)chain buffer。解决可伸缩性差的问题,避免频繁挪动数据;同时也引进了新的问题,一个数据可能在多个buffer 中都有,即数据分割,这会导致多次系统调用,从而引起中断上下文的切换。解决办法是使用 readv() 将内核中连续的 buffer 读到用户态不连续的 buffer 中,writev() 把用户态不连续的 buffer 写到内核连续的 buffer 中;从而减少系统调用。

2.IO函数使用与网络原理
(1)有了 libevent 可以不使用IO函数。因为如果使用IO函数,既需要知道这些IO函数里面的系统调用返回值的含义。
(2)有了 libevent 就可以不清楚数据拷贝原理。
(3)有了 libeven t就可以不清楚网络原理以及网络编程流程。
(4)有了 libevent 只需要知道事件处理,IO操作完全交由 libevent 处理。

3.多线程
加锁的效果比较好。
一个线程尽量只处理一个 reactor 的事件。
(1)buffer 加锁时,读要读出一个完整的数据包。
(2)buffer 加锁时,写要写一个完整的数据包。

深入理解libevent事件库的原理与实践技巧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/7690.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI去衣技术在动画制作中的应用

随着科技的发展&#xff0c;人工智能&#xff08;AI&#xff09;已经在各个领域中发挥了重要作用&#xff0c;其中包括动画制作。在动画制作中&#xff0c;AI去衣技术是一个重要的工具&#xff0c;它可以帮助动画师们更加高效地完成工作。 AI去衣技术是一种基于人工智能的图像…

人际关系之【镜子、点到为止、脸色和蔼、懂自爱、弹性、试探】

人跟人是镜子 别人看到你的表情&#xff0c;当作一面镜子 儒家&#xff1a;先检查自己&#xff0c;容易进步 礼尚往来&#xff1a;一切往好处想&#xff0c;就会有好的结果 关于借钱&#xff1a; 没问题&#xff0c;我随时&#xff08;合适&#xff09;要用 个人和团体合在…

神经网络怎么把隐含层变量融合到损失函数中?

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

【工具分享】Amnesia2勒索病毒解密工具

前言 Amnesia 勒索软件于 2017 年 4 月 26 日开始出现。Amnesia 主要通过 RDP&#xff08;远程桌面服务&#xff09;暴力攻击进行传播&#xff0c;允许恶意软件作者登录受害者的服务器并执行勒索行为。 特征 Amnesia 是一种用 Delphi 编程语言编写的勒索软件&#xff0c;它使…

Git撤回指定commit不保留更改

要撤销指定的commit但不保留这个commit中的更改&#xff0c;可以使用以下命令&#xff1a; git revert <commit_hash> --no-commit这里的<commit_hash>是你想要撤销的commit的哈希值。如果你想要在一个commit上使用这个命令&#xff0c;你可以用它的哈希值或者用H…

程序员的实用神器:助力软件开发的利器 ️

程序员的实用神器&#xff1a;助力软件开发的利器 &#x1f6e0;️ 程序员的实用神器&#xff1a;助力软件开发的利器 &#x1f6e0;️引言摘要自动化测试工具&#xff1a;保障代码质量的利剑 &#x1f5e1;️编写高效测试用例 持续集成/持续部署工具&#xff1a;加速交付的利器…

ASP.NET通用作业批改系统设计

摘  要 该系统采用B/S结构&#xff0c;以浏览器方式登陆系统&#xff0c;用ASP.NET作为开发语言&#xff0c;数据库则使用Microsoft SQL Server 2000实现。《通用作业批改系统》包括了学生子系统、教师子系统、管理员子系统三大模块&#xff0c;该系统主要完成学生&#xff…

基于C语言的贪吃蛇小游戏(简易版)

这篇博客会是对学习C语言成果的检测&#xff0c;为了实现贪吃蛇小游戏&#xff0c;我们用到的“工具”有&#xff1a;C语言函数、枚举、结构体、动态内存管理、预处理指令、链表、Win32 API等。 目录 1.简易版游戏效果 1.1欢迎界面 1.2游戏规则提示页面 1.3游戏进行页面 …

纯净水20、脉动30被指宰客!疯狂开始反噬小杨哥?

作为疯狂小杨哥早期粉&#xff0c;小柴好像很久没看到小杨哥的搞笑视频了。 自然&#xff0c;再在社交媒体上看到&#xff0c;小杨哥兄弟已经不再是那个青涩的少年了。 而是摇身一变不仅成为一个非常成功带货主播&#xff0c;且成为一个资本版图越来越多&#xff0c;玩的越来越…

现场面试题

这里写目录标题 1.sql1.1 只保留学生的最新成绩1.2 统计通话号码数1.3 更新地址 2.基础题2.1 请求序列第N位的值: 0, 1, 1, 2, ,3, 5, 8, 13, 21, 34.....第N位的值2.2 请写一段java代码&#xff0c;输出存在重复字母的单词 1.sql 1.1 只保留学生的最新成绩 表student中记录学…

CF988D题解

题目大意 题目传送门 题意&#xff1a;给你有 n n n 个数字的一个数列&#xff0c;问最多有多少个数字他们 两两的差是 2 的幂次方数。 思路 首先&#xff0c;我们想一个数能不能组成一个满足题目要求的序列&#xff0c;答案是肯定的。&#xff08;直接输出 a 1 a_1 a1​…

Android Studio之ImageView

ImageView是图像显示控件&#xff0c;与图形显示有关的属性说明如下: scaleType&#xff1a;指定图形的拉伸类型&#xff0c;默认是fitCenter。src&#xff1a;指定图形来源&#xff0c;src图形按照scaleType拉伸。 注意背景图不按scaleType指定的方式拉伸&#xff0c;背景默…

网络安全之交换基础

交换属于二层技术。路由器&#xff08;router&#xff09;是三层设备&#xff0c;可以基于IP地址转发&#xff0c;但需要路由表来记录。 交换机&#xff08;switch&#xff09;是二层设备&#xff0c;网桥&#xff08;switch&#xff09;也是二层设备&#xff0c;这两个都是基…

SegFix:预测边界和预测方向来修正边界

论文标题&#xff1a;SegFix: Model-Agnostic Boundary Refinement for Segmentation 论文地址&#xff1a;https://arxiv.org/pdf/2007.04269.pdf 代码地址&#xff1a;https://github.com/openseg-group/openseg.pytorch 两种loss监督 八种方向变回归问题为分类问题 代码地…

洛谷 P6136:【模板】普通平衡树(数据加强版) ← Splay树模板题

【题目来源】https://www.luogu.com.cn/problem/P6136【算法分析】 Splay 树简介及代码模板&#xff1a;https://blog.csdn.net/hnjzsyjyj/article/details/138504578【代码一&#xff1a;含 pushdown() 函数版本】 ● 本代码为洛谷 P6136 代码。题目来源为&#xff1a;https:…

PyQt6--Python桌面开发(1.安装配置环境)

一.PyQt6简介 PyQt&#xff1a;PyQt是一个功能强大且成熟的GUI框架&#xff0c;基于Qt库。它提供了丰富的组件、布局和主题选项&#xff0c;以及强大的功能和灵活性。PyQt的优点是它具有现代化的外观和丰富的功能&#xff0c;适用于复杂的GUI应用程序。然而&#xff0c;由于Py…

openEuler 22.03 GPT分区表模式下磁盘分区管理

目录 GPT分区表模式下磁盘分区管理parted交互式创建分区步骤 1 执行如下步骤对/dev/sdc磁盘分区 非交互式创建分区步骤 1 输入如下命令直接创建分区。 删除分区步骤 1 执行如下命令删除/dev/sdc1分区。 GPT分区表模式下磁盘分区管理 parted交互式创建分区 步骤 1 执行如下步骤…

明火检测实时识别报警:视觉算法助力安全生产管理

背景与现状 在各种工作、生产环境下&#xff0c;明火的存在往往是潜在的安全隐患。无论是加油站、化工园区、仓储场所还是校园&#xff0c;明火一旦失控就会引发火灾&#xff0c;造成严重的人员伤亡和财产损失。传统的明火检查手段主要依赖于人工巡查和定期的消防检查&#xf…

什么是高级持续威胁(APT)

高级持续性威胁&#xff08;Advanced Persistent Threat&#xff0c;APT&#xff09;&#xff0c;又叫高级长期威胁&#xff0c;是一种复杂的、持续的网络攻击&#xff0c;包含三个要素&#xff1a;高级、长期、威胁。 【高级】是指执行APT攻击需要比传统攻击更高的定制程度和…