安防监控项目---Cortex-A9和zigbee传感器数据上传至网页

news2024/11/25 13:37:56

文章目录

  • 前言
  • 一、A9平台数据的采集与上传
  • 二、共享内存上传数据到CGI
  • 三、设备代码
  • 总结


前言

书接上期,我们大概来梳理一下,已经完成的需求有哪些了,从html下发指令控制Cortex-A9平台硬件,其中主要实现的有控制LED,蜂鸣器,LED模拟数码管,这些是已经实现的硬件设备,实现了html和Cortex-A9平台的通信,是不是主要通过boa服务器呢,仔细想一下,是不是主要依赖于boa服务器搭载了CGI接口呢,那在CGI中我们进行了CGI编程,使用接口库函数进行网页(form表单)数据的接收,并且呢使用消息队列进行应用层的进程间通信,进而主框架进行客户端请求的处理,判断消息类型,唤醒相应等待线程!这样梳理下来思路是不是非常清晰了;那之前还完成了什么呢,是不是也完成了通过Cortex-A9平台控制zigbee硬件设备,这块需要注意的是linux下的串口编程,其实只要大家经常使用串口调试助手,那么这块的代码理解肯定不是问题,只不过这里把图形化的窗口进行了具体的软件实现,其实本质上来讲,就算是Windows下的UI界面,也是通过软件编写来实现的,所以原理都是一样的哈!
那么接下来要实现的是什么操作呢,接下来还需要将采集到的数据上传到网页对不对,所以本期我们的分享呢主要是实现安防监控项目中的环境数据的采集和上传!接下来带大家看一下吧!


一、A9平台数据的采集与上传

首先呢A9平台上需要上传的数据有两个,一个是MPU6050姿态传感器的加速度和角速度,另一个呢是板载的ADC模块,将采集到的数据转化为具体的电压值在网页端进行显示;
这一部分呢主要是应用层实现的事情,接下来先从应用层看起,先来看一下接收zigbee数据和采集A9平台传感器的数据,这个功能是通过pthread_transfer.c线程来实现的,具体来分析一下:

#include "data_global.h"
#include "common.h"
#include "mpu6050.h"
#include <strings.h>

//接收ZigBee的数据和采集的A9平台的传感器数据
int adc_fd;
int mpu_fd;

extern pthread_cond_t cond_transfer;
extern pthread_mutex_t mutex_transfer;
extern struct env_info_client_addr  sm_all_env_info;
//调试代码,可以进行随意赋值,但是网页实时数据肯定不会进行变化
int file_env_info_a9_zigbee_debug(struct env_info_client_addr *rt_status,int home_id);
//真实硬件采集代码,数据实时采集
int file_env_info_a9_zigbee_stm32(struct env_info_client_addr *rt_status,int home_id);
//打印传感器的数据,开发人员可以再终端调试使用
int printf_sensor_info_debug(struct env_info_client_addr  *sm_all_env_info,int home_id);

//数据采集线程
void *pthread_transfer(void *arg)
{
	int home_id = 1;
	adc_fd = open(ADC_DEV,O_RDWR);				//打开ADC设备节点
	mpu_fd = open(MPU6050_DEV,O_RDWR);			//打开MPU6050设备节点
	if((adc_fd == -1) || (mpu_fd == -1)){
		printf("open adc or mpu device failed.\n");
	}
	while(1){
		pthread_mutex_lock(&mutex_transfer);					//上锁
		pthread_cond_wait(&cond_transfer,&mutex_transfer);		//线程睡眠等待被唤醒
//		printf("pthread_analysis and tranfer.\n");
#if 1
		//进行真实数据上传
		file_env_info_a9_zigbee_stm32(&sm_all_env_info,home_id);
#else	
		//调试使用代码
		file_env_info_a9_zigbee_debug(&sm_all_env_info,home_id);
#endif
		发送完毕后解锁
		pthread_mutex_unlock(&mutex_transfer);
		sleep(1);
	}
	close(adc_fd);
	close(mpu_fd);
}
//测试用例,可以看出都是常量赋值
int file_env_info_a9_zigbee_debug(struct env_info_client_addr *rt_status,int home_id)
{
	static int temp = 0;
	int  env_info_size = sizeof(struct env_info_client_addr);
	//	printf("env_info_size = %d.\n",env_info_size);
	
	rt_status->monitor_no[home_id].zigbee_info.temperature = 10.0;
	rt_status->monitor_no[home_id].zigbee_info.tempMIN = 2.0;
	rt_status->monitor_no[home_id].zigbee_info.tempMAX = 20.0;
	rt_status->monitor_no[home_id].zigbee_info.humidity  = 20.0;
	rt_status->monitor_no[home_id].zigbee_info.humidityMIN  = 10.0;
	rt_status->monitor_no[home_id].zigbee_info.humidityMAX  = 30.0;
	rt_status->monitor_no[home_id].zigbee_info.reserved[0]  = 0.01;
	rt_status->monitor_no[home_id].zigbee_info.reserved[1]  = -0.01;
	
	//模拟ADC数据
	temp ++;
	rt_status->monitor_no[home_id].a9_info.adc  = temp;
	rt_status->monitor_no[home_id].a9_info.gyrox  = -14.0;
	rt_status->monitor_no[home_id].a9_info.gyroy  = 20.0;
	rt_status->monitor_no[home_id].a9_info.gyroz  = 40.0;
	rt_status->monitor_no[home_id].a9_info.aacx  = 642.0;
	rt_status->monitor_no[home_id].a9_info.aacy  = -34.0;
	rt_status->monitor_no[home_id].a9_info.aacz  = 5002.0;
	rt_status->monitor_no[home_id].a9_info.reserved[0]  = 0.01;
	rt_status->monitor_no[home_id].a9_info.reserved[1]  = -0.01;
//	printf_sensor_info_debug(rt_status,home_id);
	//添加stm32部分的数据、arduino数据,
	return 0;
}
//此函数未用到
#if 0
int	get_sensor_data_from_a9(struct makeru_a9_info* a9_sensor_data)
{
	int adc_sensor_data;
	struct mpu6050_data data;

	/*get adc sensor data*/
	read(adc_fd,&adc_sensor_data,4); 
	printf("adc value :%0.2fV.\n",(1.8*adc_sensor_data)/4096);  

	/* get mpu6050 sensor data*/
	ioctl(mpu_fd,MPU6050_GYRO,&data);
	printf("gyro data: x = %05d, y = %05d, z = %05d\n", data.gyro.x,data.gyro.y,data.gyro.z);
	ioctl(mpu_fd,MPU6050_ACCEL,&data);
	printf("accel data: x = %05d, y = %05d, z = %05d\n", data.accel.x,data.accel.y,data.accel.z);

	/*预填充,有点浪费空间,大家可以优化一下*/
	a9_sensor_data->adc = (1.8 * adc_sensor_data)/4096 * 100; //定义未int32,应该是float,放大100倍,保护小数位
	a9_sensor_data->gyrox = data.gyro.x;
	a9_sensor_data->gyroy = data.gyro.y;
	a9_sensor_data->gyroz = data.gyro.z;
	a9_sensor_data->aacx  = data.accel.x;
	a9_sensor_data->aacy  = data.accel.y;
	a9_sensor_data->aacz  = data.accel.z;

	return 0;
}
#endif 

下面这个函数至关重要,可以看到不仅有硬件的真实数据赋值,也有模拟数据的赋值,当然最后的目标还是要把所有的真实数据都赋值

int file_env_info_a9_zigbee_stm32(struct env_info_client_addr *rt_status,int home_id)
{
	int  env_info_size = sizeof(struct env_info_client_addr);
//	printf("env_info_size = %d.\n",env_info_size);

	rt_status->monitor_no[home_id].zigbee_info.head[0]  = 'm';
	rt_status->monitor_no[home_id].zigbee_info.head[1]  = 's';
	rt_status->monitor_no[home_id].zigbee_info.head[2]  = 'm';		//前三个字符是表示为表示安防监控
	rt_status->monitor_no[home_id].zigbee_info.head[3]  = 'z';		//'z'表示zigbee,'a'表示A9
	rt_status->monitor_no[home_id].zigbee_info.temperature = 10.0;
	rt_status->monitor_no[home_id].zigbee_info.tempMIN = 2.0;
	rt_status->monitor_no[home_id].zigbee_info.tempMAX = 20.0;
	rt_status->monitor_no[home_id].zigbee_info.humidity  = 20.0;
	rt_status->monitor_no[home_id].zigbee_info.humidityMIN  = 10.0;
	rt_status->monitor_no[home_id].zigbee_info.humidityMAX  = 30.0;
	rt_status->monitor_no[home_id].zigbee_info.reserved[0]  = 0.01;
	rt_status->monitor_no[home_id].zigbee_info.reserved[1]  = -0.01;

	//获取数据     
	int adc_sensor_data;
	struct mpu6050_data data;
	/*get adc sensor data*/
	read(adc_fd,&adc_sensor_data,4); 
//	printf("adc value :%0.2fV.\n",(1.8*adc_sensor_data)/4096);  
	rt_status->monitor_no[home_id].a9_info.adc    = (float)((1.8*adc_sensor_data)/4096);
	
	/* get mpu6050 sensor data*/
	ioctl(mpu_fd,MPU6050_GYRO,&data);
//	printf("gyro data: x = %d, y = %d, z = %d\n", data.gyro.x,data.gyro.y,data.gyro.z);
	ioctl(mpu_fd,MPU6050_ACCEL,&data);
//	printf("accel data: x = %d, y = %d, z = %d\n", data.accel.x,data.accel.y,data.accel.z);
	
	rt_status->monitor_no[home_id].a9_info.head[0]  = 'm';
	rt_status->monitor_no[home_id].a9_info.head[1]  = 's';
	rt_status->monitor_no[home_id].a9_info.head[2]  = 'm';
	rt_status->monitor_no[home_id].a9_info.head[3]  = 'a';

	rt_status->monitor_no[home_id].a9_info.gyrox  =  (short)data.gyro.x; //获取角速度
	rt_status->monitor_no[home_id].a9_info.gyroy  =  (short)data.gyro.y;
	rt_status->monitor_no[home_id].a9_info.gyroz  =  (short)data.gyro.z;

	rt_status->monitor_no[home_id].a9_info.aacx   =  (short)data.accel.x; //获取加速度
	rt_status->monitor_no[home_id].a9_info.aacy   =  (short)data.accel.y;
	rt_status->monitor_no[home_id].a9_info.aacz   =  (short)data.accel.z;
	rt_status->monitor_no[home_id].a9_info.reserved[0]  = 0.01;
	rt_status->monitor_no[home_id].a9_info.reserved[1]  = -0.01;
	
	//printf_sensor_info_debug(rt_status,home_id);
	//添加stm32部分的数据、arduino数据
	return 0;
}

说到这里呢,直接给大家展示一下图片,现象更加直观一点;
在这里插入图片描述
大家可以看到温度和湿度都是模拟数据,这个是我的原因哈,还没实现,但是ADC和MPU6050的数据是OK的,下面我还需要继续努力,搞好了给大家分享出来;

//打印采集的传感器数据
int printf_sensor_info_debug(struct env_info_client_addr  *sm_all_env_info,int home_id)
{
	printf("a9_info.adc  : %f.\n",sm_all_env_info->monitor_no[home_id].a9_info.adc  );
	printf("a9_info.gyrox: %d.\n",sm_all_env_info->monitor_no[home_id].a9_info.gyrox);
	printf("a9_info.gyroy: %d.\n",sm_all_env_info->monitor_no[home_id].a9_info.gyroy);
	printf("a9_info.gyroz: %d.\n",sm_all_env_info->monitor_no[home_id].a9_info.gyroz);
	printf("a9_info.aacx : %d.\n",sm_all_env_info->monitor_no[home_id].a9_info.aacx );
	printf("a9_info.aacy : %d.\n",sm_all_env_info->monitor_no[home_id].a9_info.aacy );
	printf("a9_info.aacz : %d.\n",sm_all_env_info->monitor_no[home_id].a9_info.aacz );
	printf("a9_info.reserved[0]: %d.\n",sm_all_env_info->monitor_no[home_id].a9_info.reserved[0] );
	printf("a9_info.reserved[1]: %d.\n",sm_all_env_info->monitor_no[home_id].a9_info.reserved[1] );
	return 0;
}

大家千万不要单独只看代码,一定得看我们前期的通信结构体设计的部分,才能够知道每一个结构体包括结构体成员表示的什么意义,结合注释理解,肯定是能够拿下这部分的;

二、共享内存上传数据到CGI

下面带大家来看一下这个数据刷新线程,究竟接收到的数据是如何一步步上传到网页的,数据刷新线程肯定离不开数据接收线程,所以它们之间应该存在先后逻辑顺序,各位小伙伴们能想到什么呢,是不是条件变量实现同步,哈哈哈,来看下这个数据刷新线程吧!
这里呢我先把上面数据采集线程的核心代码拿下来,大家对比着看;
在这里插入图片描述
上图线程中while循环中先上锁,睡眠等待被唤醒,接下来咱这个数据刷新线程就是把它唤醒的线程:

首先是共享内存消息队列和信号量的id号,条件变量和互斥锁数据结构体以及函数声明;

#include "data_global.h"
#include "sem.h"

#define N 1024  //for share memory

extern int shmid;
extern int msgid;
extern int semid;

extern key_t shm_key;
extern key_t sem_key;
extern key_t key; //msg_key

extern pthread_mutex_t mutex_client_request,
	   mutex_refresh,
	   mutex_sqlite,
	   mutex_transfer,
	   mutex_analysis,
	   mutex_sms,
	   mutex_buzzer,
	   mutex_led,
	   mutex_camera;

extern pthread_cond_t  cond_client_request,
	   cond_refresh,
	   cond_sqlite,
	   cond_transfer,
	   cond_analysis,
	   cond_sms,
	   cond_buzzer,
	   cond_led,
	   cond_camera;
extern struct env_info_client_addr  sm_all_env_info;

struct shm_addr
{
	char shm_status;   //shm_status可以等于home_id,用来区分共享内存数据
	struct env_info_client_addr  sm_all_env_info;
};
struct shm_addr *shm_buf;

int file_env_info_struct(struct env_info_client_addr  *rt_status,int home_id);//模拟数据刷新的函数

下面这部分就是核心代码,大家一定要结合上面的数据采集线程一起理解,加深条件变量和互斥锁的使用;

void *pthread_refresh(void *arg)
{
	//semaphore for access to resource limits 创建IPC对象
	if((sem_key = ftok("/tmp",'i')) < 0){
		perror("ftok failed .\n");
		exit(-1);
	}
	
	//创建信号量集
	semid = semget(sem_key,1,IPC_CREAT|IPC_EXCL|0666);
	if(semid == -1)	{					//创建失败
		if(errno == EEXIST){			//信号量集和已经存在
			semid = semget(sem_key,1,0777);
		}else{
			perror("fail to semget");
			exit(1);
		}
	}else{
		init_sem (semid, 0, 1);		//创建成功则初始化
	}

	//share memory for env_info refresh config
	if((shm_key = ftok("/tmp",'i')) < 0){
		perror("ftok failed .\n");
		exit(-1);
	}

	shmid = shmget(shm_key,N,IPC_CREAT|IPC_EXCL|0666);
	if(shmid == -1)	{
		if(errno == EEXIST){
			shmid = shmget(key,N,0777);
		}else{
			perror("fail to shmget");
			exit(1);
		}
	}

	//share memap
	if((shm_buf = (struct shm_addr *)shmat(shmid,NULL,0)) == (void *)-1)
	{
		perror("fail to shmat");
		exit(1);
	}
	printf("pthread_refresh ......>>>>>>>\n");
	bzero (shm_buf, sizeof (struct shm_addr));
	while(1){
		sem_p(semid,0); //P操作
		shm_buf->shm_status = 1;
		int home_id = 1;
#if 1
		shm_buf->sm_all_env_info.monitor_no[home_id] = sm_all_env_info.monitor_no[home_id];  //真实数据上传
#else
		file_env_info_struct(&shm_buf->sm_all_env_info,shm_buf->shm_status); //模拟数据上传
#endif 
		sleep(1);
		sem_v(semid,0); //v操作
		pthread_cond_signal(&cond_transfer);			//真实的数据上传完成后,释放信号量唤醒数据采集线程进行数据采集赋值,紧接着进行第二轮的数据刷新(这个操作就是实现了同步)
	}
}
//模拟数据填充
int file_env_info_struct(struct env_info_client_addr *rt_status,int home_id)
{
	int  env_info_size = sizeof(struct env_info_client_addr);
	//	printf("env_info_size = %d.\n",env_info_size);

	rt_status->monitor_no[home_id].zigbee_info.temperature = 10.0;
	rt_status->monitor_no[home_id].zigbee_info.tempMIN = 2.0;
	rt_status->monitor_no[home_id].zigbee_info.tempMAX = 20.0;
	rt_status->monitor_no[home_id].zigbee_info.humidity  = 20.0;
	rt_status->monitor_no[home_id].zigbee_info.humidityMIN  = 10.0;
	rt_status->monitor_no[home_id].zigbee_info.humidityMAX  = 30.0;
	rt_status->monitor_no[home_id].zigbee_info.reserved[0]  = 0.01;
	rt_status->monitor_no[home_id].zigbee_info.reserved[1]  = -0.01;


	rt_status->monitor_no[home_id].a9_info.adc  = 9.0;
	rt_status->monitor_no[home_id].a9_info.gyrox  = -14.0;
	rt_status->monitor_no[home_id].a9_info.gyroy  = 20.0;
	rt_status->monitor_no[home_id].a9_info.gyroz  = 40.0;
	rt_status->monitor_no[home_id].a9_info.aacx  = 642.0;
	rt_status->monitor_no[home_id].a9_info.aacy  = -34.0;
	rt_status->monitor_no[home_id].a9_info.aacz  = 5002.0;
	rt_status->monitor_no[home_id].a9_info.reserved[0]  = 0.01;
	rt_status->monitor_no[home_id].a9_info.reserved[1]  = -0.01;

	//添加stm32部分的数据、arduino数据,

	return 0;
}

三、设备代码

这里和大家也分享一下MPU6050的寄存器文件,大家可以看到对硬件的读取都是通过加载驱动进而通过ioctl实现的,这样将功能模块化,也是我们的良好习惯;

#ifndef __MPU6050_H
#define __MPU6050_H

//	 
//#define MPU_ACCEL_OFFS_REG		0X06	//accel_offs寄存器,可读取版本号,寄存器手册未提到
//#define MPU_PROD_ID_REG			0X0C	//prod id寄存器,在寄存器手册未提到
#define MPU_SELF_TESTX_REG		0X0D	//自检寄存器X
#define MPU_SELF_TESTY_REG		0X0E	//自检寄存器Y
#define MPU_SELF_TESTZ_REG		0X0F	//自检寄存器Z
#define MPU_SELF_TESTA_REG		0X10	//自检寄存器A
#define MPU_SAMPLE_RATE_REG		0X19	//采样频率分频器
#define MPU_CFG_REG				0X1A	//配置寄存器
#define MPU_GYRO_CFG_REG		0X1B	//陀螺仪配置寄存器
#define MPU_ACCEL_CFG_REG		0X1C	//加速度计配置寄存器
#define MPU_MOTION_DET_REG		0X1F	//运动检测阀值设置寄存器
#define MPU_FIFO_EN_REG			0X23	//FIFO使能寄存器
#define MPU_I2CMST_CTRL_REG		0X24	//IIC主机控制寄存器
#define MPU_I2CSLV0_ADDR_REG	0X25	//IIC从机0器件地址寄存器
#define MPU_I2CSLV0_REG			0X26	//IIC从机0数据地址寄存器
#define MPU_I2CSLV0_CTRL_REG	0X27	//IIC从机0控制寄存器
#define MPU_I2CSLV1_ADDR_REG	0X28	//IIC从机1器件地址寄存器
#define MPU_I2CSLV1_REG			0X29	//IIC从机1数据地址寄存器
#define MPU_I2CSLV1_CTRL_REG	0X2A	//IIC从机1控制寄存器
#define MPU_I2CSLV2_ADDR_REG	0X2B	//IIC从机2器件地址寄存器
#define MPU_I2CSLV2_REG			0X2C	//IIC从机2数据地址寄存器
#define MPU_I2CSLV2_CTRL_REG	0X2D	//IIC从机2控制寄存器
#define MPU_I2CSLV3_ADDR_REG	0X2E	//IIC从机3器件地址寄存器
#define MPU_I2CSLV3_REG			0X2F	//IIC从机3数据地址寄存器
#define MPU_I2CSLV3_CTRL_REG	0X30	//IIC从机3控制寄存器
#define MPU_I2CSLV4_ADDR_REG	0X31	//IIC从机4器件地址寄存器
#define MPU_I2CSLV4_REG			0X32	//IIC从机4数据地址寄存器
#define MPU_I2CSLV4_DO_REG		0X33	//IIC从机4写数据寄存器
#define MPU_I2CSLV4_CTRL_REG	0X34	//IIC从机4控制寄存器
#define MPU_I2CSLV4_DI_REG		0X35	//IIC从机4读数据寄存器

#define MPU_I2CMST_STA_REG		0X36	//IIC主机状态寄存器
#define MPU_INTBP_CFG_REG		0X37	//中断/旁路设置寄存器
#define MPU_INT_EN_REG			0X38	//中断使能寄存器
#define MPU_INT_STA_REG			0X3A	//中断状态寄存器

#define MPU_ACCEL_XOUTH_REG		0X3B	//加速度值,X轴高8位寄存器
#define MPU_ACCEL_XOUTL_REG		0X3C	//加速度值,X轴低8位寄存器
#define MPU_ACCEL_YOUTH_REG		0X3D	//加速度值,Y轴高8位寄存器
#define MPU_ACCEL_YOUTL_REG		0X3E	//加速度值,Y轴低8位寄存器
#define MPU_ACCEL_ZOUTH_REG		0X3F	//加速度值,Z轴高8位寄存器
#define MPU_ACCEL_ZOUTL_REG		0X40	//加速度值,Z轴低8位寄存器

#define MPU_TEMP_OUTH_REG		0X41	//温度值高八位寄存器
#define MPU_TEMP_OUTL_REG		0X42	//温度值低8位寄存器

#define MPU_GYRO_XOUTH_REG		0X43	//陀螺仪值,X轴高8位寄存器
#define MPU_GYRO_XOUTL_REG		0X44	//陀螺仪值,X轴低8位寄存器
#define MPU_GYRO_YOUTH_REG		0X45	//陀螺仪值,Y轴高8位寄存器
#define MPU_GYRO_YOUTL_REG		0X46	//陀螺仪值,Y轴低8位寄存器
#define MPU_GYRO_ZOUTH_REG		0X47	//陀螺仪值,Z轴高8位寄存器
#define MPU_GYRO_ZOUTL_REG		0X48	//陀螺仪值,Z轴低8位寄存器

#define MPU_I2CSLV0_DO_REG		0X63	//IIC从机0数据寄存器
#define MPU_I2CSLV1_DO_REG		0X64	//IIC从机1数据寄存器
#define MPU_I2CSLV2_DO_REG		0X65	//IIC从机2数据寄存器
#define MPU_I2CSLV3_DO_REG		0X66	//IIC从机3数据寄存器

#define MPU_I2CMST_DELAY_REG	0X67	//IIC主机延时管理寄存器
#define MPU_SIGPATH_RST_REG		0X68	//信号通道复位寄存器
#define MPU_MDETECT_CTRL_REG	0X69	//运动检测控制寄存器
#define MPU_USER_CTRL_REG		0X6A	//用户控制寄存器
#define MPU_PWR_MGMT1_REG		0X6B	//电源管理寄存器1
#define MPU_PWR_MGMT2_REG		0X6C	//电源管理寄存器2 
#define MPU_FIFO_CNTH_REG		0X72	//FIFO计数寄存器高八位
#define MPU_FIFO_CNTL_REG		0X73	//FIFO计数寄存器低八位
#define MPU_FIFO_RW_REG			0X74	//FIFO读写寄存器
#define MPU_DEVICE_ID_REG		0X75	//器件ID寄存器
 
//如果AD0脚(9脚)接地,IIC地址为0X68(不包含最低位).
//如果接V3.3,则IIC地址为0X69(不包含最低位).
#define MPU_ADDR				0X68

因为开发板接GND,所以转为读写地址后,为0XD1和0XD0(如果接GND,则为0XD3和0XD2)  
//#define MPU_READ    0XD1
//#define MPU_WRITE   0XD0
#endif

上述就是应用层的全部实现过程了,还是那句话,驱动一定必须加载起来哦!


总结

到这里呢是不是发现这个项目做的东西已经很多了,又要移植boa,又要移植CGI,还要CGI编程,还要实现网页和A9平台的通信,还得实现A9与html的数据上传,确实挺麻烦的,这些其实都是最基础的,后面我们还需要实现GPRS报警,并且实现视频数据流的上传,这样才能彻底的安防监控!最后,各位小伙伴们如果有收获,可以点赞收藏哦,你们的认可是我创作的动力,一起加油!

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

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

相关文章

AI大模型时代网络安全攻防对抗升级,瑞数信息变革“下一代应用与数据安全”

AI与大模型技术加速普及&#xff0c;安全领域也在以创新视角聚焦下一代应用安全WAAP变革&#xff0c;拓展新一代数据安全领域。近日瑞数信息重磅发布了瑞数全新API扫描器、API安全审计、数据安全检测与应急响应系统及分布式数据库备份系统四大新品。此次发布在延续瑞数信息Bot自…

【中国知名企业高管团队】系列55:奇瑞汽车

昨天华研荟介绍了吉利集团的现状&#xff0c;创始人李书福先生的故事&#xff0c;以及吉利集团的现任高管团队。我们了解到现在的吉利集团品牌多元化&#xff0c;吉利汽车只是其中的一个品牌和产业集团&#xff0c;整个吉利集团有十余个汽车品牌&#xff0c;还有多个网约车品牌…

力扣第416题 *** 分割等和子集 c++ 新题 动态规划 中的 01背包问题

题目 416. 分割等和子集 中等 相关标签 数组 动态规划 给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集&#xff0c;使得两个子集的元素和相等。 示例 1&#xff1a; 输入&#xff1a;nums [1,5,11,5] 输出&#xff1a;true 解释…

qt 系列(二)---qt designer通过设置控件样式表进行背景颜色设置

1. 前言 一般Layouts不可以进行改变样式表&#xff0c;当我们想修改背景样式表&#xff0c;同时又不改变其他控件的颜色时&#xff0c;可以选择List View 控件改变背景颜色。 2. 设置背景 &#xff08;1&#xff09;配置 .qrc 文件 新建mypicture.qrc文件&#xff0c;记事本打…

【刷题宝典NO.0】

目录 素数的判定 打印素数 打印水仙花数 百钱买百坤 输出闰年 逆序打印一个整数的每一位 输出乘法口诀表 数字9出现的次数 二进制1的个数 输出一个整数的偶数位和奇数位的二进制序列 求两个整数的最大公约数 求两个整数的最小公倍数 小乐乐与欧几里得 小…

C#,数值计算——积分方程与逆理论Quad_matrix的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { public class Quad_matrix : UniVarRealMultiValueFun { private int n { get; set; } private double x { get; set; } public Quad_matrix(double[,] a) { this.n a…

适用于 Linux 的 WPF:Avalonia

许多年前&#xff0c;在 WPF 成为“Windows Presentation Foundation”并将 XAML 作为 .NET、Windows 等的 UI 标记语言引入之前&#xff0c;有一个代号为“Avalon”的项目。Avalon 是 WPF 的代号。XAML 现在无处不在&#xff0c;XAML 标准是一个词汇规范。 Avalonia 是一个开…

精品Python空巢老人志愿服务平台慈善捐赠活动报名

《[含文档PPT源码等]精品基于Python的空巢老人志愿服务平台》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功&#xff01; 软件开发环境及开发工具&#xff1a; 开发语言&#xff1a;python 使用框架&#xff1a;Django 前端技术&#…

EasyExcel复杂表头数据导入

目录 表头示例导入代码数据导出 表头示例 导入代码 Overridepublic void importExcel(InputStream inputStream) {ItemExcelListener itemExcelListener new ItemExcelListener();EasyExcel.read(inputStream, ImportItem.class, itemExcelListener).headRowNumber(2).sheet()…

【蓝桥每日一题]-二分类型(保姆级教程 篇2) #砍树 #木材加工

今天讲二分的例题&#xff0c;一道是“砍树”&#xff0c;一道是“木材加工” 目录 题目&#xff1a;砍树 思路1&#xff1a; 思路2&#xff1a; 题目&#xff1a;木材加工 思路&#xff1a; 题目&#xff1a;砍树 思路1&#xff1a; 二分查找&#xff1a;对高度进行二分 二…

关注云栖大会的感受:从工业大脑到全面AI时代的进化

前言 自2009年的地方网站峰会到如今的云栖大会&#xff0c;这个盛大的科技盛事已经走过了一个多十年的漫长历程。这个会议见证了中国科技行业的崛起&#xff0c;也记录了技术的不断演化。而对我来说&#xff0c;首次接触云栖大会是在2020年&#xff0c;当年大会迁移到线上&…

从零开发基于ASM字节码的Java代码混淆插件XHood

项目背景 因在公司负责基础框架的开发设计&#xff0c;所以针对框架源代码的保护工作比较重视&#xff0c;之前也加入了一系列保护措施 例如自定义classloader加密保护&#xff0c;授权license保护等&#xff0c;但都是防君子不防小人&#xff0c;安全等级还比较低 经过调研…

【密评】商用密码应用安全性评估从业人员考核题库(十七)

商用密码应用安全性评估从业人员考核题库&#xff08;十七&#xff09; 国密局给的参考题库5000道只是基础题&#xff0c;后续更新完5000还会继续更其他高质量题库&#xff0c;持续学习&#xff0c;共同进步。 4001 多项选择题 网络和通信安全层面的通信主体一般包括哪些&…

基于Docker-consul容器服务更新与发现

目录 一、什么是服务注册与发现&#xff1a; 二、Docker-consul介绍&#xff1a; 三、consul的关键特性&#xff1a; 四、consul部署&#xff1a; 1.部署规划&#xff1a; 2.consul服务器部署&#xff1a; 2.1 建立consul服务&#xff1a; 启动consul后默认会监听5个端口&a…

管理双因素身份验证的Web应用2FAuth

什么是 2FAuth &#xff1f; 2FAuth 是一种基于 Web 的自托管替代方案&#xff0c;可替代 Google Authenticator 等一次性密码 (OTP) 生成器&#xff0c;专为移动设备和桌面设备设计。 近年来&#xff0c;双因素身份验证变得非常流行&#xff0c;2FA 现在是不可避免且至关重要的…

阿里云ECS经济型e实例ecs.e-c1m1.large性能测评

阿里云服务器ECS经济型e实例2核2G配置规格ecs.e-c1m1.large&#xff0c;CPU采用Intel Xeon Platinum架构处理器&#xff0c;e系列云服务器是阿里云面向个人开发者、学生、小微企业&#xff0c;在中小型网站建设、开发测试、轻量级应用等场景推出的全新入门级云服务器。目前云服…

C++ 类型

4.5//默认double类型 4.5f//float类型 基本内置类型 基本内置类型包含算术类型和空类型&#xff0c;算术类型包含字符、整数型、布尔值和浮点数&#xff0c;空类型不对应具体的值&#xff0c;仅用于一些特殊的场合。 算术类型 分为两类&#xff0c;整型&#xff08;包括字…

艾奇免费KTV电子相册视频制作软件

不得不承认功能特色支持添加导入图形、视频、歌曲、卡啦ok动态歌词字幕文件&#xff1a;图形文件格式支持导入jpg/jpeg/png/bmp/gif等静态图形&#xff1b;视频文件支持导入AVI/MP4/FLV/MTS/MPG/RMVB等几乎所有常见视频文件&#xff1b;歌曲格式支持mp3/wma/acc/ogg/wav等几乎所…

力扣第96题 不同的二叉搜索树 c++ 二叉搜索树 动态规划 + 数学思维

题目 96. 不同的二叉搜索树 中等 相关标签 树 二叉搜索树 数学 动态规划 二叉树 给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#…

NoSQL数据库使用场景以及架构介绍

文章目录 一. 什么是NoSQL&#xff1f;二. NoSQL分类三. NoSQL与关系数据库有什么区别四. NoSQL主要优势和缺点五. NoSQL体系框架 其它相关推荐&#xff1a; 系统架构之微服务架构 系统架构设计之微内核架构 鸿蒙操作系统架构 架构设计之大数据架构&#xff08;Lambda架构、Kap…