基于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显示屏,设计并实现一个简易…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...
给网站添加live2d看板娘
给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...
