基于Linux的云端垃圾分类助手
项目简介
本项目旨在开发一个基于嵌入式系统的智能垃圾分类装置。该装置能够通过串口通信、语音播报、网络通信等多种方式,实现垃圾的自动识别和分类投放。系统采用多线程设计,确保各功能模块高效并行工作。
项目功能
- 垃圾分类识别
系统使用摄像头拍摄垃圾图片,并将其上传到阿里云进行分类识别。
识别结果包括干垃圾、湿垃圾、可回收垃圾、有害垃圾等类别。
- 语言播报
系统通过串口与语言模块通信,根据垃圾分类结果进行语音播报。
语音模块接收指令并播放相应的提示音。
- OLED显示
系统通过OLED屏幕显示当前垃圾分类结果。
4.垃圾桶盖控制
系统根据识别结果控制相应垃圾桶的开关。
使用PWM信号控制舵机开关垃圾桶盖。
5.网络通信
系统支持通过网络接收客户端指令,实现远程控制。
通过TCP/IP协议接收来自客户端的“open”指令,触发垃圾分类操作。
硬件需求
Orange Pi Zero2
摄像头模块
语音播报模块SU-03T
128*64 OLED显示屏
SG90舵机
串口通信模块
运行环境
操作系统:Linux
编程语言:C语言、Python
功能实现
garbage.py
调用阿里云SDK API
# -*- coding: utf-8 -*-
# 引入依赖包
# pip install alibabacloud_imagerecog20190930
//引入必要的Python包,包括阿里云图像识别服务的SDK包。
import os
import io
from urllib.request import urlopen
from alibabacloud_imagerecog20190930.client import Client
from alibabacloud_imagerecog20190930.models import ClassifyingRubbishAdvanceRequest
from alibabacloud_tea_openapi.models import Config
from alibabacloud_tea_util.models import RuntimeOptions//通过读取环境变量中的AccessKey ID和AccessKey Secret,配置阿里云客户端的认证信息和访问域名。
config = Config(# 创建AccessKey ID和AccessKey Secret,请参考https://help.aliyun.com/document_detail/175144.html。# 如果您用的是RAM用户的AccessKey,还需要为RAM用户授予权限AliyunVIAPIFullAccess,请参考https://help.aliyun.com/document_detail/145025.html# 从环境变量读取配置的AccessKey ID和AccessKey Secret。运行代码示例前必须先配置环境变量。access_key_id=os.environ.get('ALIBABA_CLOUD_ACCESS_KEY_ID'),access_key_secret=os.environ.get('ALIBABA_CLOUD_ACCESS_KEY_SECRET'),# 访问的域名endpoint='imagerecog.cn-shanghai.aliyuncs.com',# 访问的域名对应的regionregion_id='cn-shanghai'
)//垃圾分类函数,提供了从本地文件读取和从URL读取,两种方式
def alibaba_garbage():#场景一:文件在本地img = open(r'/tmp/garbage.jpg', 'rb') //打开文件所在路径#场景二:使用任意可访问的url#url = 'https://viapi-test-bj.oss-cn-beijing.aliyuncs.com/viapi-3.0domepic/imagerecog/ClassifyingRubbish/ClassifyingRubbish1.jpg'#img = io.BytesIO(urlopen(url).read())classifying_rubbish_request = ClassifyingRubbishAdvanceRequest()classifying_rubbish_request.image_urlobject = imgruntime = RuntimeOptions()try:# 初始化Clientclient = Client(config)//调用阿里云图像识别服务,将上传的垃圾图片进行分类,并返回分类结果。response = client.classifying_rubbish_advance(classifying_rubbish_request, runtime)# 获取整体结果print(response.body.to_map()['Data']['Elements'][0]['Category'])return response.body.to_map()['Data']['Elements'][0]['Category']except Exception as error:return 'gat failed'在脚本被直接执行时,调用‘alibaba_garbage’函数。
if __name__ == "__main__":alibaba_garbage()
garbage.c
在C语言中嵌入Python解释器以调用Python函数。
#include <Python.h>
#include "garbage.h"void garbage_init(void)
{ //初始化Python解释器Py_Initialize();//导入‘sys’模块PyObject *sys = PyImport_ImportModule("sys");//获取‘sys.path’模块PyObject *path = PyObject_GetAttrString(sys, "path");//将当前目录‘.’添加到'sys.path'中,以便导入当前目录下的Python脚本。PyList_Append(path, PyUnicode_FromString("."));
}void garbage_final(void)
{//终止Python解释器。 Py_Finalize();
}char *garbage_category(char *category)
{//导入名为‘garbage.py’的python模块。//如果导入失败,打印错误信息并跳转到'FAILED_MODULE'表签进行清理。PyObject *pModule = PyImport_ImportModule("garbage");if(!pModule){PyErr_Print();printf("ERROR: faild to load garbage.py\n");goto FAILED_MODULE;}//获取'garbage'模块中的'alibaba_garbage'函数。//如果获取失败或函数不可调用,打印错误信息并跳转到 FAILED_FUNC 标签进行清理。PyObject *pFunc = PyObject_GetAttrString(pModule, "alibaba_garbage");if(!pFunc || !PyCallable_Check(pFunc)){PyErr_Print();printf("ERROR: function alibaba_garbage not found or not callable\n");goto FAILED_FUNC;}//调用 alibaba_garbage 函数,不传递参数。//如果调用失败,打印错误信息并跳转到 FAILED_VALUE 标签进行清理。PyObject *pValue = PyObject_CallObject(pFunc, NULL);if(!pValue){PyErr_Print();printf("ERROR: function call failed\n");goto FAILED_VALUE;}char *result = NULL;if(!PyArg_Parse(pValue, "s", &result)){PyErr_Print();printf("ERROR: parse failed\n");goto FAILED_RESULT;}category = (char *)malloc(sizeof(char *)*(strlen(result)+1));memset(category, 0 , (strlen(result)+1));strncpy(category, result, (strlen(result)+1));// 释放发生错误之前分配的内存空间
FAILED_RESULT:Py_DECREF(pValue);
FAILED_VALUE:Py_DECREF(pFunc);
FAILED_FUNC:Py_DECREF(pModule);
FAILED_MODULE:return category;
}
内存泄漏
内存泄漏是指在计算机程序中,动态分配的内存未被正确释放,导致这些内存块不能被重新分配和使用。随着程序的运行,未释放的内存不断累积,最终可能耗尽可用内存资源,导致系统性能下降,甚至使程序或系统崩溃。
内存泄漏的成因
- 未释放动态分配的内存:
程序在使用 malloc、calloc 或 realloc 分配内存后,没有使用 free 函数释放内存。
- 循环或递归调用中未释放内存:
在循环或递归调用中,动态分配的内存未被释放。
- 异常退出或提前返回:
程序在处理错误或异常时,没有正确释放已经分配的内存。
- 丢失指针引用:
动态分配的内存地址被覆盖或丢失,没有其他指针指向该内存块。
栈上分配和堆上分配
栈上分配
栈上分配的内存(例如局部变量)在函数调用结束后会自动释放。
void function() {int local_variable = 10; // 栈上分配// local_variable 在函数结束时自动释放
}
堆上分配
堆上分配的内存需要程序员手动释放,否则会导致内存泄漏。
void function() {int *heap_variable = (int *)malloc(sizeof(int) * 10); // 堆上分配// 使用完 heap_variable 后需要手动释放内存free(heap_variable);
}
garbage.h
#ifndef __GARBAGE__H
#define __GARBAGE__Hvoid garbage_init(void);
void garbage_final(void);
char *garbage_category(char *category);//宏定义拍照指令和图片地址
#define WGET_CMD "wget http://127.0.0.1:8080/?action=snapshot -O /tmp/garbage.jpg"
#define GARBAGE_FILE "/tmp/garbage.jpg"#endif
main.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <wiringPi.h>
#include <pthread.h>#include "uartTool.h"
#include "garbage.h"
#include "pwm.h"
#include "myoled.h"
#include "socket.h"int serial_fd = -1;
pthread_cond_t cond;
pthread_mutex_t mutex;//该函数通过执行 shell 命令 ps 检测特定进程是否正在运行。
static int detect_process(const char *process_name)
{int n = -1;FILE *strm;char buf[128] = {0};sprintf(buf, "ps -ax | grep %s | grep -v grep", process_name);if ((strm = popen(buf, "r")) != NULL) {if (fgets(buf, sizeof(buf), strm) != NULL) {n = atoi(buf);}}else{return -1;}pclose(strm);return n;
}//从串口读取语音命令,并根据特定条件触发条件变量信号。
void *pget_voice(void *arg)
{unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0x55, 0xAA};int len = 0;if (-1 == serial_fd) {printf("%s|%s|%d: open serial failed\n", __FILE__, __func__, __LINE__);pthread_exit(0);}printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);while(1){len = serialGetstring(serial_fd, buffer);if (len > 0 && buffer[2] == 0x46) {pthread_mutex_lock(&mutex);buffer[2] = 0x00;pthread_cond_signal(&cond);pthread_mutex_unlock(&mutex);}}pthread_exit(0);
}//发送语音命令到串口。
void *psend_voice(void *arg)
{pthread_detach(pthread_self());unsigned char *buffer = (unsigned char *)arg;if (-1 == serial_fd){printf("%s|%s|%d: open serial failed\n", __FILE__, __func__, __LINE__);pthread_exit(0);}if (NULL != buffer){serialSendstring(serial_fd, buffer, 6);}pthread_exit(0);
}//控制垃圾桶打开和关闭。
void *popen_trash_can(void *arg)
{pthread_detach(pthread_self());unsigned char *buffer = (unsigned char *)arg;if (buffer[2] == 0x43) {printf("%s|%s|%d: buffer[2]=0x%x\n", __FILE__, __func__, __LINE__, buffer[2]);pwm_write(PWM_RECOVERABLE_GARBAGE);delay(2000);pwm_stop(PWM_RECOVERABLE_GARBAGE);}else if (buffer[2] != 0x45){printf("%s|%s|%d: buffer[2]=0x%x\n", __FILE__, __func__, __LINE__, buffer[2]);pwm_write(PWM_GARBAGE);delay(2000);pwm_stop(PWM_GARBAGE);}pthread_exit(0);
}//初始化 OLED 显示屏并显示垃圾分类结果。
void*poled_show(void *arg)
{pthread_detach(pthread_self());myoled_init();oled_show(arg);pthread_exit(0);
}//等待条件变量信号,执行垃圾分类逻辑,并触发语音、垃圾桶和 OLED 显示。
void *pcategory(void *arg)
{unsigned char buffer[6] = {0xAA, 0x55, 0x00, 0x00, 0x55, 0xAA};char *category = NULL;pthread_t send_voice_tid, trash_tid, oled_tid;while(1){pthread_mutex_lock(&mutex);pthread_cond_wait(&cond, &mutex);pthread_mutex_unlock(&mutex);buffer[2] = 0x00;system(WGET_CMD);if (0 == access(GARBAGE_FILE, F_OK)){category = garbage_category(category);if (strstr(category, "干垃圾")){buffer[2] = 0x41;}else if (strstr(category, "湿垃圾")){buffer[2] = 0x42;}else if (strstr(category, "可回收垃圾")){buffer[2] = 0x43;}else if (strstr(category, "有害垃圾")){buffer[2] = 0x44;}else {buffer[2] = 0x45;}}else{buffer[2] = 0x45;}//开语音播报线程pthread_create(&trash_tid, NULL, psend_voice, (void *)buffer);//开垃圾桶开关pthread_create(&send_voice_tid, NULL, popen_trash_can, (void *)buffer);//oled显示线程pthread_create(&oled_tid, NULL, poled_show, (void *)buffer);remove(GARBAGE_FILE);}}void *pget_socket(void *arg)
{int s_fd = -1;// 服务器套接字文件描述符int c_fd = -1;// 客户端套接字文件描述符char buffer[6];// 接收数据缓冲区int nread = -1;// 接收到的数据长度struct sockaddr_in c_addr;// 客户端地址结构memset(&c_addr,0,sizeof(struct sockaddr_in));// 初始化客户端地址结构s_fd = socket_init(IPADDR, IPPORT);// 初始化服务器套接字printf("%s|%s|%d:s_fd=%d\n", __FILE__, __func__, __LINE__, s_fd);if (-1 == s_fd){pthread_exit(0);}sleep(3);int clen = sizeof(struct sockaddr_in);// 客户端地址结构的长度while(1){c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);// 接受客户端连接int keepalive = 1; // 开启TCP KeepAlive功能int keepidle = 5; // 5s内没收到数据开始发送心跳包int keepcnt = 3; // 每次发送心跳包的次数int keepintvl = 3; // 每3s发送一次心跳包setsockopt(c_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive, sizeof(keepalive));setsockopt(c_fd, SOL_TCP, TCP_KEEPIDLE, (void *) &keepidle, sizeof(keepidle));setsockopt(c_fd, SOL_TCP, TCP_KEEPCNT, (void *)&keepcnt, sizeof(keepcnt));setsockopt(c_fd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepintvl, sizeof(keepintvl)); printf("%s|%s|%d: Accept a connection from %s:%d\n", __FILE__, __func__, __LINE__, inet_ntoa(c_addr.sin_addr), ntohs(c_addr.sin_port));if(c_fd == -1){perror("accept");continue;}while(1){memset(buffer, 0, sizeof(buffer));nread = recv(c_fd, buffer, sizeof(buffer), 0); //n_read = read(c_fd,buffer, sizeof(buffer));printf("%s|%s|%d:nread=%d, buffer=%s\n", __FILE__, __func__,__LINE__, nread, buffer);if (nread > 0){if (strstr(buffer, "open")){pthread_mutex_lock(&mutex);pthread_cond_signal(&cond);pthread_mutex_unlock(&mutex);}}else if(0 == nread || -1 == nread){break;}}close(c_fd);}pthread_exit(0);
}int main(int argc, char *argv[])
{ int len = 0;int ret = -1;char *category = NULL;pthread_t get_voice_tid, category_tid, get_socket_tid;wiringPiSetup();garbage_init();ret = detect_process("mjpg_streamer"); //判断mjpg_streamer是否已经在运行if (-1 == ret){goto END;}else{printf("已运行mjpg_streamer,可以开始垃圾分类识别\n");}serial_fd = myserialOpen(SERIAL_DEV, BAUD);if (-1 == serial_fd) {goto END;}//开语音线程printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);pthread_create(&get_voice_tid, NULL, pget_voice, NULL);//开网络线程pthread_create(&get_socket_tid, NULL, pget_socket, NULL);//开阿里云交互线程printf("%s|%s|%d\n", __FILE__, __func__, __LINE__);pthread_create(&category_tid, NULL, pcategory, NULL);pthread_join(get_voice_tid, NULL);pthread_join(category_tid, NULL);pthread_join(get_socket_tid, NULL);pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);close(serial_fd);
END:garbage_final;return 0;
}
关于TCP KeepAlive
通过设置 TCP KeepAlive 选项,可以在客户端异常断开连接时检测到失效连接,并在必要时关闭它。它会自动发生在操作系统内核层面。
- KeepAlive 探测: 当启用了 TCP KeepAlive 并设置了相关参数后,操作系统内核会在连接空闲指定时间(TCP_KEEPIDLE)后开始发送 KeepAlive 探测包。
- 检测响应: 内核会等待客户端对探测包的响应。如果在指定的次数(TCP_KEEPCNT)内没有收到客户端的响应,内核会认为该连接已经失效。
- 关闭连接: 当探测包没有得到响应时,内核会自动关闭该连接,并通知应用程序。此时,你在应用程序中的 recv 调用会返回 -1,表示连接已经断开。
oled.c
这段代码实现了一个 OLED 显示功能,用于在一个指定位置上显示垃圾分类的结果。具体来说,代码分为两个主要部分:oled_show 函数和 myoled_init 函数。
#include <error.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>#include "oled.h"
#include "font.h"
#include "myoled.h"#define FILENAME "/dev/i2c-3"static struct display_info disp;int oled_show(void *arg)
{unsigned char *buffer = (unsigned char *)arg;//在屏幕上的指定位置显示指定内容oled_putstrto(&disp, 0, 9+1, "This garbage is:");// 设置字体disp.font = font2;//根据 buffer[2] 的值显示相应的垃圾分类结果switch(buffer[2]){case 0x41:oled_putstrto(&disp, 0, 20, "dry waste");break;case 0x42:oled_putstrto(&disp, 0, 20, "wet waste");break;case 0x43:oled_putstrto(&disp, 0, 20, "recyclable waste");break;case 0x44:oled_putstrto(&disp, 0, 20, "hazardous waste");break;case 0x45:oled_putstrto(&disp, 0, 20, "recognition failed");break;}// 再次设置字体disp.font = font2;//把需要显示的内容刷新到屏幕上oled_send_buffer(&disp); return 0;
}int myoled_init(void)
{int e;// 设置显示屏地址和字体disp.address = OLED_I2C_ADDR;disp.font = font2;// 打开和初始化 OLED 显示屏e = oled_open(&disp, FILENAME);e = oled_init(&disp);return e;
}
相关文章:
基于Linux的云端垃圾分类助手
项目简介 本项目旨在开发一个基于嵌入式系统的智能垃圾分类装置。该装置能够通过串口通信、语音播报、网络通信等多种方式,实现垃圾的自动识别和分类投放。系统采用多线程设计,确保各功能模块高效并行工作。 项目功能 垃圾分类识别 系统使用摄像头拍摄…...

【PYG】Planetoid中边存储的格式,为什么打印前十条边用edge_index[:, :10]
edge_index 是 PyTorch Geometric 中常用的表示图边的张量。它通常是一个形状为 [2, num_edges] 的二维张量,其中 num_edges 表示图中边的数量。每一列表示一条边,包含两个节点的索引。 实际上这是COO存储格式,官方文档里也有写,…...

【知识图谱系列】(实例)python操作neo4j构建企业间的业务往来的知识图谱
本章节通过聚焦于"金额"这一核心属性,构建了一幅知识图谱,旨在揭示"销售方"与"购买方"间的商业互动网。在这张图谱中,绿色节点象征着购买方,而红色节点则代表了销售方。这两类节点间的紧密连线&…...
解决MySQL删除/var/lib/mysql下的所有文件后无法启动的问题
解决MySQL删除/var/lib/mysql下的所有文件后无法启动的问题 确保清空/var/lib/mysql初始化启动mysql参考 确保清空/var/lib/mysql rm-rf /var/lib/mysql/* 初始化 mysql_install_db --usermysql --basedir/usr --datadir/var/lib/mysql 其中的mysql用户不要改成root。否则会…...
探索WebKit的Flexbox奇境:CSS Flexbox支持全解析
探索WebKit的Flexbox奇境:CSS Flexbox支持全解析 在现代网页设计中,响应式布局的需求日益增长,CSS Flexbox作为布局模式的一个突破性进展,提供了一种更加高效和灵活的方式来设计复杂的用户界面。WebKit,作为众多流行浏…...
Unity--协程--Coroutine
Unity–协程–Coroutine 1. 协程的基本概念 基本概念:不是线程,将代码按照划分的时间来执行,这个时间可以是具体的多少秒,也可以是物理帧的时间,也可以是一帧的绘制结束的时间。 协程的写法:通过返回IEnumerator的函数实现,使用yield return语句暂停执…...

详解COB显示屏的技术特点
COB(Chip on Board)显示屏作为一种采用倒装COB封装技术的LED显示屏,在显示效果以及使用稳定性跟防护性方面,拥有更大优势,今天跟随COB显示屏厂家中品瑞科技一起来看看,COB显示屏的技术特点: 1、…...

富唯智能推出的AMR复合机器人铝板CNC上下料方案
随着科技的不断进步,CNC加工行业正面临着前所未有的变革。传统的CNC上下料方式已无法满足现代生产对效率、精度和安全性的高要求。在这样的背景下,富唯智能推出的AMR复合机器人铝板CNC上下料方案,以其智能化、自动化的特点,引领了…...

springcloud-config服务器,同样的配置在linux环境下不生效
原本在windows下能争取的获取远程配置但是部署到linux上死活都没有内容,然后开始了远程调试,这里顺带讲解下获取配置文件如果使用的是Git源,config service是如何响应接口并返回配置信息的。先说问题,我的服务名原本是abc-abc-abc…...

写代码,为什么还需要作图?
引言 古人云 :一图胜千言,闲人说:无图无真相。 在日常的聊天工具当中,无论是使用微信,还是钉钉。使用图片或表情包的频次越来越高,那是为什么呢?其实在互联网没有那么发达的时候,我…...

一句话介绍什么是AI智能体?
什么是AI智能体? 一句话说就是利用各种AI的功能的api组合,完成你想要的结果。 例如你希望完成一个关于主题为啤酒主题的小红书文案图片,那么它就可以完成 前面几个步骤类似automa的组件,最后生成一个结果。...

32.哀家要长脑子了!
1.299. 猜数字游戏 - 力扣(LeetCode) 公牛还是挺好数的,奶牛。。。妈呀,一朝打回解放前 抓本质抓本质,有多少位非公牛数可以通过重新排列转换公牛数字,意思就是,当这个数不是公牛数字时&#x…...

Vue2 - 项目上线后生产环境中去除console.log的输出以及断点的解决方案
前言 当你准备将Vue.js应用程序部署到生产环境时,一个关键的优化步骤是移除代码中的所有 console.log 语句以及断点。在开发阶段,console.log 是一个非常有用的调试工具,但在生产环境中保留它们可能会影响性能和安全性。在本文中,我将向你展示如何通过使用Vue CLI 2来自动…...
phpword生成PDF
接上一篇phpword生成word文档,如有不明白的问题可以先查看上一篇文章 首先,生成PDF需要先生成word文档,而后通过word文档生成HTML文档,最后才可以通过HTML文档生成PDF文件,详细代码如下。 执行命令安装phpword&#…...

Linux进程优先级
1. 基本概念 cpu 资源分配的先后顺序,就是指进程的优先权( priority )。 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的 linux 很有用,可以改善系统性能。还可以把进程运行到指定的CPU 上,这样一来&a…...

每日一题——Python实现PAT乙级1096 大美数(举一反三+思想解读+逐步优化)3千字好文
一个认为一切根源都是“自己不够强”的INTJ 个人主页:用哲学编程-CSDN博客专栏:每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的写法 时间复杂度分析 空间复杂度分析 总结 哲学和编程思想 1. 抽象与具体化 …...

无锁编程——从CPU缓存一致性讲到内存模型(1)
一.前言 1.什么是有锁编程,什么是无锁编程? 在编程中,特别是在并发编程的上下文中,“无锁”和“有锁”是描述线程同步和资源访问控制的两种不同策略。有锁(Locked): 有锁编程是指使用锁(例如互…...

C++编程(七)继承
文章目录 一、继承(一)概念(二)语法格式(三)通过子类访问父类中的成员1. 类内2. 类外 (四)继承中的特殊成员函数1. 构造函数2. 析构函数3. 拷贝构造函数4. 拷贝赋值函数 二、多重继承…...

【ACM_2023】3D Gaussian Splatting for Real-Time Radiance Field Rendering
【ACM_2023】3D Gaussian Splatting for Real-Time Radiance Field Rendering 一、前言Abstract1 INTRODUCTION2 RELATED WORK2.1 Traditional Scene Reconstruction and Rendering2.2 Neural Rendering and Radiance Fields2.3 Point-Based Rendering and Radiance Fields 3 O…...

【TB作品】atmega16 计算器,ATMEGA16单片机,Proteus仿真
实验报告:基于ATmega16单片机的简易计算器设计 1. 实验背景 计算器是日常生活和工作中不可或缺的工具,通过按键输入即可实现基本的四则运算。通过本实验,我们将利用ATmega16单片机、矩阵键盘和LCD1602显示屏,设计并实现一个简易…...

chili3d 笔记17 c++ 编译hlr 带隐藏线工程图
这个要注册不然emscripten编译不起来 --------------- 行不通 ---------------- 结构体 using LineSegment std::pair<gp_Pnt, gp_Pnt>;using LineSegmentList std::vector<LineSegment>; EMSCRIPTEN_BINDINGS(Shape_Projection) {value_object<LineSegment&g…...

巴西医疗巨头尤迈Kafka数据泄露事件的全过程分析与AI安防策略分析
一、事件背景与主体信息 涉事主体:Unimed,全球最大医疗合作社,巴西医疗行业龙头企业,拥有约1500万客户。技术背景:泄露源于其未保护的Kafka实例(开源实时数据传输平台),用于客户与聊天机器人“Sara”及医生的实时通信。二、时间线梳理 时间节点关键事件描述2025年3月24…...

[Spring]-AOP
AOP场景 AOP: Aspect Oriented Programming (面向切面编程) OOP: Object Oriented Programming (面向对象编程) 场景设计 设计: 编写一个计算器接口和实现类,提供加减乘除四则运算 需求: 在加减乘除运算的时候需要记录操作日志(运算前参数、运算后结果)实现方案:…...

STM32标准库-TIM输出比较
文章目录 一、输出比较二、PWM2.1简介2.2输出比较通道(高级)2.3 输出比较通道(通用)2.4输出比较模式2.5 PWM基本结构1、时基单元2、输出比较单元3、输出控制(绿色右侧)4、右上波形图(以绿色脉冲…...
【前端】每日一道面试题6:解释Promise.any和Promise.allSettled的使用场景及区别。
Promise.any() 和 Promise.allSettled() 是 JavaScript 中用于处理异步操作的两种不同策略的 Promise 组合器,它们的核心区别在于逻辑目标与结果处理方式: 1. Promise.any() 使用场景: 需要获取 首个成功结果(类似竞速成功优先&…...

《PMBOK® 指南》第八版草案重大变革:6 大原则重构项目管理体系
项目管理领域的权威指南迎来关键升级!PMI 最新发布的《PMBOK 指南》第八版草案引发行业广泛关注,此次修订首次将项目管理原则浓缩为 6 大黄金法则,重构 7 大绩效域,并首度公开过程组与绩效域的映射关系。本文将全面解析新版核心变…...
Podman 和 Docker
Podman 和 Docker 都是容器化工具,用于创建、运行和管理容器。它们有很多相似之处,但也存在关键区别。下面从多个维度对比它们,并给出适用场景建议。 1. 核心区别 特性DockerPodman守护进程(Daemon)必须运行 dockerd …...

C++学习-入门到精通【14】标准库算法
C学习-入门到精通【14】标准库算法 目录 C学习-入门到精通【14】标准库算法一、对迭代器的最低要求迭代器无效 二、算法1.fill、fill_n、generate和generate_n2.equal、mismatch和lexicographical_compare3.remove、remove_if、remove_copy和remove_copy_if4.replace、replace_…...

前端实现视频/直播预览
有一个需求:后端返回视频的预览地址,不仅要支持这个视频的预览,还需要设置视频封面。 这里有两种情况: 如果是类似.mp4,.mov等格式的视频可以选用原生 video 进行视频展示,并且原生的 video 也支持全屏、…...

linux安全加固(非常详细)
安全加固方案原则 1.版本升级 对于系统和应用在使用过程中暴露的安全缺陷,系统或应用厂商会及时发布解决问题的升级补丁包。升级系统或应用版本,可有效解决旧版本存在的安全风险。2.关闭端口服务 在不影响业务系统正常运行情况下,停止或禁用承…...