ESP32-CAM网络摄像头系列-01-基于RTSP协议的局域网视频推流/拉流的简单实现

前言: 由于项目需要,最近开始开坑关于ESP32-CAM系列的RTSP网络摄像头系列,该文章为该系列的第一篇文章。用于记录项目开发过程。 本文解决的问题: 使用ESP32-CAM获取图像数据,并通过RTSP协议将获取到的视频流传输到上位机进行显示。 具体实现: 使用ESP32-CAM进行视频推流,python端作为rtsp拉流,其中ESP32-CAM使用arduinoIDE开发,使用了安信可的支持库。支持包安装网址: 拉流效果: 一、推流部分 官方示例代码: #include "OV2640.h" #include <WiFi.h> #include <WebServer.h> #include <WiFiClient.h> #include "SimStreamer.h" #include "OV2640Streamer.h" #include "CRtspSession.h" #define ENABLE_RTSPSERVER OV2640 cam; #ifdef ENABLE_WEBSERVER WebServer server(80); #endif #ifdef ENABLE_RTSPSERVER WiFiServer rtspServer(8554); #endif #ifdef SOFTAP_MODE IPAddress apIP = IPAddress(192, 168, 1, 1); #else #include "wifikeys_template.h" #endif #ifdef ENABLE_WEBSERVER void handle_jpg_stream(void) { WiFiClient client = server.client(); String response = "HTTP/1.1 200 OK\r\n"; response += "Content-Type: multipart/x-mixed-replace; boundary=frame\r\n\r\n"

再析jvm

前言 希望自己每一次学习都有不同的理解 文章目录 前言1. jvm的组成取消永久代使用元空间原因 2. 运行时数据区3. 堆栈区别队列和栈,队列先进先出,栈先进后出从栈顶弹出4. GC、内存溢出、垃圾回收4.1 如何确定引用是否会被回收4.1.1 Java中的引用类型4.1.2 如何定位对象 4.2 垃圾回收算法以及收集器4.3 分代垃圾回收器是怎么工作的4.4 jvm的类加载器什么是双亲委派机制类的加载过程 4.5 jvm调优流程参数如何调整参数 1. jvm的组成 Jdk1.6及之前:方法区(永久代), 常量池在方法区 Jdk1.7:有永久代,但已经逐步“去永久代”,常量池在堆 Jdk1.8及之后: 无永久代,元空间, HotSpot JVM 类加载子系统 Class loader 装载class文件到Runtime data area中的method area 执行引擎 Execution engine执行classes中的指令 本地方法接口库,与native libraries交互,是其它编程语 言交互的接口 运行时数据区 首先通过编译器把 Java 代码转换成字节码,类加载器(ClassLoader) 再把字节码加载到内存中,将其放在运行时数据区(Runtime data area)的方 法区内,而字节码文件只是 JVM 的一套指令集规范,并不能直接交给底层操作 系统去执行,因此需要特定的命令解析器执行引擎(ExecutionEngine),将 字节码翻译成底层系统指令,再交由 CPU 去执行,而这个过程中需要调用其他 语言的本地库接口(Native Interface)来实现整个程序的功能。 取消永久代使用元空间原因 1、字符串存在永久代中,容易出现性能问题和内存溢出。 2、类及方法的信息等比较难确定其大小,因此对于永久代的大小指定比较困难,太小容易出现永久代溢出,太大则容易导致老年代溢出。 3、永久代会为 GC 带来不必要的复杂度,并且回收效率偏低。 元空间的本质和永久代类似,元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。类的元数据放入 native memory, 字符串池和类的静态变量放入 java 堆中,这样可以加载多少类的元数据就不再由MaxPermSize 控制, 而由系统的实际可用空间来控制。

【PyQT5】自定义控件 显示网络图片

【PyQT5】自定义控件 显示网络图片 原理:使用 requests 获取图片,加载图片内容到控件中即可。 import sys import requests from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import (QWidget, QLabel, QVBoxLayout) from PyQt5.QtGui import QPixmap class Picture(QWidget): def __init__(self, parent=None, url=None): super().__init__(parent) self.url = url self.ui() def ui(self): # Get Pictures req = requests.get(self.url) photo = QPixmap() photo.loadFromData(req.content) label= QLabel() label.setPixmap(photo) layout =QVBoxLayout() layout.addWidget(label) self.setLayout(layout) if __name__ == '__main__': app = QApplication(sys.argv) url='https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=415293130,2419074865&fm=27&gp=0.jpg' pic = Picture(url=url) pic.show() sys.exit(app.exec_()) req = requests.get(self.url) 这一步会造成UI阻塞,建议使用twisted之类的库异步获取图片。

针对Pyinstaller的exe 反编译

#针对Pyinstaller的exe 反编译 再没有壳的情况下 使用pyinstxtractor.py 下载链接链接: https://sourceforge.net/projects/pyinstallerextractor/ 使用方法 python pyinstxtractor.py xxx.exe 他会详细告诉你python当时的版本和pyinstaller的版本,(python版本必须一致否则可能会报错) 然后当前目录会多一个文件夹,里面有个文件夹会包含所有的pyc文件 使用EasyPythonDecompiler,将pyc解析为py文件 https://sourceforge.net/projects/easypythondecompiler/ 打开软件 选择一个pyc文件,会再pyc文件目录上建一个同名_dis文件,直接编辑器打开就行(偶尔会有报错,可尝试使用在线反编译工具试试) 转载:https://www.cnblogs.com/edwar172038/p/7840359.html

linux SD卡驱动

Linux SD卡驱动开发(一) —— SD 相关基础概念 Linux SD卡驱动开发(一) —— SD 相关基础概念_zqixiao_09的博客-CSDN博客_tf驱动开发 Linux SD卡驱动开发(二) —— SD 卡驱动分析HOST篇 Linux SD卡驱动开发(二) —— SD 卡驱动分析HOST篇_zqixiao_09的博客-CSDN博客 Linux SD卡驱动开发(三) —— SD 卡驱动分析CORE篇 Linux SD卡驱动开发(三) —— SD 卡驱动分析CORE篇_zqixiao_09的博客-CSDN博客_sd_detect_pol Linux SD卡驱动开发(四) —— SD 控制器之真正的硬件操作 Linux SD卡驱动开发(四) —— SD 控制器之真正的硬件操作_zqixiao_09的博客-CSDN博客_mmcsd_send_request、 Linux SD卡驱动开发(五) —— SD 卡驱动分析Core补充篇 Linux SD卡驱动开发(五) —— SD 卡驱动分析Core补充篇_zqixiao_09的博客-CSDN博客_sdio_irq.c Linux SD卡驱动开发(六) —— SD卡启动过程总体分析 Linux SD卡驱动开发(六) —— SD卡启动过程总体分析_zqixiao_09的博客-CSDN博客

MYSQL安装部署--Linux 仓库安装 及 卸载

声明 : # 此次我们安装的 MYSQL 版本是 8.0.32 版本 我们本次安装 MYSQL 总共要介绍 四种方式 # 仓库安装 # 本地安装 # 容器安装 # 源码安装 我们本篇介绍的是 仓库安装 仓库安装 下载 MYSQL 安装包 # MYSQL 安装,我们都是基于 MYSQL 官方网站里进行下载~! 👉 MYSQL 官方网址 # 我们进入 官方网站 在 DOWNLOADS 页面,下方 点击下示红色标记 而后进入下示 ,点击红色标记 ✋ 上示红色标记就是 由 MYSQL 官方提供的仓库 然后进入,我们选择第一个,蓝色高亮显示的包 ,对它进行下载 ✋ 在这里需要对 下载 做以如下解释 : 为了把这个 rpm 包下载下来 ,我们有两种方式 第一种 : 就是 在 Windows 里下载,下载后,传到 Linux 上 ===>>> 那就,点击 Download,点击完后显示如下页面

TIOVX 学习笔记其三:concerto makefile

TIOVX 学习笔记其三:concerto makefile 1. Introduction2. Concerto basic’s3. Common command line options to use when building4. Anatomy of concerto.mak file4.1 示例4.2 变量 Reference: TIOVX User Guide 1. Introduction concerto 是一个基于 GNU 的搭建系统,被 PSDK RTOS 中的许多组件所使用。它是 make 规则和 make 宏的集合,可以跨多个代码生成工具、CPU arch、操作系统、SoC 进行流线编译和链接。 下面的部分使用了基于 concerto 的 PSDK RTOS 搭建系统: Ethernet firmwareRemote DeviceImagingPerception (PTK)TI OpenVXVideo codecVision apps 2. Concerto basic’s concerto 从项目根文件夹开始和根文件夹中所有子目录,寻找文件 concerto.mak。 每个 <kbd>concerto.mak 搭建一个 library 或者一个可执行文件要搜索的目录列在 /Makefile 中的 make 变量 DIRECTORIES 中 3.

python socket通信,客户端单次发送信息,服务端循环接收信息

客户端 客户端实现单次发送消息给服务端,接收到信息之后输出信息,并将连接关闭 import socket client = socket.socket() # 声明socket类型,同时生成socket连接对象 client.connect(('127.0.0.1', 789)) # 建立连接 client.send(b"hello world") # 发送信息 data = client.recv(1024) # 接受信息 print("recv:", data) client.close() # 关闭连接 服务端,接收到信息,并向客户端返回信息 import socket import traceback server = socket.socket() server.bind(('127.0.0.1', 789)) # 绑定要监听端口 server.listen() # 监听 print('begin...') # conn就是客户端连过来而再服务器端为其生成的一个连接实例 while True: conn = None try: conn, addr = server.accept() # 接收信息 except: print(traceback.print_exc()) # 若返回失误信息则结束程序 if conn != None: conn.close() break else: print("客户端 他 进来了!"

未知USB设备(设备描述符请求失败)解决方法之一

前言 网上很多帖子讲述了出现未知USB设备的处理情况。这里给大家提供一种其他的可能性,这是大部分帖子里都没讲到的。 解决方案 将线插到电脑上其他USB口上,先排除是不是电脑USB口的问题(如果电脑是台式机,尝试插机箱背面的USB口,以增强供电;如果是笔记本,尝试插靠近电源口的USB接口)。检查设备连接过程中是否使用了延长线、转接口、USB集线器等,如果使用了,请去除后直连电脑USB口(过长的USB线和转接等情况,会使外接设备供电减弱,导致识别失败)。 方案说明 使用延长线或者集线器,可能会使得供电减弱,此时外接设备将不能正常工作。延长线和集线器可能会存在接口问题。比如设备需要USB 3.0的环境,但是延长线或者集线器买的劣质的,只支持USB 1.1或USB2.0,达不到3.0标准,此时设备可能能供电,但是数据传输会受影响,从而导致识别上出现问题。 后续 对于电子设备的故障,通过控制变量法反复验证,可测出具体出问题情况。 比如上文中优先尝试电脑上其他USB口,排除是否是电脑接口问题。 然后通过更换设备间的线束,排除是否是线束问题。 随后可尝试连接到其他电脑上,排除是外接设备问题还是电脑问题。

无法将“create-react-app”项识别为 cmdlet、函数、脚本文件或可运行程序的名称

此次问题的报错主要是显示为该图片的样子 是在准备创建react项目的时候所遇到的问题,那么处理的方法入下所示 一、首先在Windows系统导航栏里找到Windows PowerShell! 二、使用管理员的身份运行,并且在PoweShell中输入set-ExecutionPolicy RemoteSigned的命令符 如下图所示 然后再次输入get-ExecutionPolicy发现出现RemoteSigned就可以了! 但是我发现再此之外还是会报相同的红色警告的错误 那么就来到了第三步 三、直接选择一个文件夹下进行create-react-app XXX 项目的创建 在create-react-app my-app命令前面,加上npx指令。如下: npx create-react-app my-app 执行之后,果然顺利创建了! 通过网上查询的原因是 npx 会自动查找当前依赖包中的可执行文件,如果找不到,就会去 PATH 里找。如果依然找不到,就会帮你安装。

Vue3后台管理系统(十一)wangEditor富文本编辑器

目录 一、安装wangEditor依赖 二、WangEditor组件封装 三、使用案例 一、安装wangEditor依赖 npm install @wangeditor/editor --save npm install @wangeditor/editor-for-vue@next --save 二、WangEditor组件封装 在src/components下新建WangEditor文件夹,并在WangEditor文件夹下新建index.vue <template> <div style="border: 1px solid #ccc"> <!-- 工具栏 --> <Toolbar :editor="editorRef" :defaultConfig="toolbarConfig" style="border-bottom: 1px solid #ccc" :mode="mode" /> <!-- 编辑器 --> <Editor :defaultConfig="editorConfig" v-model="defaultHtml" @onChange="handleChange" style="height: 500px; overflow-y: hidden" :mode="mode" @onCreated="handleCreated" /> </div> </template> <script setup lang="ts"> import { onBeforeUnmount, shallowRef, reactive, toRefs } from 'vue'; import { Editor, Toolbar } from '@wangeditor/editor-for-vue'; // API 引用 import { uploadFileApi } from '@/api/file'; const props = defineProps({ modelValue: { type: [String], default: '' } }); const emit = defineEmits(['update:modelValue']); // 编辑器实例,必须用 shallowRef const editorRef = shallowRef(); const state = reactive({ toolbarConfig: {}, editorConfig: { placeholder: '请输入内容.

1.1计算机和编成语言

一、C 语言简介 历史 C 语言最初是作为 Unix 系统的开发工具而发明的。 1969年,美国贝尔实验室的肯·汤普森(Ken Thompson)与丹尼斯·里奇(Dennis Ritchie)一起开发了 Unix 操作系统。Unix 是用汇编语言写的,无法移植到其他计算机,他们决定使用高级语言重写。但 是,当时的高级语言无法满足他们的要求,汤普森就在 BCPL 语言的基础上发明了 B 语言。 1972年,丹尼斯·里奇和布莱恩·柯林汉(Brian Kernighan)又在 B 语言的基础上重新设计了一种新语 言,这种新语言取代了 B 语言,所以称为 C 语言。 1973年,整个 Unix 系统都使用 C 语言重写。此后,这种语言开始快速流传,广泛用于各种操作系统和 系统软件的开发。 1988年,美国国家标准协会(ANSI)正式将 C 语言标准化,标志着 C 语言开始稳定和规范化。 几十年后的今天,C 语言依然是最广泛使用、最流行的系统编程语言之一,Unix 和 Linux 系统现在还是 使用 C 语言开发。 C 语言的特点 C 语言能够长盛不衰、广泛应用,主要原因是它有一些鲜明的特点。 (1)低级语言 C 语言能够直接操作硬件、管理内存、跟操作系统对话,这使得它是一种非常接近底层的语言,也就是 低级语言,非常适合写需要跟硬件交互、有极高性能要求的程序。 (2)可移植性 C 语言的原始设计目的,是将 Unix 系统移植到其他计算机架构。这使得它从一开始就非常注重可移植 性,C 程序可以相对简单地移植到各种硬件架构和操作系统。 除了计算机,C 语言现在还是嵌入式系统的首选编程语言,汽车、照相机、家用电器等设备的底层系统 都是用 C 语言编程,这也是因为它良好的可移植性。 (3)简单性 C 语言的语法相对简单,语法规则不算太多,也几乎没有语法糖。一般来说,如果两个语法可以完成几

已知带头结点有序的单向链表L={a1,a2,...an}(链表中有值相同的结点),试设计一个算法将值重复的结点删除,使所得的结果表中的值均不相同。

#include <stdio.h> #include <stdlib.h> typedef struct lnode //定义链表 { int data; struct lnode *next; }lnode,*linklist; void createfifo(linklist &l,int n) //创建先进先出链表函数 { int i; linklist p,q; l=(linklist)malloc(sizeof(lnode)); q=l; for(i=0;i<n;i++) { p=(linklist)malloc(sizeof(lnode)); scanf("%d",&p->data); q->next=p; q=p; } q->next=NULL; } void print(linklist l) //输出函数 { linklist p; p=l->next; while(p) { printf("%d ",p->data); p=p->next; } } void deletechongfu(linklist &l) //删除重复结点函数 { linklist p,q; p=l->next->next; q=l->next; while(p) { if(p->data==q->data) { q->next=p->next; p=p->next; } else {

Python matplotlib中图片不能显示中文

python中matplotlib显示中文时,会遇到一些问题, 解决方案如下: import matplotlib.pyplot as plt # 支持中文 plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号

ValueError: invalid literal for int() with base 10: ‘1.0‘

这个错误通常表示你正在尝试将一个无效的字符串转换为整数,例如,你的代码中出现了一个名为 ‘1.0’ 的字符串,它不能被解释为整数。出现这个错误通常是因为你的代码期望接收整数,但实际上输入数据中有一个字符串不能被解释为整数。 在这种情况下,你的代码可能尝试将一个浮点数转换为整数,但这是不可能的。例如,如果你的代码期望读取整数键连数据,但是输入数据中包含浮点数键连数据,那么就会出现这个错误。 为了解决这个问题,你需要仔细检查你的输入数据和代码,找到错误的数据和处理方法。你可以使用 print 语句和调试工具来查看程序中出现错误的数据,并逐步排除错误。 另外,需要注意的是,在某些情况下,如果你不确定一个字符串是否可以被解释为整数,可以使用 try/except 语句来处理可能出现的错误。例如: try: value = int(my_string) except ValueError: print("Cannot convert '{}' to int".format(my_string)) 这个代码块尝试将 my_string 转换为整数,如果无法转换,则会抛出 ValueError 异常。except 语句捕获这个异常并打印一条错误消息。这样可以避免程序崩溃,并帮助你更好地处理错误情况。

GXHT30温湿度传感器——与SHT30 pin to pin 兼容的温湿度传感器

GXHT30温湿度传感器——与SHT30 pin to pin 兼容的温湿度传感器 文章目录 目录 GXHT30温湿度传感器——与SHT30 pin to pin 兼容的温湿度传感器 文章目录 前言 一、传感器参数 二、使用示例(STM8l驱动) 1.IO口配置 2.配置SDA输入输出 3.通信子函数 4.读取数据 三.总结 前言 GXHT30温湿度传感器是一款国产温湿度I2C传感器芯片,由北京中科银河芯研发并量产,其性能与通信方式与SHT30完全兼容,可pin to pin替代SHT30,本文将针对该传感器的一些工作参数与通信进行介绍。 一、传感器参数 GXHT30温湿度传感器的工作参数与SHT30相差不大,对比如下。 GXHT30 SHT30 工作电压:2.4~5.5V 工作电压:2.4~5.5V 精度:±3%RH ,±0.2℃ 精度:±3%RH ,±0.3℃ 接口:I2C 接口:I2C 尺寸:2.5*2.5*0.9(mm) 尺寸:2.5*2.5*0.9(mm) 如图为找第三方设计的贴了防尘透气膜的GXHT30温湿度传感器demo。 二、使用示例(STM8l驱动) 1.IO口配置 I2C端口初始化:使用C0和C1分别配置为SDA和SCL。 #define I2C_SCL GPIO_Pin_1 #define I2C_SDA GPIO_Pin_0 #define GPIO_I2C GPIOC #define I2C_SCL_H GPIO_SetBits(GPIO_I2C,I2C_SCL) #define I2C_SCL_L GPIO_ResetBits(GPIO_I2C,I2C_SCL) #define I2C_SDA_H GPIO_SetBits(GPIO_I2C,I2C_SDA) #define I2C_SDA_L GPIO_ResetBits(GPIO_I2C,I2C_SDA) /**************************************************************************** * Function Name : IIC_Config * Description : 初始化GPIO.

springboot配置ssl

这里以阿里云的ssl为例:(其他云的操作基本大同小异) 第一步:在控制台中,找到SSL证书 第二步,找到SSL证书中的,免费证书 第三步,点击证书的下载 第四步,下载tomcat的证书,因为springboot是建立与tomcat服务器的 第五步,下载成功后,会有两个文件,一个是配置文件,一个配置文件的密码 第六步,将配置文件(即以.pfx结尾文件)添加到spring boot的resource当中 第七步,在application.yml配置ssl,key-store就是pfx文件的路径,注意在前面添加一个classpath。key-store-password就是下载中的pfx-password.txt文件中的一串密码。服务器类型一般都是PKCS12 第八步,在对应的服务器启动jar包,就可以进行https访问了。

Vue使用高德地图搜索功能

下载依赖 yarn add @amap/amap-jsapi-loader 2、初始化高德地图 设置key和秘钥 <template> <div class="page-box"> <el-input id="mapInput" type="text" value="请输入关键字:(选定后搜索)" onfocus='this.value=""' placeholder="请输入活动地址" /> <!-- 百度地图 --> <div id="bai-du-map"> <!-- 技术支持和联系方式 --> </div> </div> </template> <script> import AMapLoader from "@amap/amap-jsapi-loader"; // 设置安全密钥 window._AMapSecurityConfig = { securityJsCode: '01749f31f7a3a451c2e1xxxxxxx', } export default { data() { return { map: null, mouseTool: null, overlays: [], auto: null, placeSearch: null, }; }, created() { this.initMap() }, methods: { initMap() { AMapLoader.load({ "key": "

高级信息系统项目管理师(高项)高分通过经验分享

本人考了2次高级信息系统项目管理师(以下简称高项),第一次论文准备不充分挂了论文,第二次着重对论文进行准备,然后顺利通过。 根据我备考的经验,这里跟大家分享一点顺利通过的心得 。 1.上午的综合知识题 有人说上午的综合知识题是最难的,因为它考察的知识点比较多,比较杂,但我认为上午的综合知识题其实是最简单的,因为上午的题考察的知识基本就是死记硬背的,虽然涉及面广,但是只要看点看书和坚持刷题,基本都能通过。你们也可以看到上午的题,总分75,我才错了7题,而这7题,都是之前没有看到过的知识,做题也没有类似的题,而看到过的知识点都对了。 因此,对于上午的综合知识题,我总结如下几点经验: (1)五大过程组,十大知识领域,输入输出工具这些知识点必背 (2)有时间的过一下课本,时间不是很多的,把每章的主要知识点过一下,有条件的把每章的知识点记下来,方便考前复习。 (3)每天抽时间刷题,下载信管网app,做里面的每日一练,做错的题涉及的知识点要去学习巩固,隔一段事件做下错题。 能做到以上几点的话,高分跑不了。当然,作为工作党,平时并不是有那么多的时间来看书背知识点,那么,个人认为时间不充分的情况下把握两点也能轻松通过,一点是在信管网APP上刷题,在刷题中记忆知识点,另一点就是五大过程组,十大知识领域,输入输出工具这些知识点必背。 2.下午的案例题 大家可能也听过“得计算题者,得天下” 这句话,如果下午的案例题,你能把计算题都答对,那你下午的案例题要通过也基本就是板上钉钉的事情了。然而,作为过来人,想把计算题都算对,没有那么容易,根据过往的计算题来看,总有一些坑等着我们这些考生跳下去,尤其是在下午的时间比较紧张的情况下,稍有不慎,就容易看错或者理解错,所以说计算题要拿满分是很难的。因此我的经验是: (1)计算题,该拿的分,简单的计算要保证不出错,难的计算一般一两个小题,也不多,时间不够的情况下,可放弃,放弃不表示是空在那里,写对公式也有分,但前提是我说的容易的题你得全对。 (2)案例分析题,多做历年真题,很多都是有套路的,存在的问题和解决方法,一时半会不会的,可以从考察的知识领域的几个过程组中找找,比如考察的是质量管理,那么你可以从制定质量管理计划,实施质量保证和控制质量等几个方面找存在的问题或提出解决方法 (3)案例分析题尽量多写,多写不扣分,写要点,尽量用专业化的词语来解答,不要口语化的字词。 3.高项论文 大家都有一致的感触,那就是高项中的论文是最难的一科,通过率往往就是在这个地方卡的。很多人基本都是前两门过了,结果最后一门论文老是通过不了。高项论文这几年,虽然有疫情这个大环境在,但总体还是越来越难了,考过的人都知道,高项的论文已经从2选1,变成了只有一个题目,其次,论文的子要求也是考察的越来越细了,比如进度管理考察甘特图的画法,范围管理考察5层rbs的分解法,质量管理考察核查表的制定,而这些具体的要求在书本上往往是没有具体的例子的,所以高项的论文是越来越难了。 当然,虽然高项的论文难,但是每年的通过率基本都相差不多,因此只要掌握几个要点,通过也不在话下,根据我这两次考试,我总结以下几条经验: (1)提前准备论文,至少一个月,临场发挥很难,时间不够 (2)选择一个可信的项目背景,有做过实际项目的就那做过的项目当背景,没做过项目的去招投标网上找找,选好项目背景后,对项目提出背景,项目的内容,使用到的技术,项目建成后的效果进行打磨,可以多看看网上的范文,但要切记,不要抄,大家都抄,很容易雷同。看别人的范文,看的是结构和措辞方式等,千万别抄。 (3)正文部分无非就是写每个过程组中干了些什么事,用了什么工具,达到了什么效果,注意这里尽量别用书上的原话,重复率太高,用自己的话来写,比如项目章程是正式批准项目的文件,可以换成项目章程被批准后,我们的这个项目也就正式启动了。也就是尽量用自己理解的话来写,不然会被认为是背书。这里同样要注意,可以多看看别人的范文,但是别抄,别雷同。实在不知道怎么写,这里建议多看看书,每个过程组干什么事情,用什么工具,书上都有,你的内容围绕这些内容来写就可以了。 (4)在正文中要呼应论文的子要求,不管会不会,尽量扯上一点 (5)结尾要有经验总结和做的不足之处的分析,经验总结尽量不要抄书上的话,用自己的话写2点经验,一两点不足 (6)近几年没考的题目尽量都准备一篇 总的来说,高项论文把握的原则是:提前准备,尽量用自己的话写,不雷同。 有条件的可以多看看过了朋友的论文是怎么写,对比自己写的,进行修改和调整。比如我在考前就准备了很多篇,用的同一个项目背景。 由于有些同学需要高项的论文范文,而网上大部分的范文都存在雷同的问题。因此,我这里依据我软考通过的实际项目背景,结合我之前准备的几篇原创高项论文,整理成了一个专栏,欢迎有需要的同学去查看。 专栏地址:https://blog.csdn.net/c1007857613/category_12205280.html

Qt开发-用于表格QTableView的模型

如果想使用表格来呈现数据,Qt提供了一个方便的部件QTableWidget,但是直接用它实现一些功能可能比较困难。这里将介绍一种强大、灵活的方式来操作表格。 一、模型/视图架构 在这个架构中,模型用于存储数据,视图用于呈现数据,除此之外,还有一个称为委托的部分,委托显示视图中的每一项,并为可编辑的项提供合适的编辑器。 三者的关系如下图所示—— 这篇博客只介绍模型/视图的部分,接下来用一个简单的例子来说明如何使用。 二、要实现的功能 以网易云音乐为例,它的部分搜索界面是这样的: 现在,我们依照网易云音乐做一个下面的窗口,并实现额外的一些功能。 要实现的功能: 1.网上搜索:从网上搜索歌曲的数据并呈现在左边的表格中; 2.本地搜索并选中:在左边的表格中进行搜索,选中与关键字相匹配的行; 3.本地搜索并过滤:在左边的表格中进行搜索,只显示与关键字相匹配的行,过滤隐藏不匹配的行。 三、联网搜索 1.准备工作 左边的表格使用 QTableView 。 为了存储数据,需要使用合适的模型,在这里我们使用 QStandardItemModel 。 同时为了实现过滤,需要另一个代理模型 QSortFilterProxyModel 。 //数据模型 class MusicInfoModel : public QStandardItemModel { public: void loadData(const QString &strKeyword);//用于加载网上搜索得到的数据 } //主窗口 class MainWidget : public QWidget { private slots: void searchOnlineSlot(); //网上搜索 void searchAndSelcLocalSlot(); //本地搜索并选择 void searchAndFilterLocalSlot(); //本地搜索并过滤 private: MusicInfoModel *m_pInfoModel; //数据模型 QSortFilterProxyModel *m_pFilterModel; //过滤代理模型 } 以上只列出重要的成员变量和成员函数。 为了方便加载数据,我们将QStandardItemModel子类化,在子类中声明一个加载数据的函数 loadData 。 在主窗口的构造函数中初始化视图和模型—— m_pInfoModel = new MusicInfoModel(this); m_pFilterModel = new QSortFilterProxyModel(this); m_pFilterModel->setSourceModel(m_pInfoModel); ui.

深度学习环境配置指南/YOLOv8目标检测实践

深度学习环境配置指南以YOLOV8 为例 简介软件准备部分安装难点了解yolov8准备yolov8运行的环境跑一个例程运行一个例程 Load a model 简介 实验室来了很多新同学,本来更新在实验室的,但是还是想在个人区存个档,详细介绍了win深度学习环境的搭建和YOLO模型的简单实践 软件准备 环境配置前,不需要自行安装python。 Annocada 包管理器,一款优秀的软件包管理器。地址 nvidia geforce exerience 用于更新显卡驱动,保证最新的显卡驱动可以有效驱动显卡算力。 编译器 pycharm/vscode pycharm 下载地址 申请学生优惠地址,需准备校园邮箱。 CUDA (Compute Unified Device Architecture),显卡厂商NVidia推出的运算平台。 CUDA是一种由NVIDIA推出的通用并行计算架构,该架构使GPU能够解决复杂的计算问题。 它包含了CUDA指令集架构(ISA)以及GPU内部的并行计算引擎高性能GPU计算包 下载地址 在WIN+R中输入CMD ,在CMD键入NVIDIA-smi右上角查看最高支持的CUDA模块版本号 cudnn NVIDIACUDA®深度神经网络库是GPU加速的用于深度神经网络的原语库。cuDNN为标准例程提供了高度优化的实现,例如向前和向后卷积,池化,规范化和激活层。cuDNN可以极大加速深度学习的运算速度。 下载地址 需要注册,与nvidia geforce exerience 可共享,需注意版本对应 部分安装难点 Annocada 包管理器安装 参考教程 安装过程选择just me ,并将path加入环境,用for all 可能会无法添加path 将conda安装至C盘以外的盘,因为后续有许多包,所以会占用大量空间 CUDA安装 ● 点击下载好的安装包,选择解压位置,默认安装完成/失败后会销毁解压文件,等待解压结束进入安装页面 ● 此处建议使用简洁安装,会安装在默认的C盘中,当然也可以自定义安装位置,不过需要在系统环境中配置 ● 打钩即可,点击next ● 进行安装 ● 安装完成 完成CUDA驱动安装,我的默认目录如下C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.4 cuDNN安装 解压安装包,直接复制该文件夹下的三个文件夹,至CUDA安装目录下默认为C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.

mysql中 show index from tablename后每列的含义

数据表已存在索引查看SQL: show index from table_name; 查询结构如下图: 字段对应的含义: 1.Table 表的名称。 2.Non_unique 如果索引不能包括重复词,则为0。如果可以,则为1。 3.Key_name 索引的名称。 4.Seq_in_index 索引中的列序列号,从1开始。 5.Column_name 列名称。 6.Collation 列以什么方式存储在索引中。在MySQL中,有值‘A’(升序)或NULL(无分类)。 7.Cardinality 索引中唯一值的数目的估计值。通过运行ANALYZE TABLE或myisamchk -a可以更新。基数根据被存储为整数的统计数据来计数,所以即使对于小型表,该值也没有必要是精确的。基数越大,当进行联合时,MySQL使用该索引的机会就越大 8.Sub_part 如果列只是被部分地编入索引,则为被编入索引的字符的数目。如果整列被编入索引,则为NULL。 9.Packed 指示关键字如何被压缩。如果没有被压缩,则为NULL。 10.Null 如果列含有NULL,则含有YES。如果没有,则该列含有NO。 11.Index_type 用过的索引方法(BTREE, FULLTEXT, HASH, RTREE)。 12.Comment 多种评注。

Docker学习(十二)docker-compose构建

目录 1.简介2.安装3.使用方法4.常用命令 1.简介 docker-compose: Compose可译为组合物,docker-compose 适用于定义和运行多个Docker容器的工具。通过docker-compose,你可以使用YAML文件来配置应用程序需要的所有服务,然后通过使用一个命令,就可以创建并启动所有服务。 docker-compose 将所管理的容器分为三层,分别是 工程(project),服务(service)以及容器(container)。 2.安装 官方安装文档:https://docs.docker.com/compose/install/ # 下载 sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose # 增加执行权限 sudo chmod +x /usr/local/bin/docker-compose # 查看是否安装成功 docker-compose --version 3.使用方法 目录分布 |- docker |- ---- docker-compose.yml |- ---- eureka-server |- ---- ---- eureka-server.jar |- ---- ---- Dockerfile |- ---- any-gateway |- ---- ---- any-gateway.jar |- ---- ---- Dockerfile Dockerfile: FROM openjdk:8-jdk-alpine VOLUME /tmp ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.

MongoDB在java代码中的增删改查

一、配置文件 pom文件中加入依赖即可在java代码中使用 <dependency> <groupId>com.inphase.mjai</groupId> <artifactId>mjai-common-ctgcache</artifactId> </dependency> 在yml文件中加入连接数据的配置文件 spring: data: mongodb: uri: mongodb:连接路径 database: 数据库名 二、启动项目配置 在启动类上,加入两个注解,通过springBoot启动起来的时候就可以加载MongoDB @ComponentScan(basePackages = {"包路径"}) @SpringBootApplication(scanBasePackages = "包路径", exclude = {DruidDataSourceAutoConfigure.class}) 三、项目中的应用 在代码中创建集合 先判断数据库中是否存在该集合,不存在则可以按照自己的命名规则来创建集合 判断名字为tableName的集合是否存在,存在则返回true。 mongoTemplate.collectionExists(tableName) 如果不存在则创建集合 mongoTemplate.createCollection(tableName); 往集合中放入数据 先获取集合对象 MongoCollection<Document> table = mongoTemplate.getCollection(tableName); 再组装参数,两种组装方式 1.麻烦的组装方式但简单 Document document = new Document(); document.put("字段1","值1"); document.put("字段2","值2"); 2.简单的组装方式,用映射的方式将对象中的所有值都放入document中,其中faceSec就为需要存储的对象。 Document document = new Document(); Field[] fields = faceSec.getClass().getDeclaredFields(); for(Field field : fields){ field.setAccessible(true); document.put(field.getName(), field.get(faceSec)); } 将数据放入集合中去 table.insertOne(doc); 分页查询、条件查询并按照规则排序 1.条件查询 先创建一个query,并且加入一个条件

完美解决SpringMVC中org.springframework.web.servlet.DispatcherServlet.noHandlerFound No mapping 404错误

错误原因描述 出现该错误的原因主要是无法扫描注册@Controller注解的类的实例进入IOC容器而导致的,从而从一下几个方面来分析 MVC配置文件中:component-scan 标签扫描包路径是否正确,且是否误写了排除@Controller注解Controller类头部声明注解是否是:org.springframework.stereotype.Controller包内容自动声明MVC中常用注解使用<mvc:annotation-driven />标签而不是<mvc:annotation-config /> 以上问题分析完成后再进行测试如果还是出现404排查以下问题 此时可能问题并不是扫描的问题,而是@RequestMapping路径问题,检查路径是否正确 综合以上问题描述,问题应该能够得到结局,如果还是出现无法映射,则查看web.xml配置文件中springmvc配置文件加载以及前端控制器加载时机是否合理 <!-- 配置前端控制器 --> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 当前端控制器加载时要加载springMVC配置文件 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring.xml</param-value> </init-param> <!-- 让前端控制器Servlet在项目启动加载阶段就进行实例 --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> 感谢各位看官,如果喜欢的话点赞给我多多支持,我会一直出Java全栈开发课程内容,蟹蟹大家~磕头

浅谈面向过程和面向对象的区别

面向过程和面向对象都是对软件分析、设计和开发的一种思想,它指导着人们以不同的方式去分析、设计和开发软件。 伴随着每个开发人员的职业生涯,或多或少都会接触到这两种软件设计思想。不仅是软件开发人员,其实这两种思想在我们平时的生活中也处处可见,下面我将一步一步的来揭开面向过程和面向对象的神秘面纱。 一、基本概念 1、面向过程(Procedure Oriented) 是一种以过程为中心的编程思想。“面向过程” 也可称之为 “面向记录” 编程思想。简而言之,面向过程强调流程化,线性化,步骤化的思考方式。 2、面向对象 (Object Oriented,OO) 是软件开发方法和编程思想。首先强调整体性和差异性,即可将任何事物看做一个有机统一的整体来研究,然后通过派生的方式实现差异性来降低高耦合的可能性;其次强调行为的多样性和多态性,然后后强调高度可扩展性,由此也因说明了面向对象的四个基本特征,抽象,封装,继承,多态。 二、面向过程和面向对象的区别 1、面向过程的优缺点 效率高, 面向过程强调代码的胆小精悍,善于结合数据结构来开发高效率的程序。 流程明确,具体步骤清楚,便于节点分析。 缺点是:需要深入的思考,耗费精力,代码重用性低,扩展能力差,维护起来难度比较高,对复杂业务来说,面向对象的模块话难度较高,耦合度也比较高。 2、面向对象的优缺点 结构清晰,程序便于模块化,结构化,抽象化,更加符合人类的思维方式; 封装性,将事务高度抽象,从而便于流程中的行为分析,也便于操作和自省; 容易扩展,代码重用率高,可继承,可覆盖; 实现简单,可有效地减少程序的维护工作量,软件开发效率高。 面向对象的缺点:效率低,面向对象在面向过程的基础上高度抽象,从而和代码底层的直接交互非常少机会,从而不适合底层开发和游戏甚至多媒体开发;复杂性,对于事务开发而言,事务本身是面向过程的,过度的封装导致事务本身的复杂性提高。 面向对象三大特征:封装、继承、多态。 封装:封装是一种把代码和代码所操作的数据捆绑在一起,使这两者不受外界干扰和误用的机制。封装可被理解为一种用作保护的包装器,以防止代码和数据被包装器外部所定义的其它代码任意访问。 继承:继承是指一个对象从另一个对象中获得属性和方法的过程。它支持按层次分类的概念,如果不使用层次的概念,每个对象需要明确定义各自的全部特征,通过层次分类方式,一个对象只需要在它的类中定义使它成为唯一的各个属性和方法。 多态:多态是指同一个实体同时具有多种形式。同一操作作用于不用的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的引用,来调用实现派生类中的方法。 三、实例分析 这里就拿大家熟知的如何把大象放进冰箱里的案例来分析面向对象和面向过程这两种思想。 答案大家早已耳熟能详:第一步,打开冰箱门;第二步,把大象装进去;第三步,关上冰箱门。 这就是一个典型的面向过程的思想。虽然看上去有点不可思议,但是回答的又是那么的无懈可击。 如果用面向对象的思想来分析这个问题,又会怎么样呢?请看下图: 这个需求里一共出现了三个对象:人、大象、冰箱 定义好上面三个对象的属性和方法之后,我们只需要分别调用对象完成需求即可。 小结: 通过上面的分析我们会发现:面向过程适合于一个人的小量工作,而面向对象更侧重于团队合作,需要很多人完成的大量工作。面向过程思想是我们每一个人天生具备的。在编程时,我们总会不自觉的去考虑怎么来完成某一需求,分析出具体的步骤,然后按照步骤来一步步实现。但是在现实生活当中,并不是每一件事都可以自己独立来完成,我们需要团队,需要合作才可以完成某一项复杂的工作。这样来看的话,面向对象思想似乎更符合人们的做事方式,也更生活化。是的呢,不管是生活中,亦或是编程中,面向对象才是我们更应该具备的一种思想

【redis篇】超详细的redis安装教程,学不会你找我

目录 😃第一:下载安装包 😃第二:上传到服务器并解压 😃第三:安装编译所需依赖 🙋升级GCC 😃第四:开始预编译 😃第五:安装 第六步:启动 🙋方式一:直接启动 🙋方式二:守护进程启动 🙋方式三:开机自启动 😃第一:下载安装包 安装包下载地址:Download | Redis 一般下载稳定版本(Stable),截至目前最新版是7.0。 我这里使用的是6.2.10版本,或者也可以的采用远程下载,命令如下所示: wget -P /usr/local/src/ https://download.redis.io/releases/redis-6.2.10.tar.gz 😃第二:上传到服务器并解压 tar -zxvf redis-6.2.10.tar.gz 😃第三:安装编译所需依赖 由于redis是使用的C语言开发的,所以编译环境需要用到GCC yum install gcc c++ autoconf automake 🙋升级GCC 之所以升级GCC是因为我们使用的是redis-6.x,要求C5.3以上的编译器,否则会遇到大量的错误,而yum安装的GCC默认是4.8.5版本的,显然不符合redis-6.x编译的要求,所以需要进行升级。 # 安装 SCL 源 yum install -y centos-release-scl scl-utils-build # 安装 9 版本的 gcc、gcc-c++、gdb 工具链(toolchian) yum install -y devtoolset-9-toolchain # 临时覆盖系统原有的 gcc 引用 scl enable devtoolset-9 bash 💁SCL源:SCL是Software Collention的缩写,由CentOS特别兴趣小组所维护,其收录了大量程序的最新版本,包括gcc、python、git、PHP等,所以升级GCC之前先安装SCL源。 升级完成之后可通过命令 gcc -v查看最新的GCC版本 😃第四:开始预编译 先切换到解压目录,命令如下所示:

数据结构(1)——数据结构定义

一、逻辑结构:集合结构、线性结构、树形结构、图(网)状结构 (1)线性结构:数据元素之间是一对一的关系。除了第一个元素,所有元素都有唯一前驱;除了最后一个元素,所有元素都有唯一后继。 (2)树形结构:数据元素是一对多的关系。 (3)图(网)状结构:数据元素时多对多的关系。 二、物理结构(存储结构):顺序存储、链式存储、索引存储、散列存储 (1)顺序存储:把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间的关系由存储单元的领接关系来体现。 (2)链式存储:逻辑上相邻的元素在物理位置上可以不相邻,借助指示元素存储地址的指针来表示元素之间的逻辑关系。 (3)索引存储:在存储元素信息的同时,还建立附加的索引表。索引表中的每项称为索引项,索引项的一般形式是(关键字,地址)。 (4)散列存储:根据元素的关键字直接计算出该元素的存储地址,又称哈希(Hash)存储。 >>若采用顺序存储,则各个数据元素在物理上必须是连续的; 若采用非顺序存储,则各个数据元素在物理上可以是离散的; >>数据的存储结构会影响存储空间分配的方便程度; 数据的存储结构会影响对数据运算的速度; >>运算的定义是针对逻辑结构的,指出运算的功能; 运算的实现是针对存储结构的,指出运算的具体操作步骤; 二、数据类型、抽象数据类型 (1)数据类型是一个值的集合和定义在此集合上的一组操作的总称。 >原子类型。其值不可再分的数据类型。 >结构类型。其值可以再分解成若干成分的数据类型。 (2)抽象数据类型(Abstract Data Type ,ADT):是抽象数据组织及与之相关的操作。 定义一个ADT就是在“定义”一种数据结构;确定了ADT的存储结构,才能“实现”这种数据结构。 三、算法 算法是对特定问题求解步骤的一种描述,它是指令的有限序列,其中的每条指令表示一个或多个操作。 1、算法的特性 (1)有穷性。一个算法必须总在执行有穷步之后结束,且每一步都可在有穷时间内完成。算法必须是有穷的,而程序可以是无穷的。(用有限步骤解决某个特定的问题)。 (2)确定性。算法中每条指令必须有确切的含义,对于相同输入只能得出相同的输出。 (3)可行性。算法中描述的操作都可以通过已经实现的基本运算执行有限次来实现。 输入。一个算法有零个或多个输入,这些输入取自于某个特定的对象的集合。 输出。一个算法有一个或多个输出,这些输出是与输入有着某种特定关系的量。 2、“好”算法的特质 (1)正确性。算法应能够正确地解决求解问题。 (2)可读性。算法应具有良好的可读性,以帮助人们理解。 (3)健壮性。输入非法数据时,算法能适当地做出反应或进行处理,而不会产生莫名其妙的输出。 (4)高效率与低存储量需求。(高效率指花的时间少,时间复杂度低;低存储量需求指不费内存,空间复杂度低) 四、时间复杂度和空间复杂度 (1)时间复杂度 事前预估算法时间开销T(n)与问题规模n的关系(T表示“time”) >>大O表示“同阶”,同等数量级。即:当n->∞时,二者之比为常数;可以只考虑高阶的部分; 例:T1(n)=3n+3=O(n);T2(n)=n^2+3n+1000=O(n^2);T3(n)=n^3+n^2+9999999=O(n^3); ①顺序执行的代码只会影响常数项,可以忽略; ②只需挑循环中的一个基本操作分析它的执行次数与n的关系即可; ③如果有多层嵌套循环,只需关注最深层循环循环了几次。 例: void f(int n){ int i=1; while(i<=n){ i=i*2; printf("Hello World! %d\n",i); } printf("Good!!! %d\n",n); } 例: int a[n]={1..n}; f(a,n); void f(int a[],int n){ printf("AAAAAAAA\n"); for(int i=0;i<n;i++){ if(a[i]==n){ printf("

【FFMPEG】Filtering Introduction[翻译/举例]

Filtering Introduction Filtering in FFmpeg is enabled through the libavfilter library. FFmpeg中的Filtering可以通过libavfilter library来使用。 In libavfilter, a filter can have multiple inputs and multiple outputs. To illustrate the sorts of things that are possible, we consider the following filtergraph. 在libavfilter中,一个filter可以有多个输入和多个输出。为了说明这些事情可实现的可能,我们看下下面这幅图 [main] input --> split ---------------------> overlay --> output | ^ |[tmp] [flip]| +-----> crop --> vflip -------+ This filtergraph splits the input stream in two streams, then sends one stream through the crop filter and the vflip filter, before merging it back with the other stream by overlaying it on top.

C语言用链表计算学生结构体的成绩平均分

#include <stdio.h> #include <stdlib.h> #define N 8 struct slist { double s; struct slist *next; }; typedef struct slist STREC; double fun( STREC *h ) { STREC *p; double sum=0; p=h; while(p!=NULL) { sum+=p->s;p=p->next; } return sum/N; } STREC * creat( double *s) //创建带头结点的单链表 { STREC *h,*p,*q; int i=0; h=p=(STREC*)malloc(sizeof(STREC)); p->s=0; while(i<N) { q=(STREC*)malloc(sizeof(STREC)); q->s=s[i]; i++; p->next=q; p=q; } p->next=0; return h; } outlist( STREC *h) //输出链表 { STREC *p; p=h->next; printf("

mysql按30分钟进行分组

数据库 DB 数据: warning_info 是对应的DB表,create_date 是字段 SELECT time30, COUNT(*) AS num FROM (select DATE_FORMAT(time, '%Y-%m-%d %H:%i') as time30 from (SELECT DATE_FORMAT( concat(date(create_date), ' ', HOUR(create_date), ':', floor(MINUTE(create_date) / 30) * 30), '%Y-%m-%d %H:%i') AS time FROM warning_info) a) as b GROUP BY time30 order by time30; 结果:time30 表示从这个时刻往前30分钟。第一条数据即:5:00 ~5:30 分 转载自:https://www.cnblogs.com/wjx-blog/p/10119575.html

免费html5 css3大学生网页设计期末作业 网页制作作业成品

html5 css3大学生网页设计期末作业 网页制作作业成品 布局技术:html5 css3 页面个数:6个 网页元素:图文 超链接 表单 效果图: 目录如下: <!DOCTYPE html> <html lang="en"> <head> <title>Home</title> <meta charset="utf-8"> <meta name="description" content="Your description"> <meta name="keywords" content="Your keywords"> <meta name="author" content="Your name"> <link rel="stylesheet" href="css/style.css"> <script src="js/jquery-1.7.1.min.js"></script> <script src="js/superfish.js"></script> <script src="js/jquery.easing.1.3.js"></script> <script src="js/tms-0.4.1.js"></script> <script src="js/slider.js"></script> <!--[if lt IE 8]> <div style=' clear: both; text-align:center; position: relative;'> <a href="http://windows.microsoft.com/en-US/internet-explorer/products/ie/home?ocid=ie6_countdown_bannercode"> <img src="http://storage.ie6countdown.com/assets/100/images/banners/warning_bar_0000_us.jpg" border="0" height="42" width="820" alt="You are using an outdated browser. For a faster, safer browsing experience, upgrade for free today.

[C语言]中,为什么整型数据以浮点型输出(或浮点数类型的数据以整型输出),其输出的结果与我们预期的大相径庭?这篇博客,带你拨开云雾见月明。

在我们学习C语言的过程中,可能会出现这样的情况:我们定义了一个整型数据,想以浮点型输出,结果却不是我们预想的那样。比如: #include<stdio.h> int main() { int a = 7; float* pFloat = (float*)&a; printf("a的值为:%d\n", a); printf("*pFloat的值为:%f\n", *pFloat); *pFloat = 7.0; printf("a的值为:%d\n", a); printf("*pFloat的值为:%f\n", *pFloat); return 0; } 我们预想的结果应该是 :7 7.000000 7 7.000000 但是天不遂人愿,程序输出的结果如下: 这样的输出结果,肯定是有原因的。我们可以设想:有没有可能,是因为int和float的存储方式不同呢? 答案确实是这样。 根据国际标准IEEE(电气和电子工程协会)754,任意一个二进制浮点数V可以表示成以下形式: (-1)^S * M * 2^E (-1)^S 表示符号位,当S=0,V为正数;当S=1,V为负数。 M表示有效数字,大于等于1,小于2 2^E表示指数位 现在我们就来仔细研究一下这个式子((-1)^S * M * 2^E)到底是什么意思。 在看完以上这个例子之后,相信你对浮点数的表示已经有了一定的理解。 那么,理解了浮点数的表示形式之后,它又是怎么存储的呢? IEEE 754规定: 对于32位的浮点数,最高的1位是符号位S,接着的8位是指数E,剩下的23位为有效数字M。 对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。 我们这里主要讨论单精度浮点数。对于双精度浮点数来说,原理相同。 IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的小数部分。比如保存1.01的时候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位浮点数为例,留给M只有23位,将第一位的1舍去以后,等于可以保存24位有效数字。 至于指数E,情况就比较复杂。 首先,E为一个无符号整数(unsigned int)。 这意味着,如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0~2047。但是,我们知道,科学计数法中的E是可以出现负数的,所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数是127;对于11位的E,这个中间数是1023。比如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即10001001。 对于E来说, E不全为0或不全为1 这时,浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将 有效数字M前加上第一位的1。 比如:

软件测试/测试开发 | 黑盒测试方法论—等价类

公众号搜索:TestingStudio 霍格沃兹测试开发的干货都很硬核 等价类划分是一种重要的、常用的黑盒测试方法,不需要考虑程序的内部结构,只需要考虑程序的输入规格。它将不能穷举的测试过程进行合理分类,从而保证设计出来的测试用例具有完整性和代表性。 需要把用户所有可能输入的数据,划分成若干份(若干个子集),然后从每一个子集当中选取少数具有代表性的数据作为测试用例,这种方法被称为——等价类划分法。 在有限的测试资源的情况下,用少量有代表性的数据得到比较好的测试效果。 等价类划分 等价类划分的基本思想就是先把可能的数据划分为不同的类别,然后再从每一类里面挑选有代表性的数据进行测试。这样挑选出来的数据,就可以代表这一类里面的全部数据。通过这种方式,测试用例的数量就可以减少。 等价类分类 从已经划分出来的这些范围当中,又可以分为两种情况: 有效等价类:指符合《需求文档》,输入合理的数据集合。无效等价类:指不符合《需求文档》,输入不合理的数据集合。 因为软件不仅要能够接收合理的数据,不合理的数据也需要做出正确响应,所以在设计测试用例时,两种等价类都需要考虑,这样的测试才能确保软件具有更高的可靠性。 所有的有效等价类和无效等价类合起来,就是整个的测试数据范围。 等价类划分原则 通常按照以下规则进行划分等价类: 如果规定输入的取值范围或个数时,则划分一个有效等价类和两个无效等价类。如:注册用户名的长度限制 6~18 个字符,6~18 个字符是有效等价类,小于 6 个字符和大于 18 个字符则是两个无效等价类。如果规定了输入的集合或规则必须要遵循的条件,则划分一个有效等价类,和一个无效等价类。如:注册用户名的格式要求必须以字母开头时,以字母开头是有效等价类,非字母开头是无效等价类。如果输入条件是一个布尔值,则划分为一个有效等价类和一个无效等价类。如:在注册用户时需要遵循协议或条款是否接受时,“接受”是有效等价类,“不接受”则是无效等价类。如果输入条件时一组数据(枚举值),并且程序对每一个输入的值做不同的处理,则化为若干个有效等价类和一个无效等价类。如:网游中充值 VIP 等级(三个等级),对每个 VIP 的等级优惠不同,VIP1、VIP2、VIP3 不同等级是三个有效等价类,不是 VIP 用户则是无效等价类。如果输入条件规定了必须要遵循的某些规则下,则划分为一个有效等价类和若干个无效等价类(无效等价类需要从不同的角度去违反规则)。如:密码要求首位必须是大写字母的,首字母大写时有效等价类,首位小写字母的、首位为数字的或者首位为特殊字符的则是无效等价类。不是所有的等价类都有无效等价类。如:性别的选择只有男或女两种。 等价类设计步骤 先划分等价类:找出所有可能的分类。确定有效等价类:需求中的条件。确定无效等价类:与条件相反的情况,再找到特殊情况(中文、英文、符号、空格、空)。从各个分类中挑选测试用例数据。 划分等价类要点:文本框要求输入的长度、输入的类型、组成规则、是否为空、是否重复—区分大小写、是否去除空格。 实例 等价类设计步骤的前3个步骤,可以通过等价类表这种方法来辅助进行分析。 例:计算 1—100 的整数之和(包括 1 和 100) 以上面的计算器来举例,这次是计算1–100中的其中两个整数之和。 创建等价类表 在确立了等价类之后,可按下表的形式列出所有划分出的等价类表。 输入条件有效等价类无效等价类1-100的整数(包括1和100)[1,100]整数<1整数>100整数小数字母汉字特殊字符 等价类表可以帮助分析如何划分等价类,是一个辅助工具,初学者可以这样写,等熟练之后可以直接快速的编写出测试用例。 设计用例的时候需要注意,应该按照以下原则来覆盖不同的等价类: 设计新的测试数据,尽可能多覆盖尚未被覆盖的有效等价类,重复这一步骤,直到将所有的有效等价类都被覆盖完为止。设计新的测试数据,只覆盖一个无效等价类,重复这一步,直到将所有的无效等价类都被覆盖完为止。 设计测试用例 先编写一个很简单的用例,只包含最关键的一些信息,比如用例编号,属于的等价类,两个输入框中的测试数据,还有预期结果。 因为这里想要得到最终结果的话涉及到了多个元素,这里就需要输入两个值。 在这种情况下,要采用控制变量法,如果是要覆盖无效等价类的话,设计测试用例的时候,当前元素覆盖无效等价类,用例中涉及到的其他元素要保持有效。 用例编号所属等价类输入框1输入框2预期结果1有效等价类3060902无效等价类-240给出错误提示3无效等价类40-2给出错误提示4无效等价类1102给出错误提示5无效等价类2110给出错误提示6无效等价类10.53给出错误提示7无效等价类110.5给出错误提示8无效等价类a5给出错误提示9无效等价类人20给出错误提示10无效等价类20人给出错误提示11无效等价类5a给出错误提示12无效等价类!5给出错误提示13无效等价类5!给出错误提示14无效等价类空格5给出错误提示15无效等价类5空格给出错误提示16无效等价类为空5给出错误提示17无效等价类5为空给出错误提示 每次一个单点无效输入让其他点有效输入排除更多不确定和干扰。 等价类总结 等价类划分法非常简单,也很容易理解,是在用例设计中使用最广泛的一种测试用例设计方法。 它的优点是考虑了单个输入域,所有可能的取值情况,避免了在设计用例时盲目或随机选取输入测试不完整或不稳定的数据。 最大的缺点就是产生的测试用例比较多,而且在设计时,可能会产生一些无效的测试用例,也没有对特殊点进行考虑,所以在设计时需要结合其他的设计方法进行补充。

修改jmeter内存配置(win&mac&linux)

目录 一、背景: 二、win环境下修改jmeter内存 三、mac&linux环境下修改jmeter内存 四、验证内存是否修改成功 一、背景: 在进行大数据、高并发压测的过程性,有时会遇上JMeter卡死现象,使得测试无法进行,查看日志显示:java.lang.OutOfMemoryError: Java heap space 原因:运行jmeter机器的内存,占用较高,超过了jmeter设置的内存上限,内存溢出。 我们需要给jmeter配置足够大的内存。 二、win环境下修改jmeter内存 1、查找jmeter安装路径 可以去环境变量配置文件查看安装位置,或者使用命令 which jmeter 2、修改/apache-jmeter-5.4.3/bin/ 目录下的 jmeter.bat文件 将jmeter.bat 中的,这一行 set HEAP=-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m HEAP 堆 -Xms:JVM初始分配的堆内存。表示初始化JAVA堆的大小及该进程刚创建出来的时候,他的专属JAVA堆的大小,一旦对象容量超过了JAVA堆的初始容量,JAVA堆将会自动扩容到-Xmx大小。 -Xmx:JVM最大允许分配的堆内存,按需分配。表示java堆可以扩展到的最大值,在很多情况下,通常将-Xms和-Xmx设置成一样的,因为当堆不够用而发生扩容时,会发生内存抖动影响程序运行时的稳定性。 这里我们将 -Xms -Xmx设置成 1个g MaxMetaspaceSize:jvm中的元数据区。 一般256m就够了。 三、mac&linux环境下修改jmeter内存 1、查找jmeter安装路径 可以去环境变量配置文件查看安装位置,或者使用命令 which jmeter 2、修改/apache-jmeter-5.4.3/bin/ 目录下的 jmeter文件 HEAP 堆: -Xms:JVM初始分配的堆内存。表示初始化JAVA堆的大小及该进程刚创建出来的时候,他的专属JAVA堆的大小,一旦对象容量超过了JAVA堆的初始容量,JAVA堆将会自动扩容到-Xmx大小。 -Xmx:JVM最大允许分配的堆内存,按需分配。表示java堆可以扩展到的最大值,在很多情况下,通常将-Xms和-Xmx设置成一样的,因为当堆不够用而发生扩容时,会发生内存抖动影响程序运行时的稳定性。 这里我们将 -Xms -Xmx设置成 1个g。通常将-Xms和-Xmx设置成一样的 MaxMetaspaceSize:jvm中的元数据区。 一般256m就够了。 将jmeter文件(注意不是jmeter.bat文件),这一行 : "${HEAP:="-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m"}" 修改 -Xms -Xmx 四、验证内存是否修改成功 1、修改完成后重新启动jmeter 2、启动jconsole 查看jmeter的内存 win 启动 jconsole:

java多线程并发包中的executors框架(线程池)和Fork/Join框架

1. 概述 1.1 Executor 是JDK1.5时引入的,引入该接口的主要目的是解耦任务本身和任务的执行。我们之前通过线程执行一个任务时,往往需要先创建一个线程,然后调用线程的start方法来执行任务。而Executor接口解耦了任务和任务的执行,该接口只有一个方法,入参为待执行的任务 public interface Executor { /** * 执行给定的Runnable任务. * 根据Executor的实现不同, 具体执行方式也不相同. void execute(Runnable command); } 然后有几个实现类: 同步执行任务:DirectExecutor,对于传入的任务,只有执行完成后execute才会返回异步执行任务:ThreadPerTaskExecutor ,对于每个任务,执行器都会创建一个新的线程去执行任务。对任务进行排队执行: SerialExecutor,会对传入的任务进行排队(FIFO顺序),然后从队首取出一个任务执行 1.2 ExecutorService Executor接口提供的功能很简单,为了对它进行增强,出现了ExecutorService接口,ExecutorService继承了Executor,它在Executor的基础上增强了对任务的控制,同时包括对自身生命周期的管理,主要有四类: 关闭执行器,禁止任务的提交;监视执行器的状态;提供对异步任务的支持;提供对批处理任务的支持。 对于Future,Future对象提供了对任务异步执行的支持,也就是说调用线程无需等待任务执行完成,提交待执行的任务后,就会立即返回往下执行。然后,可以在需要时检查Future是否有结果了,如果任务已执行完毕,通过Future.get()方法可以获取到执行结果——Future.get()是阻塞方法。 1.3 ScheduledExecutorService ScheduledExecutorService提供了一系列schedule方法,可以在给定的延迟后执行提交的任务,或者每个指定的周期执行一次提交的任务,该接口继承了ExecutorService 2. 实现类ThreadPoolExecutor 2.1 线程池作用 ThreadPoolExecutor是用来创建线程池的Executor,线程池概念与数据库连接池类似。 当有任务需要执行时,线程池会给该任务分配线程,如果当前没有可用线程,一般会将任务放进一个队列中,当有线程可用时,再从队列中取出任务并执行 线程池的引入,主要解决以下问题: 减少系统因为频繁创建和销毁线程所带来的开销;自动管理线程,对使用方透明,使其可以专注于任务的构建。 Executors工厂可以创建不同类型的线程池,其中有以下几个参数: maximumPoolSize限定了整个线程池的大小,corePoolSize限定了核心线程池的大小,corePoolSize≤maximumPoolSize(当相等时表示为固定线程池);maximumPoolSize-corePoolSize表示非核心线程池。 2.2 线程池状态 ThreadPoolExecutor一共定义了5种线程池状态 RUNNING : 接受新任务, 且处理已经进入阻塞队列的任务SHUTDOWN : 不接受新任务, 但处理已经进入阻塞队列的任务STOP : 不接受新任务, 且不处理已经进入阻塞队列的任务, 同时中断正在运行的任务TIDYING : 所有任务都已终止, 工作线程数为0, 线程转化为TIDYING状态并准备调用terminated方法TERMINATED : terminated方法已经执行完成 各个状态之间的流转图: 2.3 Worker工作线程 概要说明: 当我们向 ThreadPoolExecutor 提交任务时,会发生以下几件事: 1. 判断如果当前线程池中的工作线程数还没有达到 corePoolSize 的值,则调用addWorker方法

软件架构设计分层模型和构图思考(有史以来最全架构图)

架构思维概述 对于架构思维本身仍然是类似系统思维,结构化思维,编程思维等诸多思维模式的一个合集。由于架构的核心作用是在业务现实世界和抽象的IT实现之间建立起一道桥梁,因此架构思维最核心的就是要理解到业务驱动技术,技术为最终的业务服务。要真正通过架构设计来完成业务和技术,需求和实现,软件和硬件,静态和动态,成本和收益等多方面的平衡。 在前面多篇文章已经提出,架构设计中有两个重点,一个是分解,一个是集成。 分解是最基础的,架构的重点就是要对复杂问题进行分而治之,同时保证分解后的各个部分还能够高内聚,松耦合,最终又集成为一个完整的整体。分解核心是定义问题,因此架构首先仍然需要理解清楚需求。 集成是配合分解完成的动作,最终分解完成的各个组件或子系统,通过合适的接口设计,最终还能够集成为一个完整的整体,分解仅仅是加速开发和降低问题复杂度,如果分解后的内容无法集成在一起,那么分解就没有任何意义。 分解+集成可以理解为架构最核心的思考方式和方法。 在分解完成后,一个大的系统已经拆分为了诸多的小模块,或者一个小模块实现本身又分为了多个步骤阶段。那么零散的节点必须向上汇集和归纳,形成一个完整的架构。 而这个架构的形成要给关键就是要又分层思维。架构分层是谈架构绝对绕不开的一个点,通过架构分层可以更好地全面理解业务系统或功能实现。 云平台三层架构:资源-平台-应用 在规划大架构的时候,常会参考云计算的标准三层架构,即IaaS层,PaaS层,SaaS层。对于IaaS层重点是IT基础设施和虚拟化;PaaS层重点是构建平台层服务能力;而对于SaaS层则是具体的应用。 对于资源层从物理资源,再到虚拟化逻辑资源,从虚拟机到现在更加轻量的容器资源。而对于平台层原来只谈技术平台,但是当前又进一步拆分出业务平台,也可以理解成当前说得比较多的中台层。 同时在平台层和应用层之间增加了服务层,实现资源和服务的解耦。 如果涉及到物联网类应用,一般还会在底层增加网络层和感知层,比如一个智慧城市标准平台和应用的架构图类似如下: 在平台+应用构建模式下,一般在平台和应用之间还会有一个单独的服务层来实现接口服务对外的能力开放。资源+服务+应用也是我们常说的SOA分层架构模式,因此对于服务层也可以单独拆分出来作为一个小分层。 问题1:数据库和数据层 在构建一个完整的总体架构的时候,实际上没有数据层这个概念,数据层是在表达单个应用系统的分层架构实现的时候才会出现的内容。 在总架构图里面把类似结构化数据库,非结构化数据等全部列出单独一层这个也不对,这个应该是在技术架构里面体现。 还有一种是单独分出一个数据层,将大的公共基础数据列出,比如上面谈的智慧城市架构图。如果这些基础数据存在共性能力朝上提供,那么可以归纳到PaaS平台层,在PaaS平台层单独分出一个数据平台域来进行体现。 问题2:服务层和服务 在构建整体架构的时候可以单独出一个能力开放平台或服务层,但是不用体现具体有哪些业务服务能力。因为单独出业务服务能力本质已经属于应用层内容,即应用又细化拆分为了业务中台和前台应用,中间衔接的服务。我们可以参考网上的另外一个构图,如下: 这个构图既不像云平台中的分层架构,也不像应用功能实现中的分层架构。实际可以看到如果体现单独的支撑层,支撑层已经类似现在经常说到的业务中台和能力提供。 那么整个架构应该为 技术平台+中台+应用 方式来进行构图。 SOA分层:组件-服务-流程 对于SOA架构分层,重点要体现的就是服务,对于组件本身是属于逻辑资源层的概念,而对于服务则是资源对外暴露的能力抽象。 SOA架构分层重点就是要体现出独立的服务层,注意不是画服务总线,这里可以单独画出具体提供哪些业务服务能力,技术服务能力。在采用SOA架构进行开发的时候,整体业务系统拆分为4个组件,10类服务域,5类流程,那么在构建的时候重点就是将上述组件,服务域和流程类体现出来。对于参考SOA架构来进行的构图,参考如下: 这里的数据层最好改为标准的组件层,更加贴近SOA架构模型。在图中的服务层已经可以看到一个个独立的API服务接口。如果服务接口数据大,一般只会划分到服务域,比如用户中心服务,采购类服务等。在这种方式下构图参考如下: 在上图中结合了云和SOA两种架构融合在一起,对于上图中的服务层实际可以理解为组件资源层和服务接口层的融合。更好的构图方式应该是拆分为标准的中台资源层-服务层-应用层。 云和SOA架构融合 注意对于云分层架构重点强调的是基础设施,平台和应用三层架构。而对于SOA架构强调的是资源,服务和应用三层。而对于对于传统的应用系统的构建一般又包括了IT基础设施,技术平台,数据库,中间件和应用。再到应用系统本身的分层架构可能又是标准的三层架构模式等。 这些架构分层方法都帮助我们进一步融合分层架构模式。 架构分层有很多方法,包括基础设施层,平台层,组件层,支撑层,服务层,应用层,数据层,展现层等。多种分发导致分层模型反而出现歧义和模糊。 在这里我们从技术架构和应用架构两个层面来谈,技术架构沿用云计算的三层模型;而对于应用架构则采用eTOM模型标准的资源,服务,应用三层模型。那么两种分层架构模型的融合则是一个完整的云和SOA融合的分层架构模型。 即云计算的三层中,每一个层次本身又可以进一步拆分为资源,服务和应用三层。 拿IaaS层来说,最底层的物理资源虚拟机等是属于资源层内容,通过IaaS层资源能力提供API接口作为技术服务进行能力开放,即是服务层;最终基于资源能力,构建了一个公有云的面向公众的运营服务平台,本身又属于应用层的内容。而对于SaaS层,则底层的业务组件是资源,抽象的API接口是服务层,最终的前端业务或流程是应用功能实现。 应用架构分层 回到单个应用的架构分层,谈得最多的就是常说的三层架构模式。在软件架构中,经典三层架构自顶向下由用户界面层(User Interface Layer)、业务逻辑层(Business Logic Layer)与数据访问层(Data Access Layer)组成。 在整个实现过程中,可能还会增加独立的Facade层,或独立的API接口服务提供层,统一的DTO数据传输对象层等,但是这些都不影响整体的三层逻辑结构。 三层架构本身也和一个业务功能实现的完整对应,在数据访问层处理数据获取和持久化操作,在业务逻辑层对业务规则进行处理,在界面展现层进行相应的前端展现和用户交互。而谈到领域建模的时候,又引入了领域模型中的分层架构,如下: 领域驱动设计在经典三层架构的基础上做了进一步改良,在用户界面层与业务逻辑层之间引入了新的一层,即应用层(Application Layer)。同时,一些层次的命名也发生了变化。将业务逻辑层更名为领域层自然是题中应有之义,而将数据访问层更名为基础设施层(Infrastructure Layer),则突破了之前数据库管理系统的限制,扩大了这个负责封装技术复杂度的基础层次的内涵。 当然,也有融合了领域模型和传统三架构思路后的技术架构如下: 领域层和业务逻辑层 在领域建模的一个核心是领域模型,领域模型不再是一个个独立的数据库表或数据对象,而是一个业务对象或领域对象。因此领域层是面向领域对象而设计实现,而业务规则能力本身也是属于领域对象对外提供的能力接口。即业务规则本身也是领域对象暴露的能力。 传统业务逻辑层实现往往是一个数据对象对应一个DAO,一个Service和一个Interface。而领域模型下DAO可以是分开的,但是Service逻辑层往往则更多应该按领域模型思路对DAO层的能力进行组装和聚合。 独立应用层拆分 在我原来理解里面,领域层提供领域模型和领域服务能力接口,而应用层更多的是对领域层多个领域对象模型提供的服务能力进一步进行组装和编排,然后再暴露给前端应用。 谈到应用层的概念,实际上可以理解为前端应用中存在的共性能力的进一步下沉。即应用本身只是用户业务功能实现的承载,但是这个功能的实现可以通过多种前端展现形式,比如传统的CS桌面应用,BS应用,或手机端APP。 在电商里面,一个商品订购就是一个独立的应用,用户可以在APP完成,也可以在BS端完成,但是不论在哪里完成最终应用层提供的能力都应该一样。比如完成一个商品订购需要同时和底层的订单,库存,支付多个服务进行交付和协同。那么这个逻辑显然不适合同时在BS端应用和APP端应用中进行重复编写和开发。那么这个内容就应该在应用层实现。 如果回到微服务和中台架构下,这个应用层拆分更加必要,即通过应用层来下沉共性的服务组合和组装逻辑,这个逻辑和协同不应该属于任何一个前端应用。 界面层还是接口层 在开发一个聚合能力的中台微服务模块的时候,可以看到这个微服务模块本身并没有界面展现层,那么该微服务的最上层仅仅是提供API接口的接口服务层。 该API接口服务能力既可以提供给APP前端,也可以提供给BS端使用。 软件技术架构分层 软件技术架构构图,分层仍然可以沿用软件三层分层模型,重点是说明清楚各层用到的关键技术组件或技术服务能力。比如软件开发三层模型的技术架构分层如下: 如果本身就是一个技术平台,类似大数据平台,那么我们在整体构图的时候仍然需要考虑先进行分层,再详细说明每层里面的技术内容。 比如对应一个大数据平台,包括了大数据采集,大数据存储,大数据处理,大数据分析和应用,那么这个就是关键的分层,可以基于这个分层再来考虑各层采用的关键技术。 对于技术栈构图基本也可以参考技术架构构图模式进行。 技术架构重点需要回答的就是你在进行软件架构设计过程中,究竟会用到哪些关键技术,哪些开源产品或工具等。可以细化到具体的技术产品,也可以仅细化到产品类型。 比如消息中间件,你可以细化到采用RabbitMQ,也可以在技术架构中只体现采用消息中间件。 技术架构和软件功能分层架构唯一相同的就是分层,技术架构在各个分层里面都没有具体的业务功能点和实现内容,仅仅是关键技术点说明。

linux基础——黑洞文件

/dev/null: dev:device 设备 null:空 文件俗称为黑洞文件,是因为任何不需要的输出内容都可以“扔”进去,在里面不会有读取和输出结果,对于shell结果的输入输出非常方便。任何的内容存放到这个文件里,都不会保存,直接删除。 /dev/null通常用来处理进程中那些不想要的输出结果,或者作为一个方便的空文件给输入。在重定向功能常常使用。 重定向: 将本来应该在屏幕上的输出,重新改变了输出的方向,往文件里输出。 重定向可以实现在linux shell帮助保存内容到文件里 > 正确的输出重定向,会覆盖原来文件里的内容 >> 追加输出重定向,不会覆盖原来文件里的内容,只会在文件的末尾追加 例如: [root@future blog]# touch abc.txt [root@future blog]# echo 1111 >abc.txt [root@future blog]# cat abc.txt 1111 [root@future blog]# echo 2222 >abc.txt [root@future blog]# cat abc.txt 2222 [root@future blog]# echo 3333 >>abc.txt [root@future blog]# cat abc.txt 2222 3333 [root@future blog]# echo 4444 >>abc.txt [root@future blog]# cat abc.txt 2222 3333 4444 [root@future blog]# 一般我们这样使用黑洞文件:&>/dev/null &表示等同于,即 XX &>/dev/null 表示 XX的输出重定向等同于放到黑洞文件。

RK3566 多Mipi屏的兼容

需求:项目需求需要同一个固件兼容两款不同IC的mipi屏。以便有一个IC停产之后使用不受影响。由于是同一个模组厂商,所以设计初就要求硬件接口一样或者兼容。 方法:一开始的想法很简单和网上以及同行提供的方法一样在uboot阶段去读屏的ID,然后再把对应屏ID放到cmdline里面去传到kernel.在kernel里面做判断屏ID,来使用不同的panel-init-sequence 和timing。这种方法也可行。把屏的ID放到cmdline的方法是我也没找到,有大佬解答一下吗? 然后询问RK,RK提供了另一种方案不依靠cmdline传参。dts中dsi节点下面添加不同的panel节点。开机uboot阶段,通过mipi dsi读取每个屏的id寄存器与dts中设置的目标寄存器值进行比较。如果不是完全一致,就会将对应的panel节点的status设置成“disabled”。 最后会留下来唯一一个是status是“okay”的panel。kernel在加载panel的时候找到这个status是okay的panel,其他的不会加载。okay我们按照这个做法来实现我们的需求。 首先对DTB做一个深入了解。要不然怎么理解在uboot阶段把dts里面的status掉呢。在系统启动过程中,由bootloader将dtb文件加载到内存,并告知linux内核dtb在内存中的首地址(中途可能会对某些节点进行创建或者修改)。内核在start_kernel中会对dtb文件进行解析,并形成对应的device_node和property结构体;至此,dtb文件便完成任务了大佬做的详细解答可点 dtb的组成 其中structure block区域描述了设备树本身的结构和内容,strings block包含了设备树中所有属性的名称。以上都是参照链接上知乎大佬arch的文章内容。那么我理解就是dtb本身就是一个二进制文件。里面包含了我们的dts的文件内容包括节点以及属性。既然都以二进制存在。而且dtb的起始地址已知。我们只要找到节点的偏移地址以及status属性就可以把okay -> disabled.欧克解决; 这个下面就开始分析代码。 首先我们要咨询屏的IC厂屏的ID在那个寄存器里面。然后编写dts。如下: &dsi0 { status = "okay"; //天钰IC 8553 panel@0 { status = "okay"; compatible = "simple-panel-dsi"; reg = <0>; backlight = <&backlight>; iovcc-gpios = <&gpio0 RK_PC7 GPIO_ACTIVE_HIGH>; //avdd-gpios = <&gpio4 RK_PC7 GPIO_ACTIVE_HIGH>; avdd-gpios = <&gpio3 RK_PC3 GPIO_ACTIVE_HIGH>; reset-gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_LOW>; init-delay-ms = <60>; reset-delay-ms = <60>; enable-delay-ms = <60>; prepare-delay-ms = <60>; unprepare-delay-ms = <60>; disable-delay-ms = <60>; dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_EOT_PACKET)>; dsi,format = <MIPI_DSI_FMT_RGB888>; dsi,lanes = <4>; num = <0>; //panel的唯一标识,必须是大于等于0的整数 id = [95]; //读取id寄存器的返回值数组,十六进制 id-reg = <0x04>; //id寄存器地址,1个字节,需要加“0x”表示十六进制, panel-read-id-sequence= [05 78 01 11 ------------- ]; panel-exit-sequence = [ 05 0A 01 28 05 78 01 10 ]; disp_timings0: display-timings { native-mode = <&dsi0_timing0>; dsi0_timing0: timing0 { clock-frequency = <160000000>; hactive = <1080>; vactive = <2340>; hfront-porch = <60>; hsync-len = <2>; hback-porch = <60>; vfront-porch = <20>; vsync-len = <2>; vback-porch = <8>; hsync-active = <0>; vsync-active = <0>; de-active = <0>; pixelclk-active = <1>; }; }; ports { #address-cells = <1>; #size-cells = <0>; port@0 { reg = <0>; panel0_in_dsi0: endpoint { remote-endpoint = <&dsi0_out_panel0>; }; }; }; }; //奇景 83112a panel@1 { status = "

Java之 类(内部类,抽象类,接口)

文章目录 一,内部类什么是内部类为什么要设计内部类内部类分类1,静态内部类2,成员内部类3,匿名内部类4,局部内部类 二,抽象类(abstract)1,定义:2,特点:3,目的3,示例 三,接口1,定义2,特点3,目的4,示例 四,面试题1,为什么使用内部类(文中有详解)2,为什么局部类访问的变量需要final修饰(文中有详解)3,抽象类和接口的不同4,静态内部类设计意图,以及与非静态内部类的不同5,静态属性,静态方法能否被继承和重写 一,内部类 什么是内部类 定义在类内部的类就被称为内部类。外部类按常规的类访问方式使用内部类,唯一的差别是内部类可以访问外部类的所有方法与属性,包括私有方法与属性。内部类是一个编译时的概念。外部类outer.java内定义了一个内部类inner,一旦编译成功,就会生成两个完全不同的.class文件,分别是outer.class和outer$inner.class。 为什么要设计内部类 内部类是为了更好的封装,把内部类封装在外部类里,不允许同包其他类访问内部类中的属性和方法即使是外部类也不能直接访问,相反内部类可以直接访问外部类的属性和方法,即使private实现多继承:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。匿名内部类用于实现回调 内部类分类 1,静态内部类 定义:定义在类内部的静态类 示例: public class Out { private static int a; private int b; public static class Inner { public void print() { System.out.println(a); } } } 解析:Inner是静态内部类。静态内部类可以访问外部类所有静态变量和方法。静态内部类和一般类一致,可以定义静态变量、方法,构造方法等。 使用: Out.Inner inner = new Out.Inner(); inner.print(); 实现原理: public class Out$Inner { public Out$Inner() { } public void print() { System.out.println(Out.access$000()); } } 原理解析: Out.java编译后会生成两个class文件,分别是Out.class和Out$Inner.class。因为这两个类处于同一个包下,所以静态内部类自然可以访问外部类的非私有成员。对外部类私有变量的访问则通过外部类的access$000()方法。 使用场景: 静态内部类与非静态内部类之间存在一个最大的区别: 非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有。 它的创建是不需要依赖于外围类, 它不能使用任何外围类的非static成员变量和方法

RK3566添加湿度传感器以及浅析hal层

RK3566添加一款温湿度传感器gxht3x.挂在i2c总线下。驱动部分就不多做解析。大致流程硬件接好i2c线以及vcc gnd。后看数据手册。初始化寄存器,然后要读数据的话读那个寄存器,读出来的数据要做一个转化,然后实现open read write ioctl函数就行了。本文主要讲解hal层 。直接贴驱动代码。 /* drivers/input/sensors/temperature/tmp_ms5607.c * * Copyright (C) 2012-2015 ROCKCHIP. * Author: luowei <lw@rock-chips.com> * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

10个最常用的 VSCode 快捷键,提升你的编码速度

我们都知道,Visual Studio Code(VS Code)是程序员非常强大的工具。通过本文,我们将学习VS Code中一些最常用的快捷键,这将帮助我们在编程或写代码时更加高效。 使用VS Code快捷键可以提高编程速度,让你在使用这个工具时看起来像是一个专家。让我们逐个看一下每个快捷键。 1、打开命令面板 如果你是初次接触 VS Code 编辑器,那么这个快捷键可能是你学习的最重要的键盘组合之一。 命令面板提供了对 VS Code 中的所有功能、快捷键、命令和配置选项的访问。 你可以使用以下键盘组合调用命令面板: Windows — Ctrl + P Mac — Command + P 2、切换注释行 传统上,你必须将光标放置在一行代码的开头,然后键入/ /(双斜杠)将其转换为注释。 VS Code 提供了一个更简单的注释代码行的方法。使用此快捷键,可以在光标所在行的任何位置切换注释行。 下面是在 Windows 和 Mac 上切换代码行的快捷键。 Windows — Ctrl + / Mac — Command + / 3、切换终端 VS Code(Visual Studio Code)内置了终端,您可以在其中运行所有命令,例如启动服务器(后端),运行应用程序(前端),更改目录(cd),安装软件包等等。 当构建复杂的 Web 应用程序时,我总是保持终端打开,因为我经常安装软件包,并且还检查终端以查看我的正在运行的进程是否崩溃。 如果您也需要更多的工作空间,可以关闭终端。 以下是在 Windows 和 Mac 上切换到终端的键盘快捷键: Windows — Ctrl + ` Mac — control + `

redisTemplate非阻塞删除批量前缀模糊匹配key

keys * 这个命令千万别在生产环境乱用。特别是数据庞大的情况下。因为Keys会引发Redis锁,并且增加Redis的CPU占用。 在生产环境中可以使用scan命令。 public void deleteRedisMd5Phone(){ //设置需要删除的key前缀 String key = "md5Phone"; try { deleteKeysByScan(key) }catch (Exception e){ log.error(e.getMessage()); } } /** * 删除指定前缀的一系列key * * @param pattern 匹配keys的规则 */ public void deleteKeysByScan(String pattern) { long start = System.currentTimeMillis(); log.info("清理redis{}key记录缓存的定时任务开始执行", pattern); String param = pattern + "*"; int count = 0; while(true){ long start1 = System.currentTimeMillis(); log.info("第{}轮Redis删除开始",count); //设置每轮搜索到10W条数据 Set<String> keys = getValuesForStringByScan(param); count++; //找不到或者最多删除6千万条 可以自己设置 if(keys.isEmpty()||count>600){ break; } redisTemplate.delete(keys); log.

虚拟机上安装 Linux 步骤详解

目录 前言 Linux安装准备 VMware Linux 创建虚拟机 安装Linux 前言 目前大数据这个职业很火,相信很多人都在考虑转行学大数据。但是需要系统的去学习才行,不要自己在那里琢磨,非常费时间。怎么去学习大数据,我想你自己会有想法的。那么问题来了,此博客就在虚拟机中安装Linux,做一个详细的步骤。 Linux安装准备 VMware 首先,需要你先在你自己的电脑上安装好VMware虚拟机,可以自己在网上下载VMware(使用版)。他的安装方法很简单,一直点击下一步就好。安装好虚拟机你就可以开始在虚拟机上安装Linux了。 Linux 然后,你还需要有Linux的镜像文件如下: 创建虚拟机 1.打开Vmware,点击“创建新的虚拟机” 2.选择自定义,下一步 3.此处默认即可(仅展示虚拟机硬件兼容性),下一步 4.选择安装客户机操作系统,这里选择稍后安装操作系统,下一步 5.选择Linux,版本:CentOS 64 位,下一步 6.命名虚拟机,更改虚拟机安装位置,下一步 7.处理器配置(这里默认或如下图配置即可),下一步 8.设置虚拟机内存(设置推荐内存即可),下一步 9.设置网络类型(这里选择NAT网络类型),下一步 10.设置虚拟机I/O控制器类型(也就是你虚拟机的存储文件机制,我们学习用,推荐即可),下一步 11.设置虚拟机磁盘类型(选择推荐,如下图),下一步 12.选择磁盘:我们选择创建新虚拟磁盘,下一步 13.指定虚拟磁盘大小(这里根据你自己需求大小,我的机器没多大空间了,我给20G,学习用也差不多够了),下一步 14.指定磁盘文件(这里默认即可),下一步 15.这里向你展示你安装的虚拟机信息,也可以在自定义硬件设置你需要的功能,点完成: 16,ok,到这里你的Linux还没有安装完毕,它还只是一个裸机,没有任何操作系统,如下图: 安装Linux 1.点击编辑虚拟机设置 选择CD/DVD(IDE)设备,选择使用ISO映像文件(M),然后浏览指向DVD1镜像文件 2.点击开启此虚拟机 3.选择第一行,直接回车(注意此时你的鼠标箭头不见了,是因为你进入了Linux界面,回到Windows界面可以用 "Ctrl+Alt" ) 4.选择skip(跳过) 5.点击 next 6.选择English,next 7.选择 U.S.English,next 8.选择第一个(Basic storage Devices:基础存储设备,Specialized Storage Devices:特殊存储设备),next 9.选择,yes,discard any data,next(清楚所有数据) 10.给你的设备起个名字,然后设置网络信息 勾选中Connect automatically,点击apply,点击close,点击next 11.选择时区(这里选择上海时区),next 12.设置root账号名称和密码(注意长度要不少于6位),next 13.这里默认,next 14.选择 Write changes to disk,next 15.这里可以自定义安装软件类型(我们学习用,就选择Desktop即可),next 16.然后确定开始安装,等待安装结束后需要你重启,Reboot 17.安装成功后,进入欢迎界面,点击Forward 18.默认,点击Forward

ELK 详解

目录 ElasticSearch 概述 索引(Index) 类型(Type) 文档(Document) 倒排索引(Inverted Index) 节点(Node) DSL(查询语句) 官方文档 查询 创建索引 查询所有索引 删除索引 查看索引的mapping和setting 查询所有索引中数据 查询权重(boost) 分词器(analyzer) 默认分词器 Ik分词器 Kibana 概述 Logstash 启动 Filebeat filebeat和beats的关系 filebeat是什么 filebeat和logstash的关系 filebeat原理 filebeat的构成 filebeat如何保存文件的状态 filebeat何如保证至少一次数据消费 filebeat怎么玩 压缩包方式安装 基本命令 输入输出 keystore的使用 filebeat.yml配置(log输入类型为例) 实例一:logstash作为输出 实例二:elasticsearch作为输出 filebeat模块 Solr与ElasticSearch ElasticSearch 概述 ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。官网https://www.elastic.co/。 ElasticSearch6.0版本以上需要jdk8环境才可以运行。Linux系统中ElasticSearch不能以root用户启动。 索引(Index) ES将数据存储于一个或多个索引中,索引是具有类似特性的文档的集合。类比传统的关系型数据库领域来说,索引相当于SQL中的一个数据库,或者一个数据存储方案(schema)。索引由其名称(必须为全小写字符)进行标识,并通过引用此名称完成文档的创建、搜索、更新及删除操作。一个ES集群中可以按需创建任意数目的索引。 类型(Type) 类型是索引内部的逻辑分区(category/partition),然而其意义完全取决于用户需求。因此,一个索引内部可定义一个或多个类型(type)。一般来说,类型就是为那些拥有相同的域的文档做的预定义。例如,在索引中,可以定义一个用于存储用户数据的类型,一个存储日志数据的类型,以及一个存储评论数据的类型。类比传统的关系型数据库领域来说,类型相当于“表”。 文档(Document) 文档是索引和搜索的原子单位,它是包含了一个或多个域(Field)的容器,基于JSON格式进行表示。文档由一个或多个域组成,每个域拥有一个名字及一个或多个值,有多个值的域通常称为“多值域”。每个文档可以存储不同的域集,但同一类型下的文档至应该有某种程度上的相似之处。 倒排索引(Inverted Index) 每一个文档都对应一个ID。倒排索引会按照指定语法对每一个文档进行分词,然后维护一张表,列举所有文档中出现的terms以及它们出现的文档ID和出现频率。搜索时同样会对关键词进行同样的分词分析,然后查表得到结果。 这里所述倒排索引是针对非结构化的文档构造的,而在ES中存储的文档是基于JSON格式的,因此索引结构会更为复杂。简单来说,ES对于JSON文档中的每一个field都会构建一个对应的倒排索引。参考官方文档。 节点(Node) 一个运行中的 Elasticsearch 实例称为一个节点,而集群是由一个或者多个拥有相同cluster.name配置的节点组成, 它们共同承担数据和负载的压力。 ES集群中的节点有三种不同的类型: 主节点:负责管理集群范围内的所有变更,例如增加、删除索引,或者增加、删除节点等。 主节点并不需要涉及到文档级别的变更和搜索等操作。可以通过属性node.master进行设置。 数据节点:存储数据和其对应的倒排索引。默认每一个节点都是数据节点(包括主节点),可以通过node.data属性进行设置。 协调节点:如果node.master和node.data属性均为false,则此节点称为协调节点,用来响应客户请求,均衡每个节点的负载。 DSL(查询语句) 官方文档 https://www.

xilinx FPGA在线调试方法总结(vivado+ila+vio)

本文主要介绍xilinx FPGA开发过程中常用的调试方法,包括ILA、VIO和TCL命令等等,详细介绍了如何使用。 一、FPGA调试基本原则 根据实际的输出结果表现,来推测可能的原因,再在模块中加ILA信号,设置抓信号条件,逐步定位问题模块和原因,最终解决bug。 二、FPGA常用调试方法 1、调用IP (1)ILA 第1步:在vivado中,打开IP核目录(IP Catalog),在搜索框中输入ILA(不区分大小写),按图示方式进行选择即可。 第2步:设置ILA参数 探针数根据需要采集的信号数设定,或者直接设定一个信号; 采样数据深度可根据实际需要和资源消耗情况进行设置,一般选择默认的1024即可; 第3步:测量信号的位宽进行设置 第4步:在IP source区,打开ILA,添加例化模板, 在代码中插入例化,把VIO的输出口连接到模块的输入。 ila_0 u_ila( .clk(clk), .probe0(probe0), .probe1(probe1), .probe2(probe2)); (2)VIO IP VIO的输出可以控制测试模块的输入,VIO的输入可以显示模块的输出值。 第1步: 例化一个VIO核,根据需要设定输入输出的数目 第2步:设置vio输出端口的位宽与初始值: 第3步:在代码中插入例化,把VIO的输出口连接到模块的输入。 vio_0 u_vio( .clk(clk), .probe_out0(probe_out0)); 2、添加调试信号 (1)在Verilog HDL文件中直接添加,特点是防止信号被优化,最大可能保留信号原本的名称。 在input/output前或在声明变量前添加(* mark_debug = “true” *) (* mark_debug = "true" *) wire done;(* mark_debug = "true" *) reg cnt; (2)标记Debug mark方法,可以在原理图(block design)或在综合后的网表(Netlist)中添加。 A、在原理图(block design)右击添加“Mark Debug”,工程综合后,在SYNTHESIS > Open Synthesized Design,在Netlist窗口中选择需要调试的网络节点,进行调试。 右键单击任意网络节点,点击Mark Debug,该网络节点会出现小甲虫标记。 对于已经选中Mark Debug的网络节点,也可以取消调试。右键单击该网络节点,选择Unmark Debug即可