网站建设可以买东西/网站制作公司有哪些
目录
前言
项目特点及介绍
① 简单易用
② 软件可配置、易扩展
③ 纯 C 语言编程
软件总框架
显示系统
1.数据结构抽象
disp_manager.h
2.Framebuffer编程
framebuffer.c
3.显示管理
disp_manager.c
4.单元测试
disp_test.c
顶层目录Makefile
顶层目录Makefile.build
底层目录display中的Makefile
底层目录unittest中的Makefile
前言
今天开始学习Linux的第一个实战项目——电子产品量产测试与烧写工具,简称量产工具。这是一套软件,用在我们的实际生产中,有如下特点:
项目特点及介绍
① 简单易用
把这套软件烧写在 SD 卡上,插到 IMX6ULL 板子里并启动,它就会自动测试各个模块、烧写 EMMC 系统。
工人只要按照说明接入几个模块,就可以完成整个测试、烧写过程。
测试结果一目了然:等 LCD 上所有模块的图标都变绿时,就表示测试通过。
② 软件可配置、易扩展
通过配置文件添加测试项,可以添加不限个数的测试项。
每个测试项有自己的测试程序,测试通过后把结果发送给 GUI 即可。各个测试程序互不影响。
③ 纯 C 语言编程
下图是这个工具的界面,它可以一边测试一边烧写:
上图中的 led、speaker 按钮,可以点击:
① 当你看到 LED 闪烁时,就点击 led 按钮,它变成绿色表示测试通过;
② 当你从耳机里听到声音时,就点击 speaker 按钮,它变成绿色表示测试通过。
其他按钮无法点击,接上对应模块后会自动测试,测试通过时图标就会变绿。
上图中的蓝色按钮表示烧写 EMMC 的进度,烧写成功后它也会变绿。
LCD 上所有图标都变绿时,就表示测试、烧写全部完成;某项保持红色的话,就表示对应模块测试失败。
对这个项目,我们要拆分出多个子系统,并且这些子系统与业务无关,以后还可以应用在其他项目上;我们编写各个子系统的代码时,要抽象出它的对外接口,增加它的扩展性,减少和其他模块的耦合性。通过这个项目,能锻炼我们面向对象的编程思想以及对事物的抽象能力等等。这个项目可以无限扩展,比如:
软件总框架
要想最大程度复用我们写的代码,就需要模块化编程,拿显示系统举例,我们可以通过Framebuffer把数据显示到屏幕上,我们就可以构造出一个结构体,调用结构体里的初始化函数等等来使用这个模块;对于有些设备,它可能不需要用到屏幕,而是用到web输出,通过网络的方式显示数据,在网页打印出来,假设我们以后对于显示系统还要添加更多的模块,对于每个模块我们都要构造出它的结构体吗?显然是不用的,我们可以抽象出同一个结构体类型。
显示系统
1.数据结构抽象
来看看这个框图,我们要先获得一个buffer,我们可以自己在这个buffer里绘制我们想要的图案,绘制好后可以通过Framebuffer刷到屏幕上显示,也可以通过网络传输在浏览器上显示出来。
我们可以定义出下面这个结构体:
disp_manager.h
#ifndef _DISP_MANAGER_H
#define _DISP_MANAGER_H/*编译的时候报错说NULL未定义,我们干脆自己定义好了*/
#ifndef NULL
#define NULL (void *)0
#endif/*存放buffer的信息*/
typedef struct DispBuff {int iXres;/*x坐标的像素值*/int iYres;/*y坐标的像素值*/int iBpp;/*每个像素有多少位(像素的大小)*/char *buff;/*指向得到的buffer,然后就可以操作它了*/
}DispBuff, *PDispBuff;/*存放图像的区域信息*/
typedef struct Region {int iLeftUpX;/*区域左上角的x坐标*/int iLeftUpY;/*区域左上角的y坐标*/int iWidth;/*宽*/int iHeight;/*高*/
}Region, *PRegion;/*模块调用这个结构体里的函数,需要我们自己去实现里面的函数*/
typedef struct DispOpr {char *name;int (*DeviceInit)(void);//初始化函数int (*DeviceExit)(void);//退出函数int (*GetBuffer)(PDispBuff ptDispBuff);//获得buffer,以便绘制图像int (*FlushRegion)(PRegion ptRegion, PDispBuff ptDispBuff);//将buffer刷到对应的设备
(屏幕/网页),将ptDispBuff结构体指针指向的结构体里的buffer信息刷到Region结构体里(存放区域的信息)
表示你想在哪里显示?struct DispOpr *ptNext;//用链表管理这些模块
}DispOpr, *PDispOpr;/*****************************************/
/** 这些声明的函数我们后面再写,我先给出源码,先忽略这部分*/
void RegisterDisplay(PDispOpr ptDispOpr);void DisplayInit(void);
int SelectDefaultDisplay(char *name);
int InitDefaultDisplay(void);
int PutPixel(int x, int y, unsigned int dwColor);
int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff);
PDispBuff GetDisplayBuffer(void);#endif
这些结构体都是一步一步改善过来的,所以我尽量把注释写的详细一点,我们想要在屏幕或者网页(网页暂时没有实现)上显示,我们首先要实现 struct DispOpr 这个结构体里的各个函数,然后定义出各个模块的结构体,就可以调用定义出来的结构体里的函数实现各个功能。
2.Framebuffer编程
对于Framebuffer编程不熟悉的同学可以去看我这篇博客Framebuffer应用编程,下面用到的函数都是直接复制之前写的代码,原理就不再讲解了。
framebuffer.c
我们先定义出给LCD屏幕使用的结构体,再去实现底层的函数。以后上层APP就可以调用结构体里的 DeviceInit 等函数,不需要关心底层的驱动代码。这就是面向对象的编程思想。
源码如下:
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <disp_manager.h>static int fd_fb;
static struct fb_var_screeninfo var; /* Current var */
static int screen_size;
static unsigned char *fb_base;
static unsigned int line_width;
static unsigned int pixel_width;/*初始化函数*/
static int FbDeviceInit(void)
{/*打开设备结点,获得LCD参数等等*/fd_fb = open("/dev/fb0", O_RDWR);if (fd_fb < 0){printf("can't open /dev/fb0\n");return -1;}if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)){printf("can't get var\n");return -1;}/*使用mmap函数获得可以直接操作LCD的buffer*/line_width = var.xres * var.bits_per_pixel / 8;pixel_width = var.bits_per_pixel / 8;screen_size = var.xres * var.yres * var.bits_per_pixel / 8;fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);if (fb_base == (unsigned char *)-1){printf("can't mmap\n");return -1;}return 0;
}/*退出函数*/
static int FbDeviceExit(void)
{/*释放buffer,关闭设备结点*/munmap(fb_base, screen_size);close(fd_fb);return 0;
}/* 可以返回LCD的framebuffer, 以后上层APP可以直接操作LCD, 可以不用FbFlushRegion* 也可以malloc返回一块无关的buffer, 要使用FbFlushRegion*/
static int FbGetBuffer(PDispBuff ptDispBuff)
{ptDispBuff->iXres = var.xres;ptDispBuff->iYres = var.yres;ptDispBuff->iBpp = var.bits_per_pixel;ptDispBuff->buff = (char *)fb_base;return 0;
}/*为了方便,我们直接得到可以操作LCD的buffer,因此不需要Flush函数*/
static int FbFlushRegion(PRegion ptRegion, PDispBuff ptDispBuff)
{return 0;
}static DispOpr g_tFramebufferOpr = {.name = "fb",.DeviceInit = FbDeviceInit,.DeviceExit = FbDeviceExit,.GetBuffer = FbGetBuffer,.FlushRegion = FbFlushRegion,
};/*RegisterDisplay函数是将显示系统的所有设备注册到链表里统一管理,这在后面会讲,这里先忽略*/
void FramebufferInit(void)
{RegisterDisplay(&g_tFramebufferOpr);
}
这里就是实现了底层的驱动函数,实现 DispOpr 结构里的函数。
3.显示管理
我们的应用程序当然可以直接使用我们上面构造的结构体,但是我有多个显示模块,我们还需要一个公共的部分,来选择我们要使用的模块,所以需要还需要写出管理底层模块的代码。
框图如下:
我们要写出 disp_manager.c 这个程序,它起到承上启下的作用,很多函数其实也只是调用最底层的代码,但是我们再经过一层封装,就非常方便的实现管理底层的模块
disp_manager.c
#include <stdio.h>
#include <string.h>
#include <disp_manager.h>/* 管理底层的LCD、WEB */
static PDispOpr g_DispDevs = NULL;/*创建一个空的链表*/
static PDispOpr g_DispDefault = NULL;/*这个指针指向想要操作的模块,相当于句柄*/
static DispBuff g_tDispBuff;
static int line_width;
static int pixel_width;/*描点函数,是所有图像的基础,我之前写的Framebuffer应用编程里有讲*/
int PutPixel(int x, int y, unsigned int dwColor)
{unsigned char *pen_8 = (unsigned char *)(g_tDispBuff.buff+y*line_width+x*pixel_width);unsigned short *pen_16; unsigned int *pen_32; unsigned int red, green, blue; pen_16 = (unsigned short *)pen_8;pen_32 = (unsigned int *)pen_8;switch (g_tDispBuff.iBpp){case 8:{*pen_8 = dwColor;break;}case 16:{/* 565 */red = (dwColor >> 16) & 0xff;green = (dwColor >> 8) & 0xff;blue = (dwColor >> 0) & 0xff;dwColor = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);*pen_16 = dwColor;break;}case 32:{*pen_32 = dwColor;break;}default:{printf("can't surport %dbpp\n", g_tDispBuff.iBpp);return -1;break;}}return 0;
}/*注册函数,把模块放进链表里统一管理*/
void RegisterDisplay(PDispOpr ptDispOpr)
{ptDispOpr->ptNext = g_DispDevs;g_DispDevs = ptDispOpr;
}/* 选择函数,传入想要操作的底层模块的名字,如"fb",表示使用Framebuffer在屏幕上显示* 遍历链表,如果模块注册进链表里并且找到了名字,g_DispDefault就会指向我们想操作的模块的结构体*/
int SelectDefaultDisplay(char *name)
{PDispOpr pTmp = g_DispDevs;while (pTmp) {if (strcmp(name, pTmp->name) == 0){g_DispDefault = pTmp;return 0;}pTmp = pTmp->ptNext;}return -1;
}/*初始化函数,其实就是调用底层的初始化*/
int InitDefaultDisplay(void)
{int ret;/*调用g_DispDefault指向的结构体,调用底层的模块初始化函数*/ret = g_DispDefault->DeviceInit();if (ret){printf("DeviceInit err\n");return -1;}/*获得buffer,参数会保存在传入的结构体里面*/ret = g_DispDefault->GetBuffer(&g_tDispBuff);if (ret){printf("GetBuffer err\n");return -1;}/*这两个参数是为了给描点函数用的,看描点函数第一行计算pen_8的地址,需要这两个参数*/line_width = g_tDispBuff.iXres * g_tDispBuff.iBpp/8;pixel_width = g_tDispBuff.iBpp/8;return 0;
}/*把获得到的buffer返回给上层代码*/
PDispBuff GetDisplayBuffer(void)
{return &g_tDispBuff;
}/*Flush函数,底层的Flush函数我们并没有写,这里可以忽略*/
int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff)
{return g_DispDefault->FlushRegion(ptRegion, ptDispBuff);
}/*这里的初始化函数是将模块的结构体注册到链表里*/
void DisplayInit(void)
{extern void FramebufferInit(void);FramebufferInit();
}
虽然代码封装了很多层,但是这样便于以后添加更多的模块,更加容易扩展和移植。
4.单元测试
disp_test.c
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>#include <disp_manager.h>#define FONTDATAMAX 4096
/*略*/
需要自己定义点阵字体,这里我就省略了,可以看我关于Framebuffer的博客,或者去看韦东山老师的相关课程,里面有讲到哪里可以找到这个字体库。
/*********************************************************************** 函数名称: lcd_put_ascii* 功能描述: 在LCD指定位置上显示一个8*16的字符* 输入参数: x坐标,y坐标,ascii码* 输出参数: 无* 返 回 值: 无* 修改日期 版本号 修改人 修改内容* -----------------------------------------------* 2020/05/12 V1.0 zh(angenao) 创建***********************************************************************/
void lcd_put_ascii(int x, int y, unsigned char c)
{unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];int i, b;unsigned char byte;for (i = 0; i < 16; i++){byte = dots[i];for (b = 7; b >= 0; b--){if (byte & (1<<b)){/* show */PutPixel(x+7-b, y+i, 0xffffff); /* 白 */}else{/* hide */PutPixel(x+7-b, y+i, 0); /* 黑 */}}}
}int main(int argc, char **argv)
{Region region;PDispBuff ptBuffer;/*调用这个函数把所有模块注册到链表里(我们暂时只用到Framebuffer)*/DisplayInit();/*然后选择要操作的模块,传入名字*/SelectDefaultDisplay("fb");/*底层的初始化(打开设备节点等操作)*/InitDefaultDisplay();/*调用显示字符的函数,在这个函数里会调用的描点函数,所以我说描点函数是基础*/lcd_put_ascii(100, 100, 'A');/*这里是初始化一下要传入Flush函数的结构体*/region.iLeftUpX = 100;region.iLeftUpY = 100;region.iWidth = 8;region.iHeigh = 16;/*获得buffer*/ptBuffer = GetDisplayBuffer();/*刷到硬件上(暂时只有屏幕)*/FlushDisplayRegion(®ion, ptBuffer);return 0;
}
接下来给大伙看看函数的调用流程。
多层函数的封装看起来会很乱,但如果看过我之前一篇博客UART开发基础,这篇博客也是我第一次接触这种面向对象的编程思想,像我之前写代码,也是直接APP调用底层函数,快准狠,但是如果以后工作,这种方法显然不可行,而且也锻炼不了什么事物抽象的能力,面对一些大型的项目可能会无从下手,但是这些结构体里的参数,也不是一下子就能想出来的,都是边写边补,缺啥补啥。
上传到Ubuntu时,要整个文件上传,如下:
并且在要编译的文件夹下添加Makefile,可以看这篇博客Makefile保姆级教程
顶层目录Makefile
CROSS_COMPILE ?=
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
export AS LD CC CPP AR NM
export STRIP OBJCOPY OBJDUMP
CFLAGS := -Wall -O2 -g
CFLAGS += -I $(shell pwd)/include
LDFLAGS :=
export CFLAGS LDFLAGS
TOPDIR := $(shell pwd)
export TOPDIR
TARGET := test
obj-y += display/
obj-y += unittest/
all : start_recursive_build $(TARGET)
@echo $(TARGET) has been built!
start_recursive_build:
make -C ./ -f $(TOPDIR)/Makefile.build
$(TARGET) : built-in.o
$(CC) -o $(TARGET) built-in.o $(LDFLAGS)
clean:
rm -f $(shell find -name "*.o")
rm -f $(TARGET)
distclean:
rm -f $(shell find -name "*.o")
rm -f $(shell find -name "*.d")
rm -f $(TARGET)
顶层目录Makefile.build
PHONY := __build
__build:
obj-y :=
subdir-y :=
EXTRA_CFLAGS :=
include Makefile
# obj-y := a.o b.o c/ d/
# $(filter %/, $(obj-y)) : c/ d/
# __subdir-y : c d
# subdir-y : c d
__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))
subdir-y += $(__subdir-y)
# c/built-in.o d/built-in.o
subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o)
# a.o b.o
cur_objs := $(filter-out %/, $(obj-y))
dep_files := $(foreach f,$(cur_objs),.$(f).d)
dep_files := $(wildcard $(dep_files))
ifneq ($(dep_files),)
include $(dep_files)
endif
PHONY += $(subdir-y)
__build : $(subdir-y) built-in.o
$(subdir-y):
make -C $@ -f $(TOPDIR)/Makefile.build
built-in.o : $(cur_objs) $(subdir_objs)
$(LD) -r -o $@ $^
dep_file = .$@.d
%.o : %.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -Wp,-MD,$(dep_file) -c -o $@ $<
.PHONY : $(PHONY)
底层目录display中的Makefile
EXTRA_CFLAGS :=
CFLAGS_file.o :=
obj-y += disp_manager.o
obj-y += framebuffer.o
底层目录unittest中的Makefile
EXTRA_CFLAGS :=
CFLAGS_file.o :=
obj-y += disp_test.o
量产工具的第一篇博客就到此为止,下一篇是量产工具的输入系统,希望大伙多多关注支持。
相关文章:

Linux应用项目之量产工具(一)——显示系统
目录 前言 项目特点及介绍 ① 简单易用 ② 软件可配置、易扩展 ③ 纯 C 语言编程 软件总框架 显示系统 1.数据结构抽象 disp_manager.h 2.Framebuffer编程 framebuffer.c 3.显示管理 disp_manager.c 4.单元测试 disp_test.c 顶层目录Makefile 顶层目录Makefil…...

Python小白学习教程从入门到入坑------第二十九课 访问模式(语法进阶)
目录 一、访问模式 1.1 r 1.2 w 1.3 1.3.1 r 1.3.2 w 1.3.3 a 1.4 a 一、访问模式 模式可做操作若文件不存在是否覆盖r只能读报错-r可读可写报错是w只能写创建是w可读可写创建是a只能写创建否,追加写a可读可写创建否,追加写 1.1 r r&…...

使用 PageHelper 在 Spring Boot 项目中实现分页查询
目录 前言1. 项目环境配置1.1 添加 PageHelper 依赖1.2 数据库和 MyBatis 配置 2. 统一的分页响应类3. 使用 PageHelper 实现分页查询3.1 Service 层分页查询实现3.2 PageHelper 分页注意事项 4. 控制层调用示例5. 常见问题与解决方案5.1 java.util.ArrayList cannot be cast t…...

深度学习-张量相关
一. 张量的创建 张量简介 张量是pytorch的基本数据结构 张量,英文为Tensor,是机器学习的基本构建模块,是以数字方式表示数据的形式。 例如,图像可以表示为形状为 [3, 224, 224] 的张量,这意味着 [colour_channels, h…...

电脑提示xinput1_3.dll丢失怎么解决,分享6种有效的解决方法
xinput1_3.dll 是一个动态链接库(DLL)文件,它在Windows操作系统中扮演着重要的角色,特别是在处理游戏控制器和其他输入设备的交互方面。这个文件是Microsoft DirectX软件包的一部分,DirectX是微软公司开发的一个多媒体…...

【计网】数据链路层笔记
【计网】数据链路层 数据链路层概述 数据链路层在网络体系结构中所处的地位 链路、数据链路和帧 链路(Link)是指从一个节点到相邻节点的一段物理线路(有线或无线),而中间没有任何其他的交换节点。 数据链路(Data Link)是基于链路的。当在一条链路上传送数据时&a…...

蓝牙FTP 协议详解及 Android 实现
文章目录 前言一、什么是蓝牙 FTP 协议?二、FTP 的工作流程1.蓝牙设备初始化2. 设备发现与配对3. 建立OBEX FTP 连接4. 文件传输文件上传(通过OBEX PUT命令)文件下载(通过OBEX GET命令) 5. 关闭OBEX会话 三、进阶应用与…...

【前端】Svelte:动画效果
在现代前端开发中,动画效果可以大大提升用户体验,使应用更生动、易用。Svelte 提供了灵活的动画 API,让开发者能够快速实现从简单过渡到复杂动画的各种效果。本文将系统性地介绍 Svelte 的动画功能,并通过多个示例演示如何创建动感…...

2024系统架构师--论基于架构的软件设计方法(ABSD)及应用(论文范文)
题目: 基于架构的软件设计(Architecture-Based Software Design,ABSD)方法以构成软件架构的商业、质量和功能需求等要素来驱动整个软件开发过程。ABSD是一个自顶向下,递归细化的软件开发方法,它以软件系统功能的分解为基础,通过选择架构风格实现质量和商业需求,并强调在架…...

ORU 的 Open RAN 管理平面 (M 平面)
[TOC](ORU 的 Open RAN 管理平面 (M 平面)) ORU 的 Open RAN 管理平面 (M 平面) https://www.techplayon.com/open-ran-management-plane-m-plane-for-open-radio-unit/ ORU M 平面 在 ORAN 中,设置参数的 O-RU 管理功能是通过 M-Plane 完成的。管理功能包括 O-…...

软件缺陷等级评定综述
1. 前言 正确评估软件缺陷等级,在项目的生命周期中有着重要的作用: 指导缺陷修复的优先级和资源分配 在软件开发和维护过程中,资源(包括人力、时间和资金)是有限的。通过明确缺陷的危险等级,可以帮助团队合…...

Nuxt.js 应用中的 schema:extend事件钩子详解
title: Nuxt.js 应用中的 schema:extend事件钩子详解 date: 2024/11/10 updated: 2024/11/10 author: cmdragon excerpt: schema:extend 钩子使开发者能够扩展默认数据模式,为特定业务需求添加自定义字段和验证。 categories: 前端开发tags: Nuxt钩子数据扩展自定义验证应…...

自然语言处理在客户服务中的应用
💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 自然语言处理在客户服务中的应用 自然语言处理在客户服务中的应用 自然语言处理在客户服务中的应用 引言 自然语言处理概述 定义…...

OpenCoder:首个完全开源的顶级代码大模型,训练秘籍全公开!| LLM×MapReduce,无需训练就超越GPT-4!
大模型领域的发展日新月异,每天都有许多有趣的论文值得深入品读。下面是本期觉得比较有意思的论文: 1、OpenCoder:首个完全开源的顶级代码大模型,训练秘籍全公开!2、超长文本处理新突破!LLMMapReduce&…...

springboot静态资源映射不生效问题
最近有个同事问我,静态资源映射不生效的问题,很正常我想不就是配置下资源路径就可以了吗?类似配置如下代码 Configuration public class CorsConfig implements WebMvcConfigurer {Overridepublic void addResourceHandlers(ResourceHandlerR…...

通过 SSH 隧道将本地端口转发到远程主机
由于服务器防火墙,只开放了22端口,想要通过5901访问服务器上的远程桌面,可以通过下面的方式进行隧道转发。 一、示例命令 这条代码的作用是通过 SSH 创建一个 本地端口转发,将你本地的端口(5901)通过加密的 SSH 隧道连接到远程服务器上的端口(5901)。这种方式通常用于在…...

【北京迅为】itop-3588开发板摄像头使用手册Android12 双摄方案
本章节对应资料在网盘资料“iTOP-3588 开发板\02_【iTOP-RK3588 开发板】开发资料 \07_Android 系统开发配套资料\08_Android12 摄像头使用配套资料”目录下下载。 2.1 Android12 前摄后摄 网盘中默认的 Android12 源码支持四个摄像头单独打开,本小节我们来修改源码…...

初见Linux:基础开发工具
前言: 这篇文章我们将讲述Linux的基本开发工具,以及讨论Linux的生态圈,最后再了解vim开发工具。 Yum: YUM(Yellowdog Updater Modified)是一个在Linux系统中用于管理软件包的工具,特别是在基于…...

微服务架构面试内容整理-分布式配置管理-Nacos Config
Nacos Config 是 Nacos 提供的一个配置管理功能,专门用于动态管理应用的配置。在微服务架构中,Nacos Config 允许开发者集中管理和动态更新各个服务的配置,从而提升系统的灵活性和可维护性。以下是 Nacos Config 的主要特点、工作原理和使用场景: 主要特点 1. 动态配置管理…...

React官网生成Recat项目的区别
1. Next.js 特点: 页面级路由:使用文件系统路由,基于 /pages 文件夹的结构自动创建 URL 路径。渲染模式:支持三种渲染模式:静态生成 (SSG)、服务器端渲染 (SSR) 和客户端渲染 (CSR),并允许根据页面的具体需…...

网络安全---安全见闻
网络安全—安全见闻 拓宽视野不仅能够丰富我们的知识体系,也是自我提升和深造学习的重要途径!!! Web程序(网站) web站点、app都属于Web程序 二进制程序 与逆向分析挂钩 驱动程序 驱动程序也属于软件,以Windows系统…...

在 CSS 中,gap 是 布局容器(flex 或 grid)的属性。它用于设置容器内子元素之间的间距。
在 CSS 中,gap 是 布局容器(flex 或 grid)的属性。它用于设置容器内子元素之间的间距。以下是 gap 属性在不同布局中的应用: 1. 在 CSS Grid 布局中 gap 定义了网格行和列之间的间距。可以分别使用 row-gap 和 column-gap 设置行…...

[zotero]Ubuntu搭建WebDAV网盘
搭建Ubuntu Apache WebDAV网盘的综合步骤,使用666端口: 安装Apache和WebDAV模块: sudo apt update sudo apt install apache2 sudo a2enmod dav sudo a2enmod dav_fs创建WebDAV目录: sudo mkdir /var/www/webdav sudo chown www-d…...

力扣17-电话号码的数字组合
力扣17-电话号码的数字组合 思路代码 题目链接 思路 原题: 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 输…...

如何处理模型的过拟合和欠拟合问题
好久没有写人工智能这块的东西了,今天正好在家休息,给大家分享一下最近在训练时遇到的过拟合和欠拟合的问题,经过仔细的思考,总结如下: 在处理模型的过拟合和欠拟合问题时,我们需要根据具体情况采取不同的…...

CSRF详解
CSRF,全称是Cross-Site Request Forgery,即跨站请求伪造,也被称为“one click attack”或者session riding,是一种网络攻击方式。它允许攻击者诱导用户在已登录的Web应用程序上执行非预期的操作。 工作原理CSRF攻击通常涉及三个主…...

C# winform 的数据采集,采集周期是间隔10ms、100ms等等,但始终都有1ms的误差,并不是精准的10ms,哪些原因呢
C# winform 的数据采集,采集周期是间隔10ms、100ms等等,但始终都有1ms的误差,并不是精准的10ms,哪些原因呢 在C# WinForms应用程序中进行数据采集时,如果遇到采集周期存在1ms误差的问题,可能的原因包括&am…...

【国内中间件厂商排名及四大中间件对比分析】
国内中间件厂商排名 随着新兴技术的涌入,一批国产中间件厂商破土而出,并在短时间内迅速发展,我国中间件市场迎来洗牌,根据市占率,当前我国中间件厂商排名依次为:东方通、宝兰德、中创股份、金蝶天燕、普元…...

qt QLocale详解
1、概述 QLocale是Qt框架中的一个类,用于处理与本地化相关的操作。它能够方便地实现日期、时间、数字和货币的格式化和解析,支持不同的语言、区域设置和字符集。QLocale提供了一种跨平台的方式来获取当前系统的语言设置,并返回该语言的本地化…...

Node.js简介以及安装部署 (基础介绍 一)
Node.js简介 Node.js是运行在服务端的JavaScript。 Node.js是一个基于Chrome JavaScript运行时建立的一个平台。 Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。 Node.…...