记录:359
场景:PostgreSQL数据库常用操作,创建用户、数据库、表、主键、索引、注释等。配置远程可连接、配置环境变量、常用命令行操作。表的增删改查等操作。
版本:
操作系统:CentOS 7.9
PostgreSQL版本:PostgreSQL 13.4
PostgreSQL帮助手册:
官网入口:https://www.postgresql.org/
文档入口:https://www.postgresql.org/docs
文档内容列表:https://www.postgresql.org/docs/current/
支持的命令列表:https://www.postgresql.org/docs/current/reference.html
psql命令行列表:https://www.postgresql.org/docs/current/app-psql.html
1.PostgreSQL数据库
1.1PostgreSQL
PostgreSQL: The World's Most Advanced Open Source Relational Database.
PostgreSQL is a powerful, open source object-relational database system that has earned it a strong reputation for reliability, feature robustness, and performance.
解析:PostgreSQL是一个先进的开源关系型数据库。在可靠性、健壮性和性能方面赢得很高声誉。
1.2PostgreSQL历史版本下载
(1)下载地址
官网地址:https://ftp.postgresql.org/pub/source/
解析:下载需求的各版本移步此网站。
(2)命令下载
命令下载:wget https://ftp.postgresql.org/pub/source/v13.4/postgresql-13.4.tar.gz --no-check-certificate
(3)页面下载
浏览器登录到下载页面,选择对应版本。
2.安装PostgreSQL
注意:从1.3步骤下载的包是源码包,需要编译后才能安装使用。PostgreSQL启动运行一般使用Linux操作系统的普通用户。
(1)解压
解压命令:tar -xzvf /home/apps/software/postgresql-13.4.tar.gz -C /home/apps/module
(2)编译和安装
操作目录:cd /home/apps/module/postgresql-13.4
编译命令:make -C /home/apps/module/postgresql-13.
二叉树的构造(如何唯一确定一棵二叉树?附证明) 一些直观的认识 ▪ 同一棵二叉树具有唯一先序序列、中序序列和后序序列。
▪ 不同的二叉树可能具有相同的先序序列、中序序列和后序序列。
通过上面两个例子的验证:
▪ 仅有一个先序序列(或中序序列、后序序列),无法确定这颗二叉树的树形!
▪ 思考:给定先序序列、中序和后序遍历序列中任意两个,是否可以唯一确定这颗二叉树的树形?
二叉树的构造 (1) 同时给定一棵二叉树的先序序列和中序序列,就能唯一确定棵二叉树?
• 是!
• 定理1
(2) 同时给定一棵二叉树的中序序列和后序序列,就能唯一确定这棵二叉树?
• 是
• 定理2
(3) 同时给定一棵二叉树的先序序列和后序序列,就能唯一确定这棵二叉树吗?
• 否
下面我们给出证明:
定理1 ▪ 任何n(n>=0)个不同节点的二叉树,都可由它的中序序列和先序序列唯一地确定。
证明(数学归纳法) • 基础: 当 n=0 时,二叉树为空,结论正确.
• 假设: 设节点数小于n的任何二叉树,都可以由其先序序列和中序序列唯一地确定
• 归纳: 已知某二叉树具有n(n>0)个不同节点,其先序序列是a0a1 …an-1;中序序列是b0b1…bk-1bk+1…bn-1 .
▪ 先序遍历“根-左-右”,a0 必定是二叉树的根节点
▪ a0 必然在中序序列中出现,设在中序序列中必有某个bk(0<=k<=n-1)就是根节点a0。
• 由于bk是根节点,中序遍历“左-根-右”,故中序遍历中
▪ b0b1…bk-1必是根节点bk(a0)左子树的中序序列,即bk的左子树有k个节点
▪ bk+1…bn-1必是根节点bk(a0)右子树的中序序列,即bk的右子树有n-k-1个节点
• 对应先序序列,紧跟在根节点a0之后的k个节点a1…ak是左子树的先序序列,ak+1…an-1,这n-k-1就是右子树的先序序列.
文章目录 Hystrix 熔断器Hystrix 概述Hystrix 降级服务提供方步骤pom.xml(依赖)GoodsController.java(包含降级方法)启动类(@EnableCircuitBreaker)application.yml 服务消费方步骤pom.xmlOrderController.java(不变)feign调用接口(配置`@FeignClient`中fallback参数)feign调用接口实现类application.yml(feign:hystrix:enable = true) Hystrix 异常处理Hystrix 命令名称、分组及线程池划分Hystrix 熔断(自动)测试步骤自定义熔断阈值 Hystrix 仪表盘(Dashboard)单体应用监控 Hystrix 熔断监控(Turbine聚合监控)1. 搭建监控模块,引入依赖2. yml文件中进行配置3. 创建启动类4. 被监控模块导入依赖5. 被监控模块中添加Bean(高版本需要)6. 被监控模块的启动类上添加注解7. 启动测试 Hystrix 熔断器 Hystrix 概述 Hystrix 是 Netflix 开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败(雪崩)。
雪崩:一个服务失败,导致整条链路的服务都失败的情形。
Hystrix 主要功能:
隔离 线程池隔离(导入依赖,自动会进行线程池隔离)信号量隔离(每个服务只允许固定的访问数) 降级(提供方和消费方都需要添加降级方案)熔断限流 Hystrix 降级 Hystrix 降级:当服务发生异常或调用超时,返回默认数据 服务提供方 步骤 在服务提供方,引入hystrix依赖
<!-- hystrix --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> 定义降级方法
使用@HystrixCommand注解配置降级方法
在启动类上开启Hystrox功能:@EnableCircuitBreaker
pom.xml(依赖) <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>hystrix-parent</artifactId> <groupId>com.itheima</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>hystrix-provider</artifactId> <dependencies> <!
pandas是Python进行数据分析的过程中使用最广泛的库。利用pandas的内置方法,可以高效完成各种日常数据分析工作,如描述统计、数据清洗、分类汇总等。pandas的数据结构有4种,分别是Series、Time-Series、DataFrame和Panel。 1.Series:一维数组,与Numpy中的一维Array相似。 二者与List的区别是List中的元素可以是不同的数据类型,而Array和Series只允许存储相同的数据类型。
定义一个Series:
from pandas import Series s = Series([1,2,'a','b','c']) print(s) 0 1 1 2 2 a 3 b 4 c dtype: object 左侧的为索引,右侧列为元素值,可以通过索引修改元素值
s[3] = 'ccd' print(s) 0 1 1 2 2 a 3 ccd 4 c dtype: object 也可以通过index修改索引
s1=Series([1,2,'a','b','c'], index=['A','B','C','D','F']) s2=Series([111,222,333]) s2.index=['a','b','c'] print(s1) print(s2) A 1 B 2 C a D b F c dtype: object a 111 b 222 c 333 dtype: int64 2.Time-Series:以时间为索引的Series。 3.
问题 无法安全地用该源进行更新,所以默认禁用该源。 N: 参见 apt-secure(8) 手册以了解仓库创建和用户配置方面的细节。 E: 仓库 “https://mirrors.tuna.tsinghua.edu.cn/ubuntu bionic-updates Release” 不再含有 Release 文件。 N: 无法安全地用该源进行更新,所以默认禁用该源。 N: 参见 apt-secure(8) 手册以了解仓库创建和用户配置方面的细节。 E: 仓库 “https://mirrors.tuna.tsinghua.edu.cn/ubuntu bionic-backports Release” 不再含有 Release 文件。 解决方法 重新安装ca-certificates
安装地址 http://ports.ubuntu.com/pool/main/c/ca-certificates/
选最新更新的我是ubuntu 18.04,其他版本对应选择
或者用命令行
wget http://ports.ubuntu.com/pool/main/c/ca-certificates/cacertificates_20211016ubuntu0.18.04.1_all.deb 将文件下载到本地后使用以下命令
dpkg -i cacertificates_20211016ubuntu0.18.04.1_all.deb 至此问题解决
第一步:打开虚拟机找到创建新的虚拟机
第二步:进入向导选择典型
第三步:选择稍后添加操作系统
第四步:选择linux CentOS 7的版本
第五步:自定义虚拟机名称和安装地址
第六步:指定磁盘大小,默认选择20G,选择将虚拟机拆成多个文件
G
第七步:选择自定义硬件,进行相关设置
第八步:设置内存大小,推荐设置2-8G
第九步:选择新CD/DVD 安装CentOS7镜像文件
第九步:关闭设置点击完成
第十步:开启此虚拟机
第11步:选择CentOS7 点击回车
第12步:等待安装,安装完毕选择语言
第13步:选择图形化安装
第14步:自定义分区
第15步:点击加号添加分区,/boot设置500M swap设置1G 剩下内存全部给到/
第十六步:点击完成,选择接受更改
第17步:开始安装,等待安装(4-6分钟)并设置root密码和创建一个普通用户
第18步:安装成功点击重启
第19步:接受许可证
第20步,登录用户或者root用户
第21步:跳过向导,安装成功
RAID 和 LVM 简单学习笔记 RAID RAID 简介 RAID: Redundant Arrays of Inexpensive (Independent) Disks 廉价(独立)的磁盘冗余阵列。1988 年由加利福尼亚伯克利分校一个研究人员提出。多个磁盘组成一个’阵列’来提供更好的性能、冗余,或者两者都提供,当然可以提供更大的存储空间。
RAID 实现的方式
外接式磁盘阵列,通过扩展卡提供适配能力内接式磁盘阵列,主板集成 RAID 控制器,安装操作系统前在 BIOS 中进行配置软件磁盘阵列,通过操作系统实现 RAID 级别 这里的级别是指,多块磁盘组织在一起的工作方式。
RAID-0: 条带卷,stripRAID-1: 镜像卷,mirrorRAID-5RAID-6RAID-10RAID-01 一般根据需要使用 RAID-0、RAID-1、RAID-5、RAID-6、RAID-10。
RAID-0 该级别是加速的方式,即读写文件数据时,会把数据切割成以 ‘chunk’ 为单位的数据,按照一定的次序分别写入组成的磁盘中(磁盘数量 N >= 2 )。但是缺点是没有容错性,只有其中的一块硬盘出问题,所有的数据无效。
RAID-1 该级别是冗余的方式,即在写入数据时,同时在组成的磁盘中写入相同的数据(N >=2),这时具有容错性,但是磁盘空间只有一半,写速度没有提升,读性能有提升。
RAID-5 该级别是改进了 RAID-4 的基础上出现的,至少需要三块磁盘,每次写入数据时,也需要进行指定大小的切割,然后在组成磁盘数量按次序写入,但是有一块磁盘不是用于存放数据,而是用于存放其他几个磁盘数据的校验数据,且存放校验的磁盘是按照次序轮流的。
这样,读写性能提升,也有冗余。但是磁盘的使用率是 (N -1)/N。
RAID-6 该级别是在 RAID-5 基础上,增加了一个用于校验的磁盘,容错性更好。但是磁盘至少 4 块,其利用率为 ‘(N-2)/N’。
RAID-10 这是结合 RAID-1 和 RAID-0 两种方式。即先进行镜像式组合,然后再条带时组合。至少 4 块磁盘,利用率 50%。一般来说,这个容错性更好。
RAID-10 这是结合 RAID-0 和 RAID-1 两种方式。即先进行镜像式组合,然后再条带组合。至少 4 块磁盘,利用率 50%。
Contents Jetson Nano在 EMMC 上安装镜像U 盘启动和 TF 卡启动U 盘启动 (复制 eMMC 上系统)TF 卡启动 设置远程登录系统SDK 安装使用 SDK Manager 安装使用指令安装 Linux 操作基础文件传输、系统备份风扇配置AI 环境搭建PIP3 安装安装机器学习领域重要的安装包设置 CUDA 环境Tensorflow GPU 环境搭建Pytorch 环境搭建 硬件控制Jetson-IO - 端口使能修改设备树使能端口 CameraIMX219-83 Stereo CameraIntel RealSense D435i (深度相机)安装 SDK 和 pyrealsense2Python codes 更多资料References 我是直接购买的微雪 Jetson nano 开发板,它基于 Jetson Nano Module 核心板,提供与官方的 Jetson Nano Developer Kit (B01) 几乎一模一样的外设接口、大小及厚度
Jetson Nano Jetson Nano Module 参数
JETSON-IO-BASE-A 底板资源
(1) 模组卡座:插入 Jetson Nano 核心板(2) SD 卡扩展卡槽:可以接入 SD 卡做 SD 卡扩展,支持从 SD 卡启动系统(3) M.
列如:列表a=[1,2,3]
1、当使用 b=a时 给列表b赋值时
如果如果b里面的内容发现改变则列表a会发生变化
如:
a=[1,2,3]
b=a
b.append(4)
print(a)
输出:[1, 2, 3, 4]
2、当使用b[:]=a 或b=a[:] 或b[:]=a[:] 给列表b赋值时
如果如果b里面的内容发现改变则列表a不会发生变化
a=[1,2,3]
b[:]=a
b.append(4)
print(a)
输出:[1, 2, 3]
#####################
a=[1,2,3]
b=a[:]
b.append(4)
print(a)
输出:[1, 2, 3]
#####################
a=[1,2,3]
b[:]=a[:]
b.append(4)
print(a)
输出:[1, 2, 3]
同理,字典数据类型
列如:字典aa={‘name’:‘li’,‘age’:‘20’,‘time’:‘520’}
1、当使用 bb=aa时 给字典b赋值时
如果字典b里面的内容发现改变则字典a同时也会发生变化
aa={‘name’:‘li’,‘age’:‘20’,‘time’:‘520’}
bb=aa
bb.update(go=“good”)
print(aa)
输出:{‘name’: ‘li’, ‘age’: ‘20’, ‘time’: ‘520’, ‘go’: ‘good’}
2、当使用bb=aa.copy时 给字典b赋值时
如果字典b里面的内容发现改变则字典a不会发生变化
aa={‘name’:‘li’,‘age’:‘20’,‘time’:‘520’}
bb=aa
bb.update(go=“good”)
print(aa)
输出:{‘name’: ‘li’, ‘age’: ‘20’, ‘time’: ‘520’}
通过前面内置组件和修饰符Modifier的使用,结合Stat状态,相信对于一般的开发需求已经没有问题了,接下来对CompositionLocal进行学习,以及对列表组件LazyColumn&LazyRow和约束布局的完善ConstraintLayout
一、CompositionLocal CompositionLocal可以创建以树为作用域的具名对象,简单来说就是可组合函数的作用域内,其所有的内容组件都可以隐式的拿到和修改CompositionLocal中的内容,针对组件的颜色、样式等属性值,他们往往按照一套风格来设计,使用隐式调用更加合适
1.MaterialTheme主题 之前我们在使用一些Shape、Color、TextStyle时,用到了MaterialTheme的shapes、colors、typography获取,这些都是CompositionLocal对象
创建项目时,也会自动帮助我们创建一个主题:
private val DarkColorScheme = darkColorScheme( primary = Purple80, secondary = PurpleGrey80, tertiary = Pink80 ) private val LightColorScheme = lightColorScheme( primary = Purple40, secondary = PurpleGrey40, tertiary = Pink40 /* Other default colors to override background = Color(0xFFFFFBFE), surface = Color(0xFFFFFBFE), onPrimary = Color.White, onSecondary = Color.White, onTertiary = Color.White, onBackground = Color(0xFF1C1B1F), onSurface = Color(0xFF1C1B1F), */ ) @Composable fun MyComposeApplicationTheme( darkTheme: Boolean = isSystemInDarkTheme(), // Dynamic color is available on Android 12+ dynamicColor: Boolean = true, content: @Composable () -> Unit ) { val colorScheme = when { dynamicColor && Build.
代码阅读:基于扩散模型的标签高效语义分割Label-efficient semantic segmentation with diffusion models 代码阅读仅涉及DDPM部分,不对涉及的对比方法代码进行学习 开源代码
代码阅读仅涉及DDPM部分,不对涉及的对比方法代码进行学习
2.2.0 以太网 网络设备与终端设备在以太网中的传输数据过程 一、终端设备传输数据过程 当本机访问目标主机时,通过(IP+掩码 求出网段地址)的方式,求出本机与目标主机的网段地址进行与运算,从而判断出主机与目标主机是否在同一网段内: 如:本地地址(172.28.128.91/24)、目标地址1(172.28.128.20)、目标地址2(172.28.129.10/24)通过计算得出本机网段172.28.128.0,目标1网段172.28.128.0、目标2网段172.28.129.0 下图,通过IP与掩码的求出网段: 如果目标、本机在同网段,优先检查本机的ARP缓存表:
成功匹配到目标的IP信息,获取到MAC地址,将直接进行封装数据向目标发送没有匹配到目标的IP信息,本机将发送ARP request请求目标主机MAC地址,收到ARP Replay获取到目标主机MAC地址之后再封闭数据向目标发送。 如果目标、本机不在同网段,优先检查本机的ARP缓存表中是否存在本机的网关信息:
成功匹配到网关的IP信息,获取到MAC地址,将直接进行封装数据向网关发送没有匹配到网关的IP信息,本机将发送ARP request请求网关MAC地址,收到ARP Replay获取到网关MAC地址之后再封闭数据向网关发送。 下图,在终端查看arp缓存表:
C:\Users\Administrator>arp -a 接口: 172.28.128.91 --- 0xd Internet 地址 物理地址 类型 169.254.10.171 58-69-6c-4c-5a-3b 动态 172.28.128.1 58-69-6c-4c-5a-3b 动态 172.28.129.177 88-44-77-d2-6c-59 动态 二、交换设备传输数据过程 交换机处理数据帧的3种方式: 转发(Forwarding) 转发已知的单播帧(目标MAC信息在MAC地址表中存在) 泛洪(Flooding) 收到广播帧(目标MAC为全F时)、未知单播帧时(目标MAC信息不在MAC地址表) 丢弃(Discarding) 收到非正常的数据帧时(数据帧字节过小或过大,数据内容有误,FCS校验有误等) 交换机收到不同帧的转发过程: 当交换机收到数据帧之后,会优先将帧中的源MAC信息与接收帧的端口号进行一个绑定,然后记录在本机的MAC地址表中,这样做的好处就是下次有数据帧需要找某个目标MAC,可以通过MAC地址表快速的找到目标的信息与转发的端口。
MAC地址表: MAC地址表信息默认老化时间300秒,300秒内MAC信息没有更新/替换,将自动删除该MAC信息。如果端口状态变为了Down,相应的表项也会立即清除华为设备手动删除所有MAC地址表信息(含静态、动态等):undo mac-address [Huawei]display mac-address MAC address table of slot 0: --------------------------------------------------------------------------------------------------- MAC Address VLAN/ PEVLAN CEVLAN Port Type LSP/LSR-ID VSI/SI MAC-Tunnel --------------------------------------------------------------------------------------------------- 5489-98dc-20a4 1 - - Eth0/0/1 dynamic 0/- 5489-9836-620f 1 - - Eth0/0/2 dynamic 0/- --------------------------------------------------------------------------------------------------- Total matching items on slot 0 displayed = 2 对于交换机收到不同帧时的转发过程: 交换机收到已知单播帧 已知单播帧:帧中目标MAC地址已经存在本机MAC地址表中交换机收到单播帧之后,拆开发现需要找的目标MAC地址已经存在MAC地址表中,将直接将该帧从MAC地址表中记录的端口中发出。(交换机不修改帧中的源MAC、目标MAC) 交换机收到未知单播帧 未知单播帧:帧中目标MAC地址不存在本机MAC地址表中交换机收到单播帧之后,拆开发现需要找的目标MAC地址不存在MAC地址表中,将向除了收到该帧的端口,对其它端口进行泛洪收到的未知单播帧。 交换机收到广播帧 广播帧:帧中目标MAC地址为ff-ff-ff-ff-ff-ff当收到广播帧之后,拆开发现需要找的目标是广播MAC,将向除了收到该帧的端口,对其它端口进行泛洪收到的广播帧。 三、路由设备传输数据过程 路由设备与交换设备不同,并不会转发广播包(在二层中称为广播帧),如果发现广播包(ARP)请求的IP并不是自己的IP地址将会直接丢弃该包。
最近项目需要,使用了 ffmpeg 做摄像头视频采集和串流。这几天有点时间,打算把相关的一些知识记录分享一下。
在撰写本文时,我又在另外一台电脑上把 ffmpeg 重新安装了一遍,所以绝对真实靠谱!如果你觉得文章写得还不错,敬请点个赞支持一下,十分感谢~
ffmpeg 简介 ffmpeg是一套跨平台的,用于音视频录制、转换、流化等操作的完善的解决方案,它是业界最负盛名的开源音视频框架之一。许多软件都是基于ffmpeg开发的,如格式工厂、各种xx影音等。
ffmpeg 是一套开源库以及命令行工具的集合,用户既可以使用命令行直接对音视频进行操作(CLI),也可以调用其开源库进行个性化的功能开发(SDK)。
如果要在自己的程序中使用 ffmpeg ,那么使用它的 SDK 是最好的选择。当前 ffmpeg 包含以下几个库:
libavcodec : 编/解码libavfilter : 帧级操作(如添加滤镜)libavformat : 文件 I/O 和 封装/解封装libavdevice : 设备视频文件的封装/解封装libavutil : 通用工具集合libswresample : 音频重采样、格式处理、混音等libpostproc : 预处理libswscale : 色彩处理和缩放 ffmpeg 库在 Windows 下的安装 这个项目大部分是在 Linux 开发板上做的,Windows 上占一小部分。虽然如此,在 Windows 上安装 ffmpeg 的步骤一点都没法省。
ffmpeg 目前不提供预编译的库文件,而是需要自己下载源码并编译。看网上说 Windows 下编译 ffmpeg 非常麻烦,我想应该是“找到好用的教程”比较麻烦。本文使用 MSYS2 来编译 ffmpeg ,许多问题可以迎刃而解!
环境准备 在 Windows 下,编译需要做的准备如下:
安装并配置 MYSY2安装 git (可选)ffmpeg 源码x264 源码(可选) 本节只讲述 MSYS2 的安装和配置和源码的下载。git 可根据需要自行选择安装。
题目描述 一个n个元素的整数数组,如果数组两个连续元素之间差的绝对值包括了[1,n-1]之间的所有整数,则称之符合“欢乐的跳”,如数组1 4 2 3符合“欢乐的跳”,因为差的绝对值分别为:3,2,1。给定一个数组,你的任务是判断该数组是否符合“欢乐的跳”。
输入描述 每组测试数据第一行以一个整数n(1≤n≤1000)开始,接下来n个空格隔开的在[-10^8,10^8]之间的整数。
输出描述 对于每组测试数据,输出一行若该数组符合“欢乐的跳”则输出"Jolly",否则输出"Not jolly"。
测试样例 输入数据 1
4 1 4 2 3 Copy
输出数据 1
Jolly Copy
输入数据 2
5 1 4 2 -1 6 Copy
输出数据 2
Not jolly #include<stdio.h> #include<math.h> #include<string.h> int main() { int n,i,o=0; int a[1000],b[1000]; scanf("%d",&n); if(n==1){ printf("Jolly"); } for(i=0;i<n;i++){ scanf("%d",&a[i]); } for(i=0;i<n-1;i++){ b[i] = abs(a[i]-a[i+1]); } for(i=0;i<n-2;i++){ if(b[i]-b[i+1]==1||b[i]-b[i+1]==-1){ o++; } } if(o==n-2){ printf("Jolly"); } else{ printf("Not jolly"); } return 0; }
操作系统第九次作业 问题一: Consider a file system where a file can be deleted and its disk space reclaimed while links to that file still exist. What problems may occur if a new file is created in the same storage area or with the same absolute path name? How can these problems be avoided? 答:
这将导致通过该路径渴望获得旧文件的用户访问得到的是新文件;
解决的办法可以是:
文件删除并且磁盘空间释放之后,立即删除所有相关的链接如果该文件为共享文件,则对当前文件的共享用户数进行计数,当有一个用户删除该文件时,计数减一,当计数为零时真正删除该文件。 问题二: Consider a file system that uses a modified contiguous-allocation scheme with support for extents.
第七次作业 问题一:Explain the difference between internal and external fragmentation. 答:
内部碎片就是已经被分配出去(能明确指出属于哪个进程)却不能被利用的内存空间;
外部碎片指的是还没有被分配出去(不属于任何进程),但由于太小了无法分配给申请内存空间的新进程的内存空闲区域。
问题二:Given five memory partitions of 100 KB, 500 KB, 200 KB, 300 KB, and 600 KB (in order), how would each of the first-fit, best-fit, and worst-fit algorithms place processes of 212 KB, 417 KB, 112 KB, and 426 KB (in order)? Which algorithm makes the most efficient use of memory? 答:
first-fit:
212KB->500KB 空闲分区288KB
417KB->600KB 空闲分区183KB
文章目录 域控制器域控制器的组成ADAS域控制器智能座舱域HUD仪表盘IVI 域控制器的发展域控制器对传统ECU的挑战 域控制器 随着车辆的信息化程度的发展,车辆的ECU也越来越多,从引擎控制、转向助力、仪表、影音等,传统的汽车电子电气架构是分布式的(图1-2),ECU之间的通讯是通过CAN或者LIN线进行连接.
图1-2 随着现代汽车的发展ECU的个数也在急剧增加,一辆车中可能有上百个之多,整个系统的复杂度也越来越高,几近上限,所以这种基于ECU的EEA架构暴漏出诸多问题和挑战,为了解决这种EEA架构带来的问题,逐渐把功能相似、分离的ECU功能集成到一个比ECU性能更加强大的处理器硬件平台上,我们把这个平台称之为域控制器1
域控制器的出现代表着汽车EE架构从EE分布式演进到域集中式EE架构,如下图1-3
图1-3 域控制器的组成 域控制器是每辆车的核心,它主要由域处理器、操作系统和应用软件以及算法三部分组成,依托于它的强大功能,将原本需要多颗ECU实现的核心功能集成进来,极大提高系统集成性,加上标准的交互接口降低开发成本。
对于域如何划分,不同车厂根据自身的理念划分可能会有区别,比如BOSCH划分为:动力域、地盘域、车身域、座舱域、自动驾驶域,这个也是经典的五域集中式EEA
ADAS域控制器 ADAS域控制器需要连接多个摄像头、毫米波雷达、激光雷达等传感器设备,要具备多传感器融合,定位,路线规划等功能,将传感器收集到的数据进行大量的计算,目前国内能够提供这种强大算力的有华为、瑞萨、地平线等。
智能座舱域 智能座舱域主要包括HUD、仪表盘(Cockpit)、车载娱乐信息系统(In-Vehicle-Infotainment简称IVI)
HUD HUD主要是将ADAS和部分导航功能投影到挡风玻璃上面,诸如ACC、行人识别、路线提示等,随着AR的发展后续可能也会发展成AR HUD。
从之前的车辆代步到目前的人机交互,越来越注重体验,后续车辆可能能帮我们做的事情就更多了,比如下车前控制家中的智能设备打开、驾驶员状态检测(DSM2),基于这种多场景下的汽车座舱多模交互后续可能会重新定义人机交互的发展,Vehicle to do everything
仪表盘 仪表盘略
IVI 影音娱乐方面包括我们的电台、收音机、音乐等第三方应用
域控制器的发展 伟世通推出的SmartCore域控制器,集成了娱乐、仪表、ADAS等功能,开创了商用域控制器的先河,各大Tier1供应商也都纷纷跟进,整个域控制市场也逐渐火了起来,整个业界对DCU市场也是比较看好,华为也推出了属于自己的DCU方案,但是也对传统的汽车MCU提出了挑战,因为在分布式ECU的时代,计算和控制的核心是MCU芯片,传输的基础核心是基于传统的CAN、LIN总线。但是到了域控制时代,高性能、高集成度的异构芯片作为域控制器的核心芯片。汽车的传输也有传送的CAN或者LIN改变成了以太网传输。因为具有高带宽、实时和可靠的数据通讯能力,以后也会成为整车通讯的核心和主流。
域控制器对传统ECU的挑战 原本需要多个ECU3实现多个功能都整合到域控制器上,这就说明原有的主机厂的核心竞争力由以前的机械制造转化为软件和硬件以及算法为重点。以后的主机厂和Tier1的关系可能会变更为Tier1和芯片商合作做出整套方案售卖给车厂,或者Tier1只负责硬件的设计和生产,主机厂负责软件部分的研发
域控制器也叫做DCU,全称为Domain control unit ↩︎
DSM全称为Driver Status Monitor ↩︎
ECU全称为Electric control unit,是微型电脑,构成由CPU和存储以及I/O等 ↩︎
本段代码是从c++ primer plus(第六版)的212页改编的。
#include <iostream> using namespace std; const int Size = 10; //限制最多的数组是10个,数组名字是size,如果int ADD行如果数组小于10个也可以运行 int sum_arr(int arr[],int n); //对函数进行声明 int main() { int ADD[Size] = {1,2,3,4,5,6,7,8,9,10}; //定义一个数组ADD,整型int,里面有10个成员 int sum = sum_arr(ADD,Size); //将数组和数组成员个数传递给函数sum——arr,函数的作用是将10个成员相加,所以函数需要返回值,所以函数定义了sum,同样是int整型 cout<<"total= "<<sum<<endl; //输出一共吃的数量 return 0; } int sum_arr(int arr[],int n) //定义一个函数,是整型int,函数名字是sum_arr,类型是int,数组名是arr[],其实这里的arr[]是指针(具体的可以看书),int n 是传递的数量。 { int total = 0; //定义一个total变量,设置他的初始值是0 for(int i=0;i<n;i++) //对数组所有函数进行求和,利用for循环 {total = total + arr[i];} //需要将arr的值赋值给=前的total,在进行=后的total累加;或者本行代码也可以替换为total += arr[i]; return total; //返回total变量。 } 运行结果:
total= 55
磁盘类型和相关术语 在 Linux 中一切皆文件,但是类型不同。例如使用 ls -l 对于设备文件和普通文件有一部分内容是不同的,即普通文件有大小,而设备文件有主设备号和次设备号,没有大小。
# ll 1.txt /dev/sda /dev/sda1 -rw-r--r-- 1 root root 47 Nov 30 21:22 1.txt brw-rw---- 1 root disk 8, 0 Dec 3 10:13 /dev/sda brw-rw---- 1 root disk 8, 1 Dec 3 10:13 /dev/sda1 如果使用 cp -a 复制一个块设备,这时两个文件的主设备号和次设备号相同,但是它们的 inode 不同,类似于文件的软连接。如果挂载复制出来的文件,可以访问到与被复制的设备的内容。
# df /dev/sda1 Filesystem 1K-blocks Used Available Use% Mounted on /dev/sda1 487634 142353 315585 32% /boot # cp -a /dev/sda1 ./sda1.bak # mount sda1.
CMT: Convolutional Neural Networks Meet Vision Transformers
论文地址:https://arxiv.org/abs/2107.06263
复现设备:单卡V100 32G
复现数据集:CIFAR100
数据集地址:链接:https://pan.baidu.com/s/1BPt7kUO6ACo_2bQN_hwVkw 提取码:1qqz 训练流程:下载代码Efficient-AI-Backbones/cmt_pytorch at master · huawei-noah/Efficient-AI-Backbones · GitHub
安装:
- python==3.6 - cuda==10.0 pip install torch==1.7.0 torchvision==0.8.1; pip install timm==0.3.2; pip install torchprofile; 下载数据集,将数据集放在 CIFAR_100文件夹下,解压数据集。
本实验采用CIFAR100数据集,epoch=300,batchsize=128,GPU为单卡V100 32G。
执行:python -m torch.distributed.launch --nproc_per_node=1 train.py --data-set CIFAR100 --data-path CIFAR_100/ --output_dir output/ --model cmt_s --batch-size 128 --apex-amp --input-size 224 --num_workers 16 --weight-decay 0.05 --drop-path 0.1 --epochs 300 --test_freq 100 --test_epoch 260 --warmup-lr 1e-7 --warmup-epochs 20 参数:
Jellyfin是一个自由软件媒体系统,它让您能够控制管理和流媒体。它是专有Emby和Plex的替代方案,可以通过多个应用程序从专用服务器向最终用户设备提供媒体。Jellyfin是Emby 3.5.2版本的派生版本,并移植到.NET Core框架,以实现完全的跨平台支持。没有附加条件,没有高级许可证或功能,也没有隐藏的议程:只有一个团队想要构建更好的东西并共同努力实现它。我们欢迎任何有兴趣加入我们的探索!
您可以在此处找到所有可用客户端的列表。有关更多信息,请参阅我们的关于页面或常见问题解答。如果您正在寻求帮助,请查看此页面,了解我们使用的所有不同通信渠道。
注意:Jellyfin是一个快速发展的项目,处于早期阶段,此文档和代码可能会频繁更改。请经常查看,不要犹豫,通过我们的Matrix频道或subreddit与我们联系!
想立即开始使用Jellyfin吗?查看以下页面,了解如何在您的机器上安装Jellyfin。
windows安装
文档 想了解更多关于管理Jellyfin服务器的信息吗?查看这些页面!
对Jellyfin的贡献 个人理解:提供了一套视频存储播放的整个解决方案
后台服务器
客户端链接播放
官网
目录
前言:为什么要用docker搭建Hadoop集群?
准备:下载VMware、VMwareTools(或Xftp、Xshell)、Ubuntu或者CentOS映像文件、Hadoop和jdk压缩包
一、创建虚拟机
(1)点击新建虚拟机
(2)下一步
(3)下一步
(4)选择映像文件
(5)自定义信息
(6)自定义信息,位置最好放在非C盘
(7)设置处理器内核总数
(8) 后面五步都选下一步即可。
(9)设置磁盘大小
(10)点击下一步,再点击完成
(11)自动加载默认配置
二、安装docker并生成相关的镜像
(1)安装docker
(2)拉取CentOS镜像(Ubuntu镜像也行)
(3)通过build Dockfile生成带ssh功能的centos镜像
1、MAINTAINER hadoop
2、root:a123456
(4)将下载的文件上传虚拟机
1、在主机下载ssh,在终端输入:
2、 查看ip地址,在终端输入:
3、用Xshell和Xftp连接虚拟机主机
4、解压文件(把目录和文件名改成你自己的)
(5)生成带有ssh、hadoop和jdk环境的CentOS镜像
三、创建网桥,并启动docker容器
(1)创建网桥,在终端输入:
(2)查看网桥,在终端输入:
(3)启动三个容器并指定网桥
四、登录容器,配置ip地址映射和ssh免密登录
(1)登录容器(Hadoop服务器)
(2)在每个hadoop服务器中配置ip地址映射
(3)在每台hadoop服务器中配置ssh免密登录
(4)测试是否成功配置ssh免密登录,ssh + hadoop服务器名:
五、修改Hadoop配置文件
(1)创建文件夹,配置时要用
(2)编辑hadoop_env.sh,修改下面三个参数,按照你自己的改
(3)编辑core-site.xml
(4)编辑mapred-site.xml
(5)编辑hdfs-site.xml
(6)编辑yarn-site.xml
(7)编辑workers,把原先的默认值localhost删除
(8)配置环境变量,在终端输入:
(9)把文件拷贝到hadoop2和hadoop3上
(10)给文件赋权
六、启动Hadoop集群
(1)在hadoop1上执行以下命令:
1、格式化hdfs
2、一键启动Hadoop集群
(2)测试Hadoop集群
(3)磁盘空间占用
前言:为什么要用docker搭建Hadoop集群? 1、磁盘空间的占用
docker搭建的集群占用电脑磁盘空间较小,对电脑的硬件要求也不高,搭建一个Hadoop集群(一主两从)只需要17GB左右的磁盘空间,而常规的开启多台虚拟机搭建的方法,可能搭建一台Hadoop服务器就需要将近20GB的磁盘空间。
2、稳定性
docker搭建的Hadoop集群不容易宕机,用常规的方法搭建的话,可能会有一台或者多台虚拟机宕机,稳定性较差。
准备:下载VMware、VMwareTools(或Xftp、Xshell)、Ubuntu或者CentOS映像文件、Hadoop和jdk压缩包 给大家准备了Ubuntu映像文件、Hadoop和jdk压缩包,点击链接下载即可。没有Xftp和Xshell的同学可以用VMwareTools替代,只要把压缩包添加到虚拟机主机上即可。
链接:Ubuntu、jdk、Hadoop 提取码:2v56
一、创建虚拟机 用VMware创建一台新的虚拟机(CentOS或Ubuntu都可以)
一、项目原理 1、开发工具 Linux操作系统、Ubuntu、VScode、sqlite3数据库
2、涉及知识点 1、TCP并发服务模型
2、文件IO
3、sqlite3命令语句
3、原理 1、TCP多线程并发服务器实现多用户同时登录
2、服务器中创建数据库,在数据库中创建员工信息表和历史记录表存放相关信息
3、登录成功后选择相应操作编号,调用send函数发送给服务器,服务器执行对应功能函数
4、功能函数中主要通过封装sqlite3命令,调用sqlite3函数实现相应增删改查功能
5、增删改查的结果服务器调用recv函数发送给客户端,客户端进行打印
二、基本功能 1、可实现多用户同时登录,用户分为管理员用户和普通用户
2、管理员用户可以对其他用户进行增删改查
3、普通用户只能对自己的信息进行更改和查看
4、员工的登录信息存放在历史记录表中,管理员可查看 三、效果展示 管理员登录>>> 管理员查询>>> 管理员修改、添加、删除用户>>> 普通用户实现>>>
四、源码 头文件>>> #ifndef __STAFF_H__ #define __STAFF_H__ #define ERR_MSG(msg) do{\ fprintf(stderr,"__%d__:",__LINE__);\ perror(msg);\ }while(0) #define PORT 8888 #define IP "192.168.250.100" //定义员工信息结构体 typedef struct staff_info{ int num; int usertype; char name[16]; char passwd[8]; int age; char phone[16]; char addr[128]; char work[128]; char date[128]; int level; double salary; }staff_info_t; //定义通信的结构体信息 typedef struct { int msgtype; int usertype; char username[128]; char passwd[8]; char recvmsg[1024]; int flags; staff_info_t info; }msg; struct fcd { int newfd; struct sockaddr_in cin; sqlite3* db; }; #endif 服务器及客户端源码 见附件
#include <stdio.h> struct Student{ int num; char name[20]; float score; }; int main(){ struct Student stu[5]={{10101,"Zhang",78},{10103,"Wang",98.5},{10106,"Li",86},{10108,"Ling",73.5},{10110,"Sun",100}}; struct Student temp; int n=5; int i,j,k; printf("由高到低排名:\n"); for(i=0;i<n-1;i++){ k=i; for(j=i+1;j<n;j++) if(stu[j].score>stu[k].score) k=j; temp=stu[k]; stu[k]=stu[i]; stu[i]=temp; } for(i=0;i<n;i++) printf("%d%8s%8.2f\n",stu[i].num,stu[i].name,stu[i].score); return 0; }
PyAV是一个视频处理库,可用于读取、写入和处理视频。要使用PyAV读取视频关键帧,首先需要安装PyAV。可以使用以下命令安装PyAV:
pip install av 安装完成后,您可以使用以下代码打开视频文件并读取关键帧:
import av # 打开视频文件 video = av.open('path/to/video.mp4') # 遍历视频中的所有帧并解析指定帧 frame_count = 0 for packet in video.demux(): frame_count += 1 if frame_count == 2431: packet.decode(): frame = packet.decode() img = frame[0].to_ndarray(format='bgr24') cv2.imwrite('test1.jpg', img) # if frame.is_key: # 读取关键帧 # do_something_with_frame(frame) 在上面的代码中,我们首先使用av.open函数打开了视频文件,然后使用demux方法遍历视频中的所有分离器包(也称为“帧”)。对于每个分离器包,我们使用decode方法来解码其中的帧。有时候第一次解析为空,所以需要解析两次,并且完是列表形式,需要取第0个索引。
注,我们可以使用is_key属性来检查帧是否为关键帧,如果是,就可以使用do_something_with_frame函数来处理它。
请注意,上面的代码只是一个示例。实际应用中,您可能需要根据自己的需求对关键帧进行更复杂的处理。如果您需要更详细的帮助,请查看PyAV的文档。
AJAX: 无刷新的与服务器进行交互
nginx添加https协议 一、https是什么?二、创建步骤1.安装nginx2.创建证书 三、验证四、浏览器访问在windows安装证书 总结 nginx 192.168.122.50 一、https是什么? HTTPS (全称:Hypertext Transfer Protocol Secure ),是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性 。
HTTPS 在HTTP 的基础下加入SSL,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP与 TCP 之间)。这个系统提供了身份验证与加密通讯方法。
SSL(Secure Socket Layer)安全套接层是Netscape公司率先采用的网络安全协议。它是在传输通信协议(TCP/IP)上实现的一种安全协议,采用公开密钥技术。
二、创建步骤 1.安装nginx mkdir /opt/download 上传openresty-1.21.4.1.tar.gz到/opt/download目录
yum -y install pcre pcre-devel openssl openssl-devel zlib zlib-devel libpcre3-dev libssl-dev perl make build-essential curl libreadline-dev libncurses5-dev tar -xf openresty-1.21.4.1.tar.gz cd openresty-1.21.4.1 ./configure --prefix=/opt/openresty && gmake && gmake install ln -s /opt/openresty/nginx /opt/nginx /bin/cp -r /opt/download/nginx.
系列文章传送门:
微信小程序第一篇:自定义组件详解
微信小程序第二篇:七种主流通信方法详解
微信小程序第三篇:获取页面节点信息
微信小程序第四篇:生成图片并保存到手机相册
目录
一、page-caontainer 实现假页弹出
二、share-element 实现共享元素动画
首先我们先看一下要完成的效果:
我们要实现的效果就是点击歌单图片的时候,弹出一个假页并且伴随动画效果,当退出假页页面的时候,假页的歌单封面图会缩小到歌单页的封面图大小,并且移动到相应的位置。
一、page-caontainer 实现假页弹出 我们先看一下官网对于 page-container 的介绍:
小程序如果在页面内进行复杂的界面设计(如在页面内弹出半屏的弹窗、在页面内加载一个全屏的子页面等),用户进行返回操作会直接离开当前页面,不符合用户预期,预期应为关闭当前弹出的组件。 为此提供“假页”容器组件,效果类似于 popup 弹出层,页面内存在该容器时,当用户进行返回操作,关闭该容器不关闭页面。返回操作包括三种情形,右滑手势、安卓物理返回键和调用 navigateBack 接口。
也就是说它主要是帮助我们实现一些 popup 组件的效果,值得注意的是,position属性用来控制弹出位置,如果为 center ,则会有假页效果。如果为 top 或者 bottom 则是 popup 效果,如果为 right 就和新页面一样,是从右向左的效果。
下面我们就把需要包裹的元素都放在 page-container 标签中:
通过 showCover 来控制假页的显示与隐藏,当单击歌单页封面图时让 showCover 为 true,在假页页面点击背景图或者返回按钮时就让 showCover 为 false,duration 属性控制动画的持续时间。这样我们就成功实现了假页的弹出效果。
二、share-element 实现共享元素动画 为什么叫共享元素动画呢,因为在歌单页和假页的图片在我们看来默认他们就是一种元素,但是代码不知道呀,所以需要 key 属性进行标记,被 share-element 标签包裹,且 key 属性相同的元素就是一对共享元素。
在歌单页包裹封面图元素:
注意:关于位置,大小等 css 属性要放在 share-element 标签上,否则不能正确实现动画效果。
在假页包裹封面图元素:
share-element 上 duration 属性控制动画时间,transform 来控制是否发生动画。因为我们只想在返回的时候发生动画,所以在进入假页的时候一直让 showAnimate 属性为 false ,当点击假页背景返回的时候再开始动画,就有了开头的效果。是不是很简单呀!
主要对于基础类型的自定义排序我们要用泛形int->Integer
Arrays.sort(a,(Integer x,Integer y)-> { return cnt[x]!=cnt[y]?-cnt[x]+cnt[y]:x-y;} ); a=sorted(a,lambda x:(x[0],x[1])) sort dict d=sorted(d.items(),lambda x: ...)
mysql自动备份成sql格式,脚本如下:
#/usr/local/crontab/dumpbackup
# use like this : dumpbackup db1 db2 db3 ...
#! /bin/bash
dbsum=$#
if [ "${dbsum}" -eq 0 ];then
echo "Error:no database chosed"
exit 1
fi
mkdir -p /opt/hotbackup/innodb/
backdir=/opt/hotbackup/innodb/
touch /var/log/pixplayerbackup.log
datetime=`date +"%Y%m%d%H%M"`
filesum=`ls ${backdir} | wc -l`
if [ "${filesum}" -ge 5 ];then
cd ${backdir}
rm -rf `ls | head -1`
fi
cd /usr/local/mysql/bin
for i in $*;do
echo "backing up for database $i starting .
为了实现真正无侵入式的mock,我们基于开源Hook框架Frida-gum提供的API,利用C++模板进行封装,作者编写了一个简单实用的mock工具,在此开源分享(代码详见附录)。
背景
在单元测试中,往往需要减少被测函数的外部依赖,如网络访问、数据库访问等。我们希望有一个mock工具能让我们轻松地屏蔽掉外部依赖。
C++的开源mock工具比较少,而且大多是基于多态实现的(如gmock),只支持mock虚函数,需要对原有代码结构进行调整,或编写mock类继承自原有类才能使用,工作量太大,我们的目标是单测代码与原有项目工程隔离,不需要为了单测对线上代码逻辑进行太大修改。为了实现真正无侵入式的mock,我们基于开源Hook框架Frida-gum提供的API,利用C++模板进行封装,编写了一个简单实用的mock工具,在此开源分享,希望能在单测工程的搭建上有所帮助,大家可以根据自己的项目情况,在此基础上扩展自己需要的功能。
Frida是一种动态插桩工具,可以插入一些代码到Win、Mac、Linux、Android或者iOS原生app的内存空间,动态地监视和修改其行为,在安卓逆向工程上应用非常多。
我们的mock工具也正是利用了Frida能动态修改函数执行的功能,在此我们不对其具体原理做过多阐述,有兴趣的同学可以移步附录的参考链接。
实现的功能
mock工具实现了最实用的函数替换功能,支持所有类型的函数替换,如:成员函数、虚函数、静态函数、系统库的全局函数、链接库的函数,暂时不支持对匿名函数进行替换(需要拿到函数指针才行)。
▐ MOCK宏 MOCK(target, alter)
第一个参数为被mock的函数指针,第二个参数为想要替换的lambda或者函数指针。
▐ MOCK_RETURN宏 MOCK_RETURN(target, alter) 对MOCK宏的封装,替换掉被mock函数的返回值,只支持值类型。
▐ ExpectTimes 被mock函数期望的调用次数。
MOCK_RETURN(&MyTest::testMember, 0)->ExpectTimes(1); //测试运行次数 测试用例运行完成时,如果被mock的函数运行次数和期望的次数不一样,则测试用例运行失败。
▐ 自动回滚mock TEST(mock, mock脱离作用域自动失效) { int input = 10; //入参 { MOCK_RETURN(&globalFunction, 100); ASSERT_EQ(globalFunction(input), 100); //修改了返回值 } ASSERT_EQ(globalFunction(input), input); //mock析构后失效 } 利用此特性可以使单元测试每个测试用例相对独立,所以在一个测试用例中mock掉的函数,不影响其他用例,如果需要全局性的mock,需要将mock宏写在全局变量区域。
▐ 跨平台 在MacOS、Linux、Windows、Android、iOS等平台都能使用。
使用方式示例
下面的示例都基于这个类来使用mock
/** * 被mock的类 */ class MyTest { public: /** * 静态函数 * @return */ static int testStatic() { return 0; } /** * 普通成员函数 * @param input * @return */ int testMember(int input) { return input; } /** * const 成员函数 * @return */ int constMemberFun() const { return 0; } /** * 测试函数重载,输入int * @param intInput * @return */ static int overloadFunction(int intInput) { return 0; } static int overloadFunction(double doubleInput) { return 0; } }; ▐ mock静态函数 // 将testStatic的返回值改为10 MOCK(&MyTest::testStatic, []() { return 10; // 返回值从0修改为10 }); // 简单写法,效果同上,使用MOCK_RETURN 可以替换函数返回值 MOCK_RETURN(&MyTest::testStatic, 10); ▐ mock成员函数 // 将testMember的返回值改为 input + 1 MOCK(&MyTest::testMember, [](auto && self, auto && input) { // 成员函数被mock后,第一个参数为this指针,这里用self替换 return input + 1; //mock后返回input + 1(之前是返回input) }); int input = 10; //入参 ASSERT_EQ(MyTest().
文章目录 前言一、学习目标二、学习任务开发前准备项目展示项目分析项目初始化开发者工具创建空白项目 任务1:标签页切换任务分析前导知识编写页面结构和样式实现标签页切换 任务2:音乐推荐任务分析前导知识内容区域滚动轮播图功能按钮热门音乐 任务3:播放器任务分析前导知识定义基础数据实现音乐播放功能编写播放器页面控制播放进度 任务4:播放列表任务分析编写页面结构和样式 前言 如今微信小程序已经成为我们日常生活中不可或缺的‘介质’,如我们的出行、购物、餐饮、社交、娱乐等活动的小程序已经因有尽有,相比于去安装一个app人们自然更加倾向于在微信中去直接访问某个小程序,而且我们的小程序极为方便的为用户提供服务; 一、学习目标 掌握swiper组件、scroll-view组件的使用掌握image的使用掌握音频API的使用掌握slider组件的使用 二、学习任务 开发前准备 项目展示 音乐小程序项目效果展示: 项目分析 音乐小程序项目页面结构图 tab导航栏content内容区player音乐播放控件 音乐小程序项目目录结构:
项目初始化 开发者工具创建空白项目 创建文件 "pages": [ "pages/index/index", "pages/test/index", "pages/test/swiper", "pages/test/test" ], 更改标题为音乐
{ "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "音乐", "navigationBarTextStyle": "black" } 任务1:标签页切换 任务分析 标签页和页面(info.wxml、play.wxml、palylist.wxml)结构图:
swiper编写滑动页面结构:
<swiper> <swiper-item style="background:#ccc">0</swiper-item> <swiper-item style="background:#ddd">1</swiper-item> <swiper-item style="background:#eee">2</swiper-item> </swiper> 前导知识 swiper组件常用属性:
swiper组件编写滑动页面结构:
<swiper current-item-id="c"> <swiper-item item-id="a" style="background:#ccc">0</swiper-item> <swiper-item item-id="b" style="background:#ddd">1</swiper-item> <swiper-item item-id="c" style="background:#eee">2</swiper-item> </swiper> swiper组件编写滑动页面结构-inder.wxml:
swiper组件编写滑动页面结构-index.wxss:
image{ width:100%; } include主要用途: 将代码拆分到多个文件中,可以更方便地查找代码。将代码公共部分抽取出来。通过外部文件引入。 <include src="
1.list[-1],此时只有一个参数,作用是通过下标访问数据,-1是倒数第一个。
2.list[:-1],作用是返回从start_index = 0到end_index = -1的一串数据
3.list[::-1],作用是返回倒序的原list
4.list[1:0:-1],返回第0,1的倒序。
5.list[::1],步长为1,步长大于0时,返回序列为原顺序;步长小于0时,返回序列为倒序。
步长:[::-1]表示从右往左以步长为1进行切片。[::2]表示从左往右步长为2进行切片。
由于项目需要开发一个倒计时的功能,后台传送了一个结束时间的字段。
因此,这里封装了一个组件:
<template> <p class="p2" :endTime="endTime" :callback="callback" :endText="endText"> <i>{{hours}}</i>:<i>{{minutes}}</i>:<i>{{seconds}}</i>.<i>{{milliseconds}}</i> </p> </template> <script> export default { data(){ return { hours:0, minutes:0, seconds:0, milliseconds:0, pageTimer:{} } }, props:{ endTime:{ type: String, default :'0' }, endText:{ type : String, default:'已结束' }, callback : { type : Function, default :'' } }, mounted () { this.countdowm(this.endTime); }, watch:{ endTime(curVal,oldVal){ if(this.pageTimer){ //清除所有的定时器,防止传过来的值变化出现闪烁的问题 for(let each in this.pageTimer){ clearInterval(this.pageTimer[each]); } } this.countdowm(curVal,oldVal); } }, methods: { countdowm(timestamp,oldtime){ let self = this; this.
系列文章传送门:
微信小程序第一篇:自定义组件详解
微信小程序第二篇:七种主流通信方法详解
微信小程序第三篇:获取页面节点信息
目录
一、封装分享组件
二、定义用户授权方法
三、调用流程
首先我们看一下要完成的效果:
这种场景还是非常常见的,点击分享的时候我们可以转发给好友,或者生成当前页的海报图片保存到手机相册中。分享给好友这个功能可以通过 button 的 open-type 方式实现,那自动保存图片到本地该如何实现呢,让我们来看一看吧:
一、封装分享组件 首先我们要封装一个分享的组件,这样方便在其他的页面中复用。这样就大大减少了代码的冗余,
在 components 文件夹中新建一个组件,下面是完整代码
share.wxml:
<!-- 底部自定义分享菜单栏 --> <view class="share-sheet-mask flex-column" hidden="{{!showShareSheet}}" catchtap="closeShareSheet"> <view class="share-sheet"> <view class="items flex-row"> <view class="item flex-column"> <button class="ico flex-row" open-type="share"> <image class="img wx-ico" src="../../images/ico_wx.svg"></image> </button> <view class="desc">微信好友</view> </view> <view class="item flex-column"> <button class="ico flex-row" catchtap="genPlayBill"> <image class="img img-ico" src="../../images/ico_img.svg"></image> </button> <view class="desc">生成海报</view> </view> </view> <view class="cancel-share-sheet">取消</view> </view> </view> share.js:
上次介绍了compose中大多数的标准组件,此外还有两个重要的组件:列表LazyColumn和LazyRow,以及约束布局ConstraintLayout,在使用它们之前,先来认识Modifier
修饰符Modifier Modifier之前已经运用过,它能做的事情很多,不仅仅是改变组件的样式,还能够改变组件的位置,以及自定义交互事件,关于Modifier的所有用法,可以查看官方文档:https://developer.android.google.cn/jetpack/compose/modifiers-list,这边只介绍常用的
一、Modifier顺序 首先我们必须要知道的是:Modifier的设置是有顺序的,下面的代码分别在设置padding之前和之后为Box设置点击事件:
@Preview @Composable fun MyModifier1() { Row( horizontalArrangement = Arrangement.SpaceAround, verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxSize() ) { Box( modifier = Modifier .size(100.dp) .background( color = MaterialTheme.colorScheme.primary, shape = MaterialTheme.shapes.medium ) .clickable { } .padding(40.dp) ) Box( modifier = Modifier .size(100.dp) .background( color = MaterialTheme.colorScheme.primary, shape = MaterialTheme.shapes.medium ) .padding(20.dp) .clickable { } ) } } 效果如下,左边为padding之前,padding之后,可以看到之后再设置点击事件,整个组件的点击范围变小了:
二、操作 对组件的操作有很多,如点击、长按、双击、拖拽、选中等
1.clickable-点击 clickable之前就使用过了,除了点击外,还有一些其他属性和提供无障碍操作(残疾人)使用:
fun Modifier.clickable( interactionSource: MutableInteractionSource,// 只有第一次按下才会发送,并更新状态 indication: Indication?
目录
1 ContextLoaderListener
2 准备工作
3 配置web.xml
4 配置springmvc.xml
5 配置spring.xml
6 Spring整合MyBatis
7 配置log4j.xml
8 配置事务
9 测试功能
9.1 创建pojo类
9.2 员工列表功能
9.3 分页数据
9.4 分页相关超链接
1 ContextLoaderListener Spring 提供了监听器 ContextLoaderListener ,实现 ServletContextListener 接口,可监听 ServletContext 的状态,在 web 服务器的启动,读取 Spring 的配置文件,创建 Spring 的 IOC 容器。 web应用中必须在web.xml 中配置 配置Spring的监听器,在服务器加载启动时加载spring的配置文件,Spring配置文件的默认位置和名称为:/WEB-INF/applicationContext.xml。当然我们可以自定位位置和名称 我们测试这个监听器: 在web.xml文件中配置监听器,在之前的配置基础上,配置如下: <!--spring监听器--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--自定义spring配置文件的位置和名称,也就是resources下面--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring.xml</param-value> </context-param> 注意:只有控制层需要交给SpringMVC管理,其它都交给Spring管理。 通过源码我们发现SpringMVC的IoC可以访问到Spring中IoC的bean,但是Spring的IoC容器访问不到SpringMVC的IoC的Bean。所以我们不需要别的操作,SpringMVC的IoC容器就可以直接访问到Spring的IoC容器。
2 准备工作 创建model
引入依赖:
<properties> <spring.version>5.3.1</spring.version> </properties> <dependencies> <dependency> <groupId>org.
修改成功方法:
1、打开cmd,右键管理员身份打开命令提示符;
2、输入 netsh -> 回车,再输入 interface -> 回车:
3、输入 ip ->回车:
4、输入IP地址设置指令:set address “以太网” static IP地址 子网掩码 默认网关。标红的三个地址按实际情况依次输入 -> 回车:
netsh interface ipv4>set address “以太网” static 192.168.7.20 255.255.255.0 192.168.7.254
5、输入DNS设置命令: set dns “以太网” static DNS地址。 标红的DNS地址按实际情况填写 ->回车:
netsh interface ipv4>set dns “以太网” static 102.108.17.3
6、打开IPv4协议,查看属性,查看到ip成功修改完成,测试内网也通了。
人脸核身模块报错,我一直以为是人脸核身的sdk代码有错,导致我体验版本上传之后,一直白屏无法查看。后来查了查,才发现跟人脸核身没关系,是编译的问题,光勾选es6转ES5是不够的,需要把增强编译也勾选上才行
像这样就可以了
1、安装samba
执行yum -y install samba
2、配置samba
mkdir -p samba/share 创建共享目录
chmod 777 /samba/share/ 设置目录权限,否则windows下访问不能修改
修改samba配置文件:
cd /etc/samba/ 定位到配置文件目录
cp smb.conf smb.conf.bak 备份配置文件
vim smb.conf 编辑配置文件
[global] workgroup = WORKGROUP security = user map to guest = Bad User passdb backend = tdbsam printing = cups printcap name = cups load printers = yes cups options = raw # 设置默认用户和用户组,不是root用户登录时有用,该配置在ubuntu18.04上验证过 # force user = xxx # force group = xxx #[homes] # comment = Home Directories # valid users = %S, %D%w%S # browseable = No # read only = No # inherit acls = Yes # #[printers] # comment = All Printers # path = /var/tmp # printable = Yes # create mask = 0600 # browseable = No # #[print$] # comment = Printer Drivers # path = /var/lib/samba/drivers # write list = @printadmin root # force group = @printadmin # create mask = 0664 # directory mask = 0775 [share] comment = share file path = /samba/share writable = yes browseable = yes guest ok = yes create mask = 0644 //创建文件属性 force user = root //和服务端用户一样 systemctl disable firewalld 禁用防火墙
通过操作代理对象来调用目标类,这样就可以实现调用者和目标对象的解耦合。
应用场景:AOP 的实现、RPC 远程调用、Java 注解对象获取、日志框架、全局性异常处理、事务处理等。
代理的类型 静态代理 public interface Subject { void request(); } // 真实类 public class RealSubject implements Subject { @Override public void request() { System.out.println("访问真实主题方法..."); } } // 代理类 public class SubProxy implements Subject { /** * 真实对象 (将真实对象委托给代理对象) */ private RealSubject realSubject; @Override public void request() { if(realSubject == null){ realSubject = new RealSubject(); } preRequest(); realSubject.request(); postRequest(); } // 方法增强 public void preRequest() { System.
学习目标 了解 qt 的基本信息了解 qt 的下载及安装了解创建一个基本 qt 项目的流程了解信号与槽通过示例了解信号与槽的设置与编写了解控件添加的方式了解控件如何使用代码获取其文本了解控件如何使用代码设置其文本使用 connect 自定义信号与槽了解使用样式修饰控件外观了解使用代码清空控件文本学习使用Qt 编写一个四则算术计算器 注:本章中使用的一些方法方法是为了简单的了解一下概念性质,例如在多个槽函数时使用的方法并不是简便的,简便的方法在之后的学习中将会进行讲解。
一、简单了解 Qt 及下载安装 1.1 简单了解 Qt qt 是 C++ 的图形用户工具,是一个跨平台的用户界面解决方案;Qt 几乎支持所有的系统平台,并且是面向对象的。
Qt 的跨平台是非常强大的,例如可支持 win下的 XP、Vista、Win7/8/10 等 Windows 系统,并且对于Linux 下 X11、HP-UX、BSD/OS 又或是 嵌入式 Linux 平台 等都是支持的,甚至是 Mac 平台也支持。
1.2 Qt 下载及安装 Qt 分为商业版以及开源版,在此我们使用开源版本,开源版本是免费的。
Qt 开源版本的下载链接为 https://www.qt.io/download,打开链接中,往下滑动页面,找到开源版本下载板块:
点击后,将会跳转到一个页面,往下拉页面,点击下载 qt 二进制在线安装:
之后将会跳转到一个页面,并且会根据你的系统推荐你使用某个版本:
最后点击 Download 即可下载,安装步骤操作简单不再赘述,以上介绍开源版下载方式是因为部分同学认为Qt 是收费的,所以在此介绍开源版的下载方法(可能由于时间问题网页更新会导致下载“路径”不同)。
1.3 项目示例 Qt 作为一款优秀的 GUI 解决方案许多经典流行的应用使用了 Qt 进行开发,例如 WPS:
谷歌地球:
VirtualBox 虚拟机:
Linux 桌面系统等。
K8s 集群部署 文章目录 K8s 集群部署前言一、部署k8s的两种方式:二、环境准备三、初始化准备配置四、安装 Docker、kubeadm、kubelet【所有节点】五、部署k8s-master【master执行】六、部署容器网络 (master执行)七 部署测试总结 前言 学习了黑马K8s,首先跟着视频部署K8s,写下笔记
转至 原文链接
整合黑马老师笔记
一、部署k8s的两种方式: 目前生产部署Kubernetes集群主要有两种方式:
一 kubeadm
Kubeadm是一个K8s部署工具,提供kubeadm init和kubeadm join,用于快速部署Kubernetes集群。 二 进制包
从github下载发行版的二进制包,手动部署每个组件,组成Kubernetes集群。 本文采用kubeadm的方式搭建集群。
二、环境准备 在开始之前,部署Kubernetes 集群机器需要满足以下几个条件:
一台或多台机器,操作系统CentOS7.x-86_x64硬件配置:2GB 或更多RAM,2 个CPU 或更多CPU,硬盘30GB 或更多集群中所有机器之间网络互通可以访问外网,需要拉取镜像禁止swap 分区 k8s-master:192.168.100.10
k8s-node1:192.168.100.11
k8s-node2:192.168.100.12
三、初始化准备配置 检查操作系统的版本
# 此方式下安装kubernetes集群要求Centos版本要在7.5或之上 [root@master ~]# cat /etc/redhat-release Centos Linux 7.5.1804 (Core) 安装环境准备:下面的操作需要在所有的节点上执行。
关闭防火墙
systemctl stop firewalld systemctl disable firewalld 关闭selinux
selinux是linux系统下的一个安全服务,如果不关闭它,在安装集群中会产生各种各样的奇葩问题
sed -i 's/enforcing/disabled/' /etc/selinux/config # 永久 setenforce 0 # 临时 禁用iptable和firewalld服务
解决问题 由于调用 setInputMask 后,导致光标不能自动定位到行首开始输入的问题
from PyQt5.Qt import * import sys class MyLineEdit(QLineEdit): def mousePressEvent(self, event): super().mousePressEvent(event) # 这个要调用需要在前面调用,否则系统设定会覆盖光标移动到行首的自定义设定 self.setCursorPosition(0) class MyWdidget(QWidget): def __init__(self): super().__init__(parent=None) form_layout = QFormLayout() label1 = QLabel() label1.setText('label1') line_edit1 = MyLineEdit() line_edit1.setInputMask('HHHHHH;_') form_layout.addRow(label1, line_edit1) self.setLayout(form_layout) if __name__ == '__main__': app = QApplication(sys.argv) wind = MyWdidget() wind.show() sys.exit(app.exec())
解决null值字段不更新的问题 1.问题 我的MP版本是3.3.2,用Mybatis-Plus的updateById()来更新数据时,无法将字段设置为null值(更新后数据还是原来的值)。
2.分析 默认情况下,Mybatis-Plus在更新时会判断字段是否为null,如果是null,则不设值(不将这个字段拼接为SQL的SET语句)。
3.推荐的解决方案 updateById默认是不修改值为null的字段
update默认是修改值为null的字段,优点:可以用Wrappers构造指定按什么修改的修改条件,但缺点是按id修改时也得手动指定。
saveOrUpdate中的Update默认是修改值为null的字段的,优势:参数直接就是实体类本身,默认的修改条件就是根据id修改,不用再指定修改条件为id。如果是存在就更新,不存在就新增的场景建议用这个,因为这个的更新自带更新null值的字段。
建议用下面这种方案,不建议用全局设置的,或者在某个字段上加"@TableField(strategy = FieldStrategy.IGNORED)"注解的方案。
@Autowired private UserService; @ApiOperation("编辑") @PostMapping("/update") public void edit(Long id) {
//构造需要修改的实体类 User user = new User(); user.setId(id); user.setName(null); userService.lambdaUpdate()
//指定修改条件 .eq(User::getId, user.getId()) .update(user); }
//如果实体类字段少,也可以这样做
public boolean updateArticleById(Integer id) { Article article = Optional.ofNullable(articleMapper.selectById(id)).orElseThrow(RuntimeException:: new ); boolean i = articleService. lambdaUpdate() . set(Article::getOfflineTime, null ); .set(Article::getContent, "try mybatis plus update null" ); .set(Article::getPublishTime,LocalDateTime.now().plusHours( 8 )); .eq(Article::getId,article.getId()) .update(); return i ; } 常见问题:
朴素贝叶斯算法 1. 算法推导 朴素贝叶斯(Naive Bayes)算法是基于贝叶斯定理与特征条件独立假设的分类方法,其特点是结合先验概率和后验概率,既避免了只使用先验概率的主观偏见,也避免了单独使用样本信息的过拟合现象。该算法在数据集较大的情况下表现出较高的准确率,同时算法本身也比较简单。
朴素贝叶斯算法的目标是根据输入的特征,对每一个分类计算其后验概率,选择后验概率最大的那个分类作为模型输出。而后验概率是根据贝叶斯准则从条件概率推导而来的,假定每个样本包含 n n n 个特征,一共分可为 m m m 类, c k c_k ck 表示其中的某一个类别,下面是对朴素贝叶斯算法的公式推导:
① 先验概率:
P ( Y = c k ) P(Y=c_k) P(Y=ck)
② 条件概率:
P ( X = x ∣ Y = c k ) = P ( X ( 1 ) = x ( 1 ) , . . . , X ( n ) = x ( n ) ∣ Y = c k ) P(X=x|Y=c_k)=P(X^{(1)}=x^{(1)},.
引言 该项目主要使用技术:sprinboot、springSecurity、vue,其它的技术就不介绍了
其中springSecurity是我参考网上的案例去进行的集成,虽然集成成功了,但是还不是太懂。
下面就开始介绍一下我遇到的问题
问题重现 由于我项目后端集成了springSecurity,所以项目的登录验证和鉴权就是使用的springSecury来进行的,前端的话使用的element-ui-admin作为模板进行二开。
起初前端在进行登录的时候是可以正常访问后端不会出现跨域的问题,直到到了后面请求我的一个delete接口,这个时候就出现了跨域的问题,通过f12可以看见报403错误以及options错误
尝试修改Configuration(×) 然后我就去调我后端之前配置的跨域配置,如下是我原来的配置:
/** * <p> * 解决跨域问题 * </p> * * @author:雷子杰 * @date:2022/10/29 */ @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") .allowedMethods("*")//允许任何方法 .allowCredentials(true) .maxAge(3600); } } 其实我这个配置是没问题的,所以改来改去还是没啥作用。
尝试增加@CrossOrigin(×) 然后我就想到在Controller层增加@CrossOrigin,但是加了后还是没啥用
尝试更改前端跨域(×) 前端跨域就是webpack来进行请求代理,在vue.config.js中去添加以下即可,但是我添加了后,似乎是没了跨域的问题,但出现了新的问题,前端传过去的request中的数据是null(无法获取登录时用户传过去的数据,但前端确实是传过去了的)
devServer: { port: port, open: true, overlay: { warnings: false, errors: true }, before: require('./mock/mock-server.js'), proxy: { '/api': { // 代理名称 凡是使用/api开头的地址都是用此代理 target: 'http://192.
什么是Word2Vecto Word2vec是一种用于将词语表示为向量的技术,它可以将每个词语映射到一个固定长度的向量空间。这些向量可以用于许多自然语言处理应用程序,如词语相似度计算和分类。Word2vec的主要优势在于它可以将相似的词语映射到接近的向量空间中,因此在许多情况下可以更准确地表示语义相似性。
Word2Vector的工作原理 Word2vec的工作原理基于神经网络语言模型,它将词语表示为向量,并学习语料库中的词汇之间的相关性和语义关系。Word2vec通过分析语料库中的词语序列来学习这些关系,并使用这些关系来预测语料库中的下一个词语。在训练过程中,Word2vec会更新每个词语的向量来更好地表示它们的语义。最终,Word2vec会生成一个词语向量空间,其中每个词语都被表示为一个向量。这些向量可以用于许多自然语言处理应用程序,如词语相似度计算和语义分类。
通常,Word2Vec模型都使用词嵌入(word embedding)来表示单词。词嵌入是将单词映射到向量空间中的连续实值向量,能够保留单词之间的相似度和语义信息。
例如,它可以找到相似的单词,或者通过简单的数学运算来推断单词的语义。
例如,如果我们想找到“苹果”和“香蕉”的相似单词,可以在Word2Vec词嵌入空间中找到与这两个单词相似度最高的单词。
或者,如果我们想推断“苹果”和“香蕉”的关系,可以通过计算它们在Word2Vec词嵌入空间中的向量之差来推断它们之间的关系。
例如,如果“苹果”和“香蕉”的词嵌入向量之差较小,那么它们之间的关系就可能比较密切,例如它们都是水果。
Word2Vec算法解决什么问题 Word2Vec算法主要用来解决自然语言处理中的一个重要问题:如何将词语映射到向量空间中。
在自然语言处理中,我们经常需要处理大量文本数据。但是,由于人类语言的复杂性,文本数据往往难以直接处理。
例如,如果我们想要找到两个词语之间的相似度,我们就需要找到一种方法来表示它们。否则,电脑无法理解它们之间的差异,也无法计算它们之间的相似度。
Word2Vec算法就是用来解决这个问题的。它通过学习大量文本数据,来捕捉单词之间的相似度和语义信息。然后,通过词嵌入(word embedding)的方法,将单词映射到向量空间中。
这样,我们就可以使用电脑能够理解的向量数据来表示词语,并计算它们之间的相似度。这样,我们就可以在自然语言处理中,处理大量文本数据,并进行一些有用的操作。
Word2Vector有哪些模型 Word2vec有两种主要模型:一种是基于神经网络的模型,称为Continuous Bag-of-Words (CBOW)模型;另一种是基于深度学习的模型,称为Skip-Gram模型。这两种模型都用于将词语表示为向量,但是它们的训练方法略有不同。CBOW模型通常更快,因为它的训练需要更少的迭代,而Skip-Gram模型通常更准确,因为它能够更好地捕捉上下文语境中的词语关系。
Skip-Gram模型
Skip-Gram模型工作原理是,给定一个词,预测与它相邻的词,使用如下的公式来表示词向量之间的相似度: w i ⋅ w j = ∑ k = 1 n w i k ⋅ w j k w_{i} \cdot w_{j} = \sum_{k=1}^{n} w_{ik} \cdot w_{jk} wi⋅wj=k=1∑nwik⋅wjk
其中, w i w_{i} wi和 w j w_{j} wj是两个词向量, n n n是词向量的维度, w i k w_{ik} wik和 w j k w_{jk} wjk分别表示 w i w_{i} wi和 w j w_{j} wj中第 k k k个元素的值。
1 CPU架构 CPU架构是CPU厂商给属于同一系列的CPU产品定的一个规范,主要目的是为了区分不同类型CPU的重要标示。目前市面上的CPU分类主要分有两大阵营,一个是intel、AMD为首的复杂指令集CPU,另一个是以IBM、ARM为首的精简指令集CPU。两个不同品牌的CPU,其产品的架构也不相同,例如,Intel、AMD的CPU是X86架构的,而IBM公司的CPU是PowerPC架构,ARM公司是ARM架构。
2 指令集 计算机指令就是指挥机器工作的指示和命令,程序就是一系列按一定顺序排列的指令,执行程序的过程就是计算机的工作过程。指令集,就是CPU中用来计算和控制计算机系统的一套指令的集合,而每一种新型的CPU在设计时就规定了一系列与其他硬件电路相配合的指令系统。而指令集的先进与否,也关系到CPU的性能发挥,它也是CPU性能体现的一个重要标志。指令的强弱也是CPU的重要指标,指令集是提高微处理器效率的最有效的工具之一。从现阶段的主流体系结构讲,指令集可分为复杂指令集和精简指令集两部分 。
复杂指令集,也称为CISC指令集,英文名是CISC,(Complex Instruction Set Computing的缩写)。在CISC微处理器中,程序的各条指令是按顺序串行执行的,每条指令中的各个操作也是按顺序串行执行的。顺序执行的优点是控制简单,但计算机各部分的利用率不高,执行速度慢。其实它是英特尔生产的x86系列(也就是IA-32架构)CPU及其兼容CPU,如AMD、VIA的。即使是现在新起的X86-64(也被称为AMD64)都是属于CISC的范畴。
精简指令集(RISC:Reduced Instruction Set Computing RISC)是一种执行较少类型计算机指令的微处理器,起源于80年代的MIPS主机(即RISC机),RISC机中采用的微处理器统称RISC处理器。这样一来,它能够以更快的速度执行操作(每秒执行更多百万条指令,即MIPS)。因为计算机执行每个指令类型都需要额外的晶体管和电路元件,计算机指令集越大就会使微处理器更复杂,执行操作也会更慢。纽约约克镇IBM研究中心的John Cocke证明,计算机中约20%的指令承担了80%的工作,于1974年,他提出RISC的概念。许多当前的微芯片都使用RISC概念。
复杂指令集与精简指令集区别简化指令与复杂指令的区别!好文 - 楚广明 - 博客园 (cnblogs.com)
主流的CPU架构按照复杂和精简指令集可以按照如下区分:
CISC:x86;RISC:arm、RISC-V、LoongArc(龙芯)、MIPS; 3 x86、ARM、MIPS和loongARC架构的特点比较
(1) x86
架构特征:指令系统庞大,功能复杂,寻址方式多,且长度可变,有多种格式;各种指令均可访问内存数据;一部分指令需多个机器周期完成;复杂指令采用微程序实现;系统兼容能力较强。
架构优势:x86 架构兼容性强,配套软件及开发工具相对成熟,且 x86 架构功能强大,高效使用主存储器,因此在处理复杂指令和商业计算的运用方面有较大优势。
主要应用领域或使用场景:服务器、工作站和个人计算机等。
(2) ARM
架构特征:指令长度固定,易于译码执行;大部分指令可以条件式地执行,降低在分支时产生的开销,弥补分支预测器的不足;算数指令只会在要求时更改条件编码。
架构优势:ARM 结构具有低功耗、小体积的特点,聚焦移动端市场,在消费类电子产品中具有优势。
主要应用领域或使用场景:智能手机、平板电脑、工业控制、网络应用、消费类电子产品等。
(3) MIPS
架构特征:采用 32 位寄存器;大多数指令在一个周期内执行;所有指令都是 32 位,且采用定长编码的指令集和流水线模式执行指令;具有高性能高速缓存能力,且内存管理方案相对灵活。
架构优势:MIPS 结构 设计简单、功耗较低,在嵌入式应用场景具有优势。
主要应用领域或使用场景:桌面终端、工业、汽车、消费电子系统和无线电通信等专用设备等。
(4) loongARC
架构特征:融合X86/MIPS/ARM等主流指令系统的主要特点,高效支持二进制翻译。保持典型RISC风格:定长 32通用定/浮点 load-store结构;取消延迟槽,新增以PC为源操作的运算指令;实现位操作等多数指令集选择增加的指令。
4 CPU架构与指令集关系
CPU的硬件结构,即架构,一旦确定,那么使用该架构的CPU能实现的功能大体上是一样的,而且去实现该功能的指令集也大体上一样的。
设计CPU架构即决定了指令集,如X86指令集,是因为该CPU采用了X86结构,所以才叫X86指令集;指令集是指某种架构CPU能实现的所有功能,这些功能对应的代码编号构成指令集;代码编号应该就是指机器码这种底层代码,某种架构CPU架构确定后,代码编号就确定了,这些编号反映了CPU以什么样的方式去执行某些功能,决定了硬件的执行方式;前面说这些代码编号可能就是机器码,机器码就是二进制数字,二进制数字反映在电路上就是高低电平,从而驱动电路运行;不同代码编号的二进制数字排列就不同,所以驱动电路的高低电平就不同,所以电路执行的方式就不同。
相同的功能<-不同的电路实现<-不同架构的CPU<-不同的指令集<-汇编语言<-同一个程序
总结: 不同架构的CPU,最终体现在CPU实现相同功能的方式不同,或者有的CPU具有其它CPU实现不了的功能,是某种架构独有的;而不同指令集实现对上层代码进行不同的翻译,对下操作不同的电路实现。 参考链接:关于CPU 架构与指令集的一些个人理解 - warmbeast - 博客园 (cnblogs.
记录:357
场景:在CentOS 7.9操作系统上,使用yum info查看软件包信息,包括软件包名称、适用架构、版本号、发行版、软件大小、仓库名称、概要、URL、许可证、描述。
版本:
操作系统:CentOS 7.9
1.iptables包
(1)查看软件信息
命令:yum info iptables
(2)软件信息
执行命令查出的软件信息。
解析:从展现信息可以看到软件包名称、适用架构、版本号、发行版、软件大小、仓库名称、概要、URL、许可证、描述。
(3)从字段Description中找出软件功能描述
描述:The iptables utility controls the network packet filtering code in the Linux kernel. If you need to set up firewalls and/or IP masquerading,you should install this package.
解析:iptables实用程序是Linux内核中控制网络包过滤的代码。可以设置防火墙和IP伪装。
2.yum-utils包
(1)软件描述
yum-utils is a collection of utilities and examples for the yum package manager. It includes utilities by different authors that make yum easier and more powerful to use.
在学习这条路上,不知道啥时候,只关注解决问题的方法,没有去溯源.下面是在BOSS看到一个话题.
java 面武:
上来面试官就让我介绍一下jvm,我直接懵逼了,然后面试就结束了.现在java 面试都这么狠了吗?开题让自由发挥
你要首先讲why,为什么要有jvm,解决什么问题。再讲一下what,jvm都有哪些东西,解决什么场景,然后是how,介绍下这些东西的实现。最后在讲下自己在日常工作中用到了哪些和jvm相关的技术,或者是借鉴了它的什么思想。一套小连招,送给你.
Why
解决什么问题
What
都有哪些东西,解决什么场景
How
都是怎能实现的
应用
日常工作中用到了哪些和jvm相关的技术,或者是借鉴
SQLyog下载链接: 点击跳转 提取码:520H
在这一篇内容MySQL数据库 —— 常用语句当中讲到关于MySQL数据库命令的基本使用,这一篇是关于SQLyog数据库图形化工具的内容,先进行安装演示后在通过SQLyog进行操作数据库:
SQLyog 安装 下载完成之后双击打开 选择【Chinese(Simplified)】进入一下界面:
运行之后会出现需要注册SQLyog证书密钥界面,内容在链接当中已经提供了;注册完成后会进入SQLyog点击【新连接】接入【数据库】,在此之前要确保mysql服务已经开启才能连接成功,在之前的内容已经讲过了,看到如下界面:
紧接着弹出一个窗口:
连接成功之后可以看到如下界面:
图形化工具操作 —— 非命令 创建数据库 创建一个名为syan的数据库,字符集和数据库排序规则可以默认,
创建数据表 查看数据表 插入表数据 修改表数据 修改表数据也非常容易,只要将要修改的数据进行点击在框内重新数据数据即可;
删除表数据 导出数据库 将刚刚创建好了的数据库进行导出给别人去使用或者进行备份保存;
可以打开该脚本进行查看; 删除数据库 下面来删除数据库之后将刚刚导出的数据库再重新导入回去; 下面来删除数据库:
导入数据库 下面来将刚刚导出的数据库文件重新导入回去;这种操作也是经常会用到的,拿到自己保存的或者他处取得的数据库导入自己的电脑当中;
导入之后可能没有看到,这时候就需要进行刷新一下数据库;
下面来进行在图形化工具当中使用MySQL数据库命令的形式来操作;
图形化工具操作 —— 命令 在SQLyog当中去使用这个MySQL数据库操作的命令,简单的了解一下关于SQLyog面板的内容,通过对这个面板的认识,可以大大的方便之前的操作;下面来对面板中常用的进行了解:
查询数据库 SHOW DATABASES; 创建数据库 CREATE DATABASE syan DEFAULT CHARACTER SET 'utf8'; 刷新一下数据即可查看到; 创建数据表 CREATE TABLE sen( sName CHAR(6) NOT NULL PRIMARY KEY, sAge INT NOT NULL); 查看数据表 DESC sen; 插入表数据 INSERT INTO sen (sName,sAge) VALUE ('ZHENG',18),('YAN',18),('LIN',20); 查询表数据 SELECT * FROM sen; 修改表数据 UPDATE sen SET sAge = 18 WHERE sName = 'LIN'; 查询修改 SELECT * FROM sen;
文章目录 1、数据链路层1.1 功能和协议1.2 Ethernet 以太网mac地址mac地址表帧格式 2、交换机3、ARP协议工作原理ARP缓存表广播风暴局域网扫描脚本 4、虚拟局域网VLAN广播域划分vlan的作用创建vlan 5、trunk中继链路trunk作用trunk模式 1、数据链路层 位于网络层与物理层之间
1.1 功能和协议 数据链路的建立,维护与拆除
帧包装,帧传输,帧同步
帧的差错恢复
流量控制
ppp协议:点到点协议(Point-to-Point Protocol)
PPPOE协议:是以太网上的点到点协议( Point-to-Point Protocol Over Ethernet ),是将点到点协议ppp封装在以太网框架中的一种网络隧道协议,
1.2 Ethernet 以太网 mac地址 mac地址是嵌入到网卡芯片里的,出产就配置好了,不需要我们去配置–》全球唯一,mac地址是可以改的。
以太网(ethernet):就是我们平常的局域网
mac地址(硬件地址、物理地址)
mac地址是48位的;前24位代表厂商;后24位代表厂商生产的网卡的唯一标识,16进制是12位
linux里面查看:ip add ——00:0c:29:6b:da:85
windows里面查看:ipconfig -all ——物理地址 : 70-8B-CD-1F-A9-58 mac地址表 交换机里面有个mac地址表,记录所有连接到交换机的电脑mac地址和对应的接口;
mac地址表存放在内存里
mac地址表:mac地址+对应的端口号+vlan
mac地址表会更新吗?
会
· mac地址表里面的条目是有老化时间的,有自动刷新行为
· mac地址表只在局域网里面使用,广域网里面使用的是ip地址
帧格式 字段内容源mac6字节目的mac6字节数据46~1500字节 mtu最大传输单元帧校验序列校验数据真伪,防止数据丢失帧的范围64 ~1518 字节MTU最大传输单元,数据在帧里最大只能是1500 字节 2、交换机 交换机只做俩件事:学习和转发 1、学习:帧里面的mac地址,将其和对应接口号记录到mac地址表里面
2、转发:
不知道mac地址时,会广播——>给每一个接口都复制一份数据,转发过去
知道mac地址,就单播
工作原理
假设一台新的交换机连了3台电脑,电脑向外发广播。
1、学习:学习帧里面的源mac地址写到mac地址表
2、转发:根据帧里的目的mac地址去转发.
先查询下mac地址表里面是否有对应的目的mac地址对应的接口,有就单播转发;
没有就广播(复制数据帧给除进来的接口以外的其他接口都发一份) 工作过程描述
nginx学习使用 一、nginx安装与使用1、linux安装2、linux卸载3、升级4、linux环境下,把nginx设置为开启自启动 二、nginx常用命令1、部署命令2、其他命令 三、配置文件解析1、系统配置2、各配置指令详解3、日志配置4、跟据上面的命令,实现一个代理配置案例5、静态资源优化配置语法6、跨域配置7、Rewrite功能配置8、目录自动添加"/"9、合并目录 四、Nginx静态资源压缩实战与缓存1、Gzip模块配置指令2、Gzip压缩功能的实例配置3、Gzip和sendfile共存问题4、gzip_static测试使用5、静态资源的缓存处理6、浏览器缓存相关指令7、静态资源防盗链8、spenssl生成证书9、静态资源下载站点制作 五、nginx反向代理1、proxy_pass2、proxy_set_header3、proxy_redirect4、nginx反向代理实战 六、负载均衡1、负载均衡的作用2、Nginx七层负载均衡3、Nginx七层负载均衡的指令4、负载均衡(轮询访问)案例5、负载均衡状态6、负载均衡策略7、负载均衡案例 八、缓存集成1、Nginx缓存设置的相关指令2、Nginx缓存设置案例3、Nginx缓存的清除4、Nginx设置资源不缓存 九、nginx用户认证十、nginx扩展:lua脚本十一、实战:Nginx实现服务器端集群搭建十二、下面补充几个nginx的置nginx.conf模板 一、nginx安装与使用 1、linux安装 2、linux卸载 3、升级 4、linux环境下,把nginx设置为开启自启动 经过前面的操作,我们会发现,如果想要启动、关闭或重新加载nginx配置文件,都需要先进入到nginx的安装目录的sbin目录,然后使用nginx的二级制可执行文件来操作,相对来说操作比较繁琐,这块该如何优化?另外如果我们想把Nginx设置成随着服务器启动就自动完成启动操作,又该如何来实现?这就需要用到接下来我们要讲解的两个知识点
第一步,nginx配置成系统服务
(1) 在/usr/lib/systemd/system目录下添加nginx.service,内容如下:
vim /usr/lib/systemd/system/nginx.service [Unit] Description=nginx web service Documentation=http://nginx.org/en/docs/ After=network.target [Service] Type=forking PIDFile=/usr/local/nginx/logs/nginx.pid ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf ExecStart=/usr/local/nginx/sbin/nginx ExecReload=/usr/local/nginx/sbin/nginx -s reload ExecStop=/usr/local/nginx/sbin/nginx -s stop PrivateTmp=true [Install] WantedBy=default.target (2)添加完成后如果权限有问题需要进行权限设置
chmod 755 /usr/lib/systemd/system/nginx.service (3)使用系统命令来操作Nginx服务
启动: systemctl start nginx 停止: systemctl stop nginx 重启: systemctl restart nginx 重新加载配置文件: systemctl reload nginx 查看nginx状态: systemctl status nginx 开机启动: systemctl enable nginx 第二步,nginx命令配置到系统环境
需求:在A分支上工作,本地修改了代码还没有提交到远程仓库,现在要将这些修改转移到B分支上。
1.在A分支上暂存: git stash
2.切换到B分支: git checkout B
3.在B分支释放暂存: git stash pop
这样就将A分支代码转移到B分支的本地工作区了,且并未提交。
文章目录 一.前言二.介绍三.硬件连接1.系统框架2.中心网关的连接3.传感器节点1的连接4.传感器节点2的连接 四.网关程序1.主程序设计2.LoRa程序3.串口1程序4.LCD显示程序 五.传感器节点程序1.传感器节点一主程序2.传感器节点二主程序流程图3.温湿度传感器程序4.气体传感器程序5.光照传感器程序6.LoRa程序 六.测试与验证1.代码的调试与下载2.LoRA模块的配置3.上位机通信4.网关控制 一.前言 本篇文章为本科毕业的时候做的毕业设计,当时还手动画了PCB版,经过验证该系统是可以正常工作,但在这里并没有把所有图片和源码都附上,有问题可以讨论
二.介绍 本系统由中心网关和两个传感器节点组成,两个传感器节点获取温湿度,二氧化碳气体浓度,光照强度这几种数据,传感器节点和中心网关通过LoRa进行数据传输。
中心网关通过串口和上位机连接,此时就可以通过上位机查看数据信息,同时中心网关有显示器模块,通过显示器模块也可以查看到数据信息。网关的小灯作为指示灯指示当前的工作模式,并通过按键改变系统的工作模式,设定的系统工作模式有:配置模式、通信模式、深度休眠模式。中心网关在设计上由ALIENTEK的战舰 STM32F103单片机和亿佰特的E22-400T30D LoRa无线模块组成。
传感器节点由主控MCU、传感器元件和LoRa无线通信模块组成,由于需要接入比较多的传感器,所以传感器节点有两个。其中一个节点由STM32F103C8T6系统板、温湿度传感器、气体传感器和LoRa无线通信模块组成,另一个节点由STC89C52RC系统板、光照传感器和LoRa无线通信模块组成,两个节点将获取到的传感器数据通过LoRa模块向中心网关发送,完成数据采集和传输的功能。同时也可以接收网关的LoRa模块发送的信号,从而做出响应。
三.硬件连接 1.系统框架 2.中心网关的连接 中心网关采用STM32F103芯片,通过引出IO控制LoRa模块的工作方式并获取LoRa模块的状态,LED小灯作为指示灯,蜂鸣器作为警报器,显示屏显示当前接收的数据,按键切换系统工作模式。中心网关通过SWD接口进行程序的调试和下载,LoRa无线模块的由5V/3V电源电路输入输出模块进行供电,整个网关由USB进行供电,保证系统的正常运行。
通过引出IO实现网关和LoRa无线传输模块的连接,将LoRa无线传输模块的M0、M1连接到网关PB6和PB7,通过这两个IO输出高低电平来控制LoRa无线传输模块的工作模式,将LoRa无线传输模块的工作状态通过AUX接到PA4,网关通过PA4IO口接收到的高低电平来判断无线传输模块处于空闲模式或者忙碌模式,中心网关MCU进而做出进一步的处理。每个IO口寄存器要按照32位字被访问,都有7个寄存器来控制,CRL和CRH控制每个IO口的模式和输出速率。
3.传感器节点1的连接 节点一的微控制处理单元为STM32F103C8T6,这是基于ARMCortex-M3内核设计的微控制器,由意法半导体公司推出。支持SWD调试,拥有USBHD外设,额定电压为3.3V或者5V,该芯片的控制LoRa模块的工作模式,芯片的RX接收数据,TX发送数据,完成与LoRa进行通信,LoRa的M1、M0、和AUX与芯片的其他引脚连接,让芯片控制LoRa工作模式及获取LoRa工作状态。DHT11的DATA总线与芯片的PA15相连,由于PA15为JTAG调试接口,需要先禁用JTAG功能才能作为普通的GPIO口,该总线完成数据传输的功能。SPG-30模块的SCL与PB0相连,SDA与PB1相连,通过IIC完成数据通信。该芯片同样可以提供3.3V或者5V电压和GND,让LoRa模块、温湿度传感器模块和气体传感器模块正常工作,板上的小灯指示节点工作状态。同样在使用GPIO口时,要对GPIO口进行初始化。
4.传感器节点2的连接 节点二的微控制器为STC89C52RC,Flash程序空间是8K字节,RAM数据空间是512字节使用该芯片可以降低成本,同时也能完成数据的接收和发送。该芯片是宏晶的增强51单片机,可以使用STC进行程序的下载,具有8K的可编程Flash存储器。该节点由STC89C52RC系统板、光照传感器和LoRa无线通信模块组成。芯片的RX和TX引脚和LoRa无线通信模块相连,完成与LoRa的数据接收和发送。T2和T2EX引脚与光照传感器相连,完成与光照传感器的数据传输。其他引脚与LoRa的M1、M0、和AUX连接,控制LoRa工作模式及获取LoRa工作状态。该系统板提供5V电压和GND,使LoRa模块和光照传感器正常运行。其他引脚与LoRa的M1、M0、和AUX连接,控制LoRa工作模式及获取LoRa工作状态。
四.网关程序 1.主程序设计 网关主程序是该系统的核心,当系统开始正常运行,对需要用到的GPIO口、系统时钟、串口、小灯、按键、蜂鸣器、LCD进行初始化。开启中断服务函数,加载LCD_display()函数,展示系统欢迎界面,扫描Key键,可以选择通信模式、配置模式和深度睡眠模式,当选择进入通信模式时,将LoRa模块的M0=0,M1=0,开始从串口3接收数据,将接收的数据存在BUFF变量中,根据通信格式解析数据,分析数据是否存在丢失,如果存在丢失则重新获取数据,数据正确后将有效数据进行处理显示在LCD上,同时通过串口1与电脑进行通信,将数据传输给电脑,电脑通过串口通信软件将数据打印处理。同时加载Warning()函数,当接收的数据出现异常时,温度大于40摄氏度,二氧化碳浓度大于1500ppm,TVOC浓度大于50ppb,就会驱动蜂鸣器响起,提示环境数据异常。可以通过按键或者上位机传输的数据对系统工作模式进行转换。
2.LoRa程序 网关和LoRa的通信是通过串口3完成的,从串口3读取数据后,网关需要对数据进行进一步的处理。根据选择的系统工作模式来控制LoRa的工作状态,一开始默认工作在通信状态,此时LoRa的M0=0,M1=0。通过接收从上位机和网关按键选择来改变M0、M1的高低电平,从而达到LoRa工作状态的改变。LoRa将获取到的数据存在串口3的数据寄存器,对该部分数据进行校验,如果发现错误则清空数据寄存器重新接收,数据校验成功则给MCU做进一步处理。同时LoRa模块也可以接收来自MCU的数据进行发送。
3.串口1程序 串口1主要完成上位机和网关的通信,在串口3从LoRa模块获取正确的数据后,便通过串口1将该数据发送给上位机,上位机通过串口通信软件接收到数据,并将接收到的数据打印出来。同时在上位机也可以向串口1发送数据,按照通信格式发送数据控制系统工作模式,通信格式的第一个字节(8位)为数据起始位,第二个字节为系统工作模式控制位,同样也为8个位,1个字节。当控制位为0x01时,MCU将LoRa的M1引脚置为0,M0引脚置为0,可以正常通信。当控制位为0x02时,MCU将LoRa的M1引脚置为1,M0引脚置为0,LoRa进入配置模式,此时可以在上位机通过E22配置软件进行参数配置。当控制位为0x03时,MCU将LoRa的M1引脚置为1,M0引脚置为1,系统进入深度睡眠模式,只有在确定在较长时间内不使用才选择进入该模式,退出该模式LoRa模块会重新进行参数配置。
4.LCD显示程序 LCD显示屏提高了网关的实用性,在没有连接上位机的情况下,也能实时显示接收到的数据,并且还能通过按键选择LoRa的工作模式。LCD显示使操作数据可视化,提高了便捷性。由于显示需要汉字,所以需要加载汉字字库,其字库存在FLASH。汉字字库为GBK编码。
先进行初始化,初始化GPIO口、FSMC、LCD序列和汉字字库,设置为竖屏显示,此时背光点亮,显示主界面,设置变量N,通过按键可以改变N的值,设置坐标,获取显示的数据,用软件将显示的数据转化成LCD显示坐标,当变量N等于0,指针指向进入通信模式,等于1指向进入配置模式,等于2指向进入深度睡眠模式,当监测到KEY_UP被按下,则显示对应模式的界面。当进入通信模式时,LoRa处于通信模式,LCD就开始显示字符,该字符从MCU的BUFF的获取,为校验过的数据,当监测到KEY2键按下则返回主界面。当进入深度睡眠模式时,控制MCU向LoRa发送进入深度睡眠模式控制字,LoRa将其发送,等待传感器节点的接收,之后整个系统进入深度睡眠模式。切换模式可以唤醒,传感器节点需要重启才能唤醒。
五.传感器节点程序 1.传感器节点一主程序 主程序先进行硬件的初始化,SPG-30开启需要一定的时间,所以在这段初始化时间内将会发送正在“正在监测中的”的数据,指示网关需要等待数据。SPG30数据的前8位为二氧化碳浓度值,后8位为TVOC浓度值。由于SPG没有完成初始化时传回的数据一直为二氧化碳浓度400,TVOC浓度0,所以当同时收到二氧化碳浓度为400并且TVOC浓度为0时,表示未初始化完成,芯片重新向SPG30读取数据。芯片向DHT11读取数据,向SPG30读取数据,将接收到的数据通过LoRa发送,当LoRa处于空闲状态时,便将数据进行传输,否则等到LoRa空闲。
2.传感器节点二主程序流程图 传感器节点二的主程序主要完成光照传感器数据的读取和LoRa数据的发送,该节点由51单片机进行控制,主程序先进行串口初始化,BH1750初始化和LoRa初始化。初始化串口时,设置串行口控制寄存器允许接收8位数据,向BH1750写入0x01控制字,打开其电源,之后写入0x10控制字,进入H分辨率模式,读取光照传感器的数据,存储在BUFF中,将该数据校验处理后发送给LoRa,当LoRa处于空闲状态时,便将数据进行传输,否则等到LoRa空闲。
3.温湿度传感器程序 温湿度传感器首先完成初始化,在这个过程中初始化PA15IO口,禁用JTAG功能,当接收到来自MCU读取数据的命令,先将DHT11进行复位,复位后检测DHT11是否响应,当响应成功返回0,此时开始连续读取数据,高电平返回1,低电平返回0,连续读取40位,5个字节,前两个字节表示温度数据,后两个字节表示湿度数据,最后一个字节表示校验,完成读取数据后判断获取的数据和校验数是否一致,一致则将读取的数据存在BUFF,否则将数据丢弃。
4.气体传感器程序 先将SPG30初始化,在这个过程中完成PB0和PB1的初始化。由于控制字的写入需要用到I2C,所以需要先产生I2C起始信号,电平从高变低,钳住I2C总线,准备发送或接收数据,完成IIC起始信号。之后向SPG30发送控制字0x2003,表示初始化接收空气质量,完成SPG30的初始化。向SPG30发送控制字0x2008,表示测量数据,前两个字节表示二氧化碳浓度,后两个字节表示TVOC浓度,同时还会发送一个CRC校验数据,当CRC校验成功则接收,MCU从PB0读取数据,否则将数据丢弃。SGP30模块开机需要一定时间初始化,在初始化阶段读取的CO2浓度为400ppm,TVOC为0ppd且恒定不变,因此上电后每隔一段时间读取一次,直到读取的数据不为上述值,获取的数据则为正常数据,读取完数据,IIC总线信号停止。
5.光照传感器程序 GY-30光照传感器接收来自51单片机的命令,做出相应的反应,BH1750先进行初始化,由于GY-30与MCU是通过IIC进行数据传输,所以先让IIC产生起始信号,先置SDA和SCL为高电平,之后为低电平,当接收到来自MCU的指令时,便根据相对应的指令执行操作。光照环境测量采用连续H分辨率模式,当收到MCU发送的控制字0x10,发送“连续h分辨率模式”指令(0x46),等待测量结束后,发送“读取数据”指令(0x47),读取完数据后将数据存在BUFF,等待MCU的处理,读取完毕便停止IIC信号。
6.LoRa程序 传感器节点1和传感器节点2的LoRa功能都是一样的,其M0、M1、AUX由MCU控制,通过MCU输出高低电平来改变工作模式,AUX返回LoRa的工作状态。当接收到MCU发送的数据时,在LoRa空闲的情况下便将读取MCU的数据,将其进行传输。LoRa同时也可以接收来自中心网关的信号将其传输给节点MCU。
六.测试与验证 1.代码的调试与下载 在Keil进行程序的编写后,需要将编译好的代码下载到单片机中,其中STM32F103ZET6使用ST-LINK进行下载,并且可以使用SWD进行调试,在KEIL中配置好ST-Link Debugger后,将ST-Link连接电脑和网关的JTAG,即可进行代码的下载。
由于STM32F103C8T6提供了HUSB,因此用数据线就可以进行代码下载,在下载前将boot0设置为高电平,boot1设置为低电平,进入WCHISPTool软件,选择32位CH32F1系列,将编译好的HEX文件导入,即可完成程序的下载。
对于STC89C52RC则选择USB转TTL下载,将USB转TTL的TX换个RX接口与芯片相连,软件选择STC-ISP,将编译好的HEX文件导入,同时将单片机重新启动,程序就会自动下载,。
2.LoRA模块的配置 系统进入配置模式后,此时LoRa模块的M1引脚为1,M0引脚为0,连接上位机打开E22配置软件,将该系统所有的LoRa模块波特率设为9600,奇偶校验选择奇校验,空中速率选择1.2Kbps,信道等均设置相同,让LoRa模块M1引脚置位0则可进入通信模式,模块间可以正常收发数据。
3.上位机通信 传感器节点放在较远处获取环境数据,中心网关连接电脑读取数据,节点与网关之间采用星型组网的方式,两个传感器节点获取周围的温度、湿度、二氧化碳浓度、TVOC浓度、光照强度。电脑上使用串口通信助手获取网关的数据,并可以通过串口1向网关发送数据。
传感器将获取的环境数据传输给中心网关,中心网关将数据进行处理后将数据发送给上位机。
当网关和电脑连接时,使用串口通信助手进行双向串口通信,当搜索到串口后,打开串口,设置波特率为9600,校验位为奇校验,在串口通信助手可以选择暂停接收数据或者继续接收数据,同样也可以在数据发送区发送数据改变系统工作状态。系统的工作状态分为三种,一种是配置模式、一种是通信模式,一种是深度睡眠模式,分别由控制字0x02,0x01,0x03决定,控制字由上位机发送。
将该系统上电,系统正常运行,通过串口传输助手发送控制字0x01切换系统进入通信模式,传感器节点收到信息也进入通信模式,初始化传感元件,数据经过校验后通过LoRa发送给网关,网关将接收的数据进行校验,校验码正确则将数据进行进一步处理,然后将数据发送给上位机,上位机接收的数据如下,获取的数据与实际情况相符合。
4.网关控制 当上位机不在的时候,也可以通过网关的显示屏来显示当前获取的数据,提高了网关的实用性。此时可以通过按键来选择当前系统工作模式。系统欢迎界面展示按键的功能如图 ,其中KEY0表示下一个,KEY1表示上一个,WK_UP表示确定/取消。欢迎界面有三种模式,一种是通信模式,一种是配置模式,一种是深度睡眠模式。
选择进入配置模式如图 ,此时LoRa的M1和M0引脚分别为1,0,将USB转TTL的RX连接LoRa的TX,串口1的TX连接LoRa的RX,打开上位机配置软件即可对LoRa进行参数配置。进入通信模式如图,将接收到的数据在LCD上进行展示,比较直观,显示的数据和在上位机上接收的数据是一样的,并且还对当前环境数据做出判断,目前环境数据正常,当出现异常时蜂鸣器就会响起。进入深度睡眠模式如图,在该模式下系统的接收和发送功能均关闭,此时LoRa无法接收和发送所有的数据,在不需要数据传输时进入该模式,可以保持系统以较低的功耗运行,当进入特定模式时按KEY2可以退出,当网关LoRa从深度睡眠模式退出时,需要重新配置参数,此时AUX返回0,需要等待一定时间才能接收数据。传感器节点退出深度睡眠模式则需要重启设备,重新运行LoRa初始化函数进入通信模式。
前言 本次实践旨在提高自己在以下方面的动手能力:
Spring,SpringMVC,SpringBootMybatis,MybatisPlusIO,并发式编程 因此,在原有项目需求上,会有以下方面的额外考量:
参照Spring,SpringBoot的面试难题,为项目设计“炫技点”综合运用XML,注解以及MybatisPlus三种方式,实现数据库读取引入对IO的操作以及并发式编程 如果读者也有类似的想法,不妨继续读下去
正文 项目共分为两期:
一期:根据H5设计的前端实现客户端服务器功能,根据管理页面实现管理端服务器功能二期:移植H5前端至微信小程序,将登陆验证由手机号+验证码改为微信验证 一期工程中,客户端服务器的主要功能有:
登录功能 用户发起验证码请求 请求数据:手机号响应数据:6位验证码PS1:验证码存于Redis中,TTL为60s,key为手机号,value为验证码 用户发起登录请求 请求数据:手机号+验证码响应数据:tokenPS1:token存于Redis中,TTL为30min,key为token,value为手机号PS2:token的存入位于数据库操作(读取用户信息,不存在则创建)后,两者进行事务管理保证一致性 菜品浏览 获取分类信息 请求数据:无响应数据:Result. <List>分类条目 获取购物车信息 请求数据:无响应数据:Result. <List>购物车条目 获取菜品信息 请求数据:{分类ID, Status}响应数据:Result. <DishList>菜品条目 获取套餐信息 请求数据:{分类ID, Status}响应数据:Result. <DishList>套餐条目 购物车 添加点餐条目 请求数据:<DishParams>购物车条目响应数据:Result. 无特殊Data 修改点餐条目 请求数据:<DishParams>购物车条目响应数据:Result. 无特殊Data 删除点餐条目 请求数据:<DishDeleteParams>购物车条目响应数据:Result. 无特殊Data PS1:购物车条目信息存于Redis,TTL为30min 下单 提交订单 请求数据:<OrderParams>订单条目响应数据:Result. 无特殊Data 拦截功能 登录状态拦截 请求数据:token响应数据 :对应请求或拦截 省略部分 地址历史订单 // DishParams let params = { amount:item.price/100,//金额 dishFlavor:item.dishFlavor,//口味 如果没有传undefined dishId:undefined,//菜品id setmealId:undefined,//套餐id name:item.name, image:item.image } // DishDeleteParams let params = { dishId:item.
报错问题如下:
出现这这种情况的多半是core-js的版本不对;
解决方案如下,亲测多次有效:
1、安装cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org 2、查看cnpm是否可用
cnpm -v 3、重新下载core-js的版本
cnpm install core-js@2 OK,就这样,End~
当一台服务器上部署多个Tomcat时,默认都会使用环境变量中配置的JDK版本
其中有些项目可能需要其他版本的JDK,这时候可以为Tomcat单独指定JDK版本,而不用修改环境变量中配置的JDK版
只需要修改Tomcat中bin目录下的 catalina.sh 和 setclasspath.sh 文件,在文件开头的空白处添加如下两行:
export JAVA_HOME=/usr/local/java/jdk1.8.0_351 export JRE_HOME=/usr/local/java/jdk1.8.0_351/jre
情绪定量模型的连续维度类型。 区分情绪状态的边界是模糊的,状态的变化和演变是连续的,没有断点。将情绪状态划分为十二种离散类型只能显示情绪的主要方面,并在精确量化情绪状态下失败。此外,在各种文化和国籍之间,离散的情感标签并不一致。例如,我们无法找到波兰语中的相应翻译,以表达“厌恶”的情感。因此,提出了情绪定量方法的连续维度类型。这种量化方法使用了几个相互正交的基本轴来显示情绪的不同维度,这解决了离散量化方法与丰富的情感内涵之间的矛盾。 Russell提出了价值双相情感象限系统,该系统已在有效的计算中被广泛接受。如图1(a)所示,价值和唤醒的经典两个维度用于描述价水平和唤醒情绪水平。
(A)和相应的自我评估Manikin量表(B)提出的价值 - 正极双极坐标系。
从正到负的价值轴的值(或评级)是指个人快乐和悲伤的程度的测量。同样,唤醒的正值表示活化状态(兴奋),而负值表示未激活状态(平静)。除了两个标准的基本轴外,还可以添加更多的尺寸以进行全面的情绪测量。优势维度代表了情感过程中个人的主要控制程度。当外部环境控制用户时,情绪状态处于较低的优势水平(例如,惊喜,恐惧等)。相反,当用户可以掌握外部环境时,情绪状态处于较高的优势水平。应该指出的是,各种离散的情绪状态可以将其定位到具有一对一信件的连续维状态空间中的特定位置。例如,悲伤的情绪位于连续情感坐标系统中的低唤醒统治地位 -低价坐标空间中,而幸福情绪则位于高唤醒高的统治高价值坐标空间中。评估连续情绪状态的广泛采用的方法是基于量表的自我评估Manikins(SAM)方法。 SAM的设计是通过将Manikins引入问卷中以视觉评估价和唤醒的程度。 数据简单介绍: DEAP(Database for Emotion Analysis usingPhysiological Signals),该数据库是由来自英国伦敦玛丽皇后大学,荷兰特温特大学,瑞士日内瓦大学,瑞士联邦理工学院的Koelstra 等人通过实验采集到的,用来研究人类情感状态的多通道数据,可以公开免费获取。该数据库是基于音乐视频材料诱发刺激下产生的生理信号,采集了32名(16名男性和16名女性)健康参与者的脑电数据。参加实验的人身体和心理都是健康状态,按照“10-20”国际导联标准的 32 导联(见电极分布图)电极帽采集脑电信号。志愿者被要求观看40个时长为一分钟的视频,并在 512Hz 采样频率下采集被试者的 EEG 信号。其中不止包含32个脑电通道,还包含了16个其他通道,其中包括眼电、心电等常见信号。所有被试均被要求在观看完视频后,按照从 1~9 的大小关系,标记所观看视频的 Valence(效价)、Arousal(唤醒度)、Dominance(优势度)的大小。(上面有具体介绍) 数据集的简单预处理: 生理信号采用512Hz采样,128Hz复采样(官方提供了经过预处理的复采样数据)每个被试者的生理信号矩阵为40408064(40首实验音乐,40导生理信号通道,8064个采样点)其中40首音乐均为时长1分钟的不同种类音乐视频,40导生理信号包括10-20系统下32导脑电信号、2 导眼电信号(1导水平眼电信号,1导竖直眼电信号)[眼电信号EOG]、2导肌电信号(EMG)、1导GSR信号(皮电)、1导呼吸带信号、1导体积描记器、1导体温记录信号。8064则是128Hz采样率下63s的数据,每一段信号记录前,都有3s静默时间。
据一般选取官网可下载的预处理( 降采样,去除眼电等噪声) 之后的数据(两个版本:data_preprocessed_matlab文件夹和data_preprocessed_python文件夹,即matlab和python处理后的,格式分别为.mat和.dat),实验数据由32个文件组成。对应32个实验受试者每个参与者文件包含两个数组。
做了几个项目之后,发现经常用的几个控件每次都需要设置样式,而且每次都是翻以前的项目样式粘贴复制,很麻烦,还不如直接统一做一下笔记,以后直接粘贴复制得了。省得东找西找。
QPushButton按钮 //QPushButton样式表 QPushButton{ background:#525253; border-radius:4px; color: #ffffff; font:bold; font-size:15px; } QPushButton:hover{ background:#2d96dc; border:3px solid white; } QPushButton:pressed{ background:#2d96dc; border:3px solid white; } QPushButton:checked{ background:#2d96dc; border:3px solid white; } //如果想弄出按下有下划线的感觉的话,然后按钮的背景颜色通常都是设置为透明 QPushButton:checked{ background:#transparent; border-bottom:3px solid #1C80FF; } //如果QPushButton用到了图片作为背景的话,那么border-radius:和border:就算设置了也不起作用 QPushButton{ border-image:url(:/image/pic.png); } //如果想调整控件大小 QPushButton{ min-height:20px; min-width:20px; max-width:50px; max-height:50px; } 效果如下
QSlider滑动条 /*滑动条*/ #滑块还没有滑到的部分 QSlider#volumeSlider::groove:horizontal{ height:6px; margin-left:3px; margin-right:3px; border-radius: 3px; background:rgba(180,180,180,100%); } #滑块手柄样式 QSlider#volumeSlider::handle:horizontal{ width: 12px; min-height: 12px; margin-top:-3px; margin-bottom:-3px; margin-left:-3px; margin-right:-3px; border-radius: 6px; background:rgba(255,255,255,100%); } #滑块已经划过的部分 QSlider#volumeSlider::sub-page:horizontal{ height:6px; margin-left:3px; margin-right:3px; border-radius: 3px; background:rgba(0,164,255,100%); } margin-bottom:-3px;//表示除了占满滑条外,往下增加3px高度 margin-bottom:3px;//表示向内缩窄3px 效果如下:
刚开始使用WSL方式进行开发,记录一下开发环境自启动方式
创建启动脚本:
进入任意 WSL 发行版中,创建并编辑文件:/etc/init.wsl
#! /bin/sh /etc/init.d/nginx $1 /etc/init.d/mysql $1 /etc/init.d/php7.4-fpm $1 /etc/init.d/redis-server $1 /etc/init.d/supervisor $1 里面调用了我们希望启动的三个服务的启动脚本,设置权限为可执行,所有者为 root,这时候可以通过:
sudo /etc/init.wsl [start|stop|restart] 来启停我们需要的服务,在 Windows 中,开始-运行,输入:
shell:startup 按照你 WSL 使用的 Linux 发行版创建启动脚本,比如我创建的 Ubuntu2204.vbs 文件:
Set ws = CreateObject("Wscript.Shell") ws.run "wsl -d Ubuntu-22.04 -u root /etc/init.wsl start", vbhide 这个脚本就会在你登陆的时候自动在名字为 “Ubuntu-22.04” 的 wsl 发行版中执行 /etc/init.wsl 启动我们的服务了,如果你用的是 debian 的发行版,那么修改上面脚本里的 Ubuntu22.04 为 debian :
Set ws = CreateObject("Wscript.Shell") ws.run "wsl -d debian -u root /etc/init.
现有3个表,分别为student(sid, name),course(cid, name),student_course(sid, cid, score)。
要求查询各个课程的最高分、第二高分、最高分人数,查询的结果有5个属性,分别为cid, name, max_score, max_score2, max_score_count。此题查询代码如下。
select cid,name, (select max(t1.score) from student_course t1 where t1.cid =t0.cid)max_score, (select max(t2.score) from student_course t2 where t0.cid =t2.cid and score not in (select max(t1.score) from student_course t1 where t1.cid =t0.cid))max_score2, (select count(distinct sid) from student_course t1 where t1.cid =t0.cid and t1.score = (select max(t1.score) from student_course t1 where t1.cid =t0.cid)) max_score_count from course t0 这种思想主要为,select查找的每一个属性都是一个单独的关系,因此将嵌套子查询用在select中。
最外层的查询为
select cid, name from course t0 这也是最核心的约束,即查询结果的cid和name先说好在course里找,用t0来表示最外层查询的表,并进一步用来约束内部的查询。
在联想GeekPro 2022上安装了ubuntu18.04系统,GeekPro 2022上的有线网卡和无线网卡都是realtek的,其中无线无线网卡的型号为RTL8852BE。安装好系统后,发现并没有有线无线网络图标,无法上网。原因是两个网卡驱动与当前的网卡不匹配,需要重新手动代码编译安装。安装步骤如下:
目录 安装显卡驱动查看网卡型号安装有线网卡驱动安装有线网卡将会遇到的问题安装无线网卡驱动 安装显卡驱动 显卡驱动的安装方法可参考链接: https://zhuanlan.zhihu.com/p/59618999 的方法一。这里一定要先安装显卡驱动,显卡的安装过程中,会删除已经安装好的网卡驱动,这样的话,还要再重新安装一次网卡驱动,所以最好第一步就先安装网卡驱动,网卡驱动需要的网络连接,连接方法在 安装有线网卡驱动目录的1.1和1.2。
查看网卡型号 1.使用命令
lspci | grep -i Ethernet
结果如下
2.查看网卡驱动
lspci -vvv
显示网卡驱动并不是需要的r8125
3.去realtek下载 r8125 的驱动
链接: 驱动下载
下载下面这个
安装有线网卡驱动 1.下载编译需要的工具
首先目前的主机是没有网络的,首先解决网络的问题
1.1 使用手机的usb网络共享,把手机的网络共享给现在的ubuntu
1.2 使用usb转网口的转接头(我使用的这个,身边刚好有一个)
需要下载编译工具包build_essential
sudo apt-get install build_essential
2.安装
解压并进入目录,运行
sudo ./autorun.sh
理论上来说,这样做是会失败的。按照下面的步骤来一个一个解决问题
安装有线网卡将会遇到的问题 这里参考了链接: https://blog.csdn.net/tanmx219/article/details/122754753
主要是:
1.openssl证书问题
首先下载可通过sudo apt-get install安装
之后
cd /lib/modules/$(uname -r)/build/certs sudo tee x509.genkey > /dev/null << 'EOF' [ req ] default_bits = 4096 distinguished_name = req_distinguished_name prompt = no string_mask = utf8only x509_extensions = myexts [ req_distinguished_name ] CN = Modules [ myexts ] basicConstraints=critical,CA:FALSE keyUsage=digitalSignature subjectKeyIdentifier=hash authorityKeyIdentifier=keyid EOF sudo openssl req -new -nodes -utf8 -sha512 -days 36500 -batch -x509 -config x509.
Python-3.1使用OpenCV人脸对比 提示:实验示例,仅供参考
Python:下载地址
IDEA Python:下载地址
Open CV:官网
目录 Python-3.1使用OpenCV人脸对比前言一、安装OpenCV环境准备 二、使用OpenCV新建项目创建目录Python全代码 总结 前言 随着人工智能的不断发展,机器视觉越来越重要,如下介绍Opencv中人脸对比应用,采用自训练模型方式,对期望人脸获取置信度。
一、安装OpenCV 环境准备 打开Pycharm,点击右上角File,选中Settings
搜索,opencv-python,然后点击左下角,Package Install
搜索,numpy,然后点击左下角,Package Install
搜索,opencv-contrib-python,然后点击左下角,Package Install
二、使用OpenCV 新建项目 创建目录 imgs 用于存放需要识别的图片,目录中存放训练图片(1.jpg,2.jpg,copy_5.jpg.jpg),存放测试图片(5.jpg)
Python全代码 本实例copy_5.jpg 来源于 5.jpg进行灰度后保存
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*- import cv2 import numpy as np images = [] # 定义统一宽高 width = 300 height = 300 # 重置图片大小,对比需要; 置灰度,提高效率 image1 = cv2.resize(cv2.imread("imgs/1.jpg", cv2.IMREAD_GRAYSCALE), (width, height)) image2 = cv2.
如果项目中文件夹中显示某个文件,但是AndroidStudio中不显示,一般的情况下是进行了忽略处理。如果想显示出来可以把忽略进行移除。
Android项目提交代码时一般忽略的文件:
1、.idea文件夹
2、所有的build文件夹
3、所有的.iml文件
4、local.properties文件。
方式一:版本3.6之前 File >>> setting >>> version control >>> ignored file
版本3.6之后 File ->setting->editor->File Types
版本Arctic Fox (Patch 3):
File ->setting->editor->File Types(Ignoreed Files and Folders)
(点击加号增加忽略的文件或者文件夹,红框内为新增内容)
系统 Ubuntu 20.04阿里云端口 5433 以及 5432 都开了 问题产生 使用 sudo apt-get install postgresql 之后使用 systemctl 打开SQL服务。
指令 psql --version 验证安装,发现如题错误。
检查及修复 ps aux | grep post 发现没有回应,立即认为是出现了安装错误。
于是再次检查 sudo apt-get update 发现报错
N: Skipping acquire of configured file 'main/binary-i386/Packages' as repository 'http://apt.postgresql.org/pub/repos/apt focal-pgdg InRelease' doesn't support architecture 'i386' 于是修改文件 /etc/apt/sources.list.d/pgdg.list
将其修改为
deb [arch=amd64] http://apt.postgresql.org/pub/repos/apt focal-pgdg main 再次 apt-get update 发现没有错误,后续按照教程重新安装即可
文章目录 1.可调用对象1.1 函数指针1.2 函数对象1.3 可被转换为函数指针的类对象1.4 类成员函数指针 2.std::function2.1 包装普通函数2.2 包装函数指针2.3 包装函数对象2.4 包装可被转换为函数指针的类对象2.5 包装类的静态成员函数2.6 包装类的非静态成员函数 3.std::bind()3.1 绑定普通函数3.2 placeholders占位符3.3 绑定函数对象3.4 绑定类的成员函数 4.std::bind()和std::function配合使用 1.可调用对象 1.1 函数指针 #include <iostream> using namespace std; void fun(int v) { cout << "fun()函数执行了,v = " << v << endl; } int main() { void(*pfun)(int) = fun; pfun(15); return 0; } 1.2 函数对象 仿函数是一个重载了 operator() 运算符、能行使函数功能的类,这个类也称为函数对象类,这个类的对象就是函数对象。
函数对象本质上是一个对象,但其使用形式看起来和函数调用一样,因而得名。
#include <iostream> using namespace std; class TC { public: void operator()(int tv) // 函数调用运算符 { cout << "
场景 我们在一些特殊的业务场景下,想要获取到下一个工作日,这里的工作日指正常的法定工作日(包含调休日),这个需求来源于银联的提现,银联只能在法定工作日才能体现,那么在业务代码里对提现日期必须就是工作日即可,在查询了相关的信息,目前没有稳定的API或者三方付费的稳定API,那么这个需求其实不难处理,自己也可以动手维护一套WorkingHolidayAPI的,那么我就以Springboot简答举例写出重要的环节。
文章目录 场景代码Springboot单元测试原理优化项 总结 代码 关键工具:
import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.Week; import java.util.*; import java.util.concurrent.ConcurrentHashMap; public class WorkingHolidayUtil { private static final int DEFAULT_YEAR_DAY = 365; private Map<Integer, WorkingHoliday> whMap; /** * 创建时间 */ private Date createTime; /** * 起始日期 */ private Date startDay; /** * */ private int offDay; /** * 权重比例 * */ private int[] WEIGHT_ARR = {10000, 100, 1}; public WorkingHolidayUtil(List<WorkingHolidayEntity> data, Date startDay, int offDay) { if (data.
目录
OSPF的三张表:
邻居和邻接关系:
OSPF邻居关系的建立过程:
邻接关系建立的详细过程:
指邻居:
OSPF支持的网络类型:
OSPF路由器类型:
OSPF的三张表: OSPF有三张重要的表项,OSPF邻居表、LSDB表和OSPF路由表。
对于OSPF的邻居表,需要了解:
1.OSPF在传递链路状态信息之前,需先建立OSPF邻居关系。
2.OSPF的邻居关系通过交互Hello报文建立。
3.OSPF邻居表显示了OSPF路由器之间的邻居状态,使用display ospf peer查看
对于OSPF的LSDB表,需要了解:
1.LSDB会保存自己产生的及从邻居收到的LSA信息。
2.Type标识LSA的类型,AdvRouter标识发送LSA的路由器。
3.使用命令行display ospf lsdb查看LSDB表
type有七类: 一类、二类、三类、五类、四类、七类 ,advR:是通告路由器,即谁发的 。
OSPF路由表
使用display ip routting-table 这条命令查看到的路由表叫做是实际路由的转发表,即路由器是主要依据这个表进行数据转发。
OSPF路由表中只有通过OSPF协议学到的路由信息,但不是转发表。
对于OSPF的路由表,需要了解:
1.OSPF路由表和路由器路由表是两张不同的表项。
2.OSPF路由表包含Destination、Cost和NextHop等指导转发的信息。
3.使用命令display ospf routing查看OSPF路由表。
邻居和邻接关系: 邻居关系和邻接关系:所有OSPF路由器之间的关系都是邻居关系,但只有部分路由器之间的关系是邻接关系。
邻居关系的形成:
OSPF邻居关系的建立过程: 1、运行OSPF协议的路由器在启动后会主动向外发送一个Hello报文(第1个)
Hello中包含(自己的RID,邻居的RID为空的)
2、当邻居也运行的是OSPF在收到发来的Hello后,会将自己状态从原始Down转换为Init,并向邻 居也发送第一个Hello报文
3、当运行OSPF协议的路由器在收到邻居发来的第一个Hello报文后会将自己状态从Down转换为 Init
4、先转换为Init状态的路由器发现自己的RID不在邻居发来第一个Hello报文中,这时,会发送第二 Hello报文 Hello报文中包含(自己RID,邻居的RID)
5、邻居路由器在收到后也会发送第二个Hello报文
6、当收到邻居发来的Hello报文中包含自己的RID时,会将自己的状态从Init转换为2-Way,这时两 台路由之间就形成了邻居关系。
邻接关系的形成:
邻接关系建立的详细过程: 路由器在建立完成邻居关系之后,根据路由器角色便开始进行数据库同步过程,具体如下:
第一次DD用于选主从:
1、邻居状态变为ExStart以后,发送第一个DD报文,在这个报文中,DD序列号被设置为X(任 意),并假设自己为主路由器。
2、互相发送完第一个DD报文后会比较Router ID的大小,大的为真正的主路由器Master,次大 的为Slave。
第二次真正交互DD报文
3、在主从确定后,从路由器会发送一个新的DD报文,这个新的报文中包含LSDB的摘要信 息,序列号设置为主路由器第一次使用的序列号,并将自己的状态从Exstart转换为Exchange, 主路由器在收到从路由器发来新的DD报文后将邻居状态改变为Exchange。
4、当主路由器邻居状态变为Exchange以后,主路由器会发送一个新的DD报文,该报文中包含 LSDB的描述信息,收到DD报文序列号不变(上次使用的序列号)。
问题描述: 给定一个对象:
let myObject = { "ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*" }; 如何删除属性 regex 以得到以下 myObject?
let myObject = { "ircEvent": "PRIVMSG", "method": "newURI" }; 解决方案1: huntsbot.com汇聚了国内外优秀的初创产品创意,可按收入、分类等筛选,希望这些产品与实践经验能给您带来灵感。
要从对象中删除属性(改变对象),您可以这样做:
delete myObject.regex; // or, delete myObject['regex']; // or, var prop = "regex"; delete myObject[prop]; 演示
var myObject = { “ircEvent”: “PRIVMSG”, “method”: “newURI”, “regex”: “^http://.*” };删除 myObject.regex;控制台.log(myObject);
对于有兴趣了解更多相关信息的任何人,Stack Overflow 用户 kangax 在他们的博客 Understanding delete 上写了一篇关于 delete 声明的非常深入的博文。强烈推荐。
如果您想要一个 new 对象,其中包含除一些之外的所有原始键,您可以使用 destructuring。
一、对象头的结构(32位虚拟机) 1、普通对象 普通对象头占用64 bits ,其中Mark word占32 bits ,Klass Words 占32bits。Klass Words 可以理解为指针,指向类对象。Mark Word下面会详解。
2、数组对象 数组对象增加了4个字节的空间,用于存储数组长度。
二、Mark Word介绍 1、Mark Word结构 对象在不同情况下的结构会有所不同, 参考以下表格:
32位虚拟机Mark Word 64位虚拟机Mark Word 2、Mark Word 不同状态 1、Normal状态:此状态为普通状态,hashcode为对象的hashcode值 , age代表垃圾回收的分代年龄, biased_lock表示是否为偏向锁,最后两位代表加锁状态。
2、Biased状态:此状态为偏向锁状态,thread指向获得偏向锁的线程,后3位为101表示对象为偏向锁状态。
3、Lightweight Locked状态:轻量级锁状态,ptr_to_lock_record指向栈帧的锁记录。
4、Heavyweight Locked状态:重量级锁,ptr_to_heavyweight_monitor指向Monitor。
注意: 1、当开启偏向锁时(默认开启),创建一个对象,对象的Mark Word为偏向锁状态,偏向锁是默认延迟的,不会在程序启动时立即生效。 2、当禁用偏向锁时,创建的对象为普通状态,即使该对象被synchronized修饰,也不会变为偏向锁状态。 3、如果对象调用hashcode方法,会自动禁用偏向锁,是因为偏向锁的对象头中没办法存储hashcode。轻量级锁把Mark Word的值存放在栈帧中,重量级锁把Mark Word的值存放在Monitor中。 三、Monitor介绍 Monitor 是监视器的意思,在Java中被synchronized关键字修饰的对象头且为重量级锁时,会关联一个Monitor对象,Monitor有Owner、EntryList、WaitSet三个字段,分别表示Monitor的持有者线程(获得锁的线程)、阻塞队列、和等待队列。如下图:
上图的情况下,MarkWord状态应为heavyweight Locked,ptr_to_heavyweight_monitor占用30位指向Monitor对象。Thread-2为Monitor的持有者,因此Thread-2是获得锁的线程,其它争抢锁的线程进入阻塞队列中。
注意:不加synchronized关键字的对象,是不会关联Monitor对象的。只有重量级锁对象才会关联Monitor。
什么是pg_hba文件? HBA全称是host-based authentication(基于主机的认证)。在initdb初始化数据目录时,它会在PG数据目录下安装一个默认的pg_hba.conf文件。pg_hba.conf默认路径是/var/lib/pgsql/<pg_version>/data
[root@node01 vagrant]# ps -ef|grep postgres postgres 22899 1 0 16:48 ? 00:00:00 /usr/pgsql-11/bin/postmaster -D /var/lib/pgsql/11/data/ [root@node01 vagrant]# ll /var/lib/pgsql/11/data/pg_hba.conf -rw-r--r--. 1 vagrant vagrant 911 Dec 6 16:48 /var/lib/pgsql/11/data/pg_hba.conf pg_hba.conf中每条记录指定一种连接类型、一个客户端 IP 地址范围(如果和连接类型相关)、一个数据库名、一个用户名以及对匹配这些参数的连接使用的认证方法。第一条匹配连接类型、客户端地址、连接请求的数据库和用户名的记录将被用于执行认证。这个过程没有“落空”或者“后备”的说法:如果选择了一条记录而且认证失败,那么将不再考虑后面的记录。如果没有匹配的记录,那么访问将被拒绝。
记录格式一般是:
TYPE DATABASE USER ADDRESS METHOD 各个域的具体含义参考http://www.postgres.cn/docs/14/auth-pg-hba-conf.html
常用配置 # 允许本地系统上的任何用户 # 通过 Unix 域套接字以任意 # 数据库用户名连接到任意数据库(本地连接的默认值)。 # # TYPE DATABASE USER ADDRESS METHOD local all all trust # 相同的规则,但是使用本地环回 TCP/IP 连接。 # # TYPE DATABASE USER ADDRESS METHOD host all all 127.
数据结构-图-思维导图 1 数据结构-第六章-图-思维导图2 知识点小结 1 数据结构-第六章-图-思维导图 数据结构-第六章-图-思维导图缩略图展示如下图1所示:
图1 2 知识点小结 1、邻接矩阵、邻接表、十字链表、邻接多重表。
邻接矩阵邻接表十字链表邻接多重表空间复杂度O( ∣ V ∣ | V \vert ∣V∣ 2)无向图O( ∣ V ∣ | V \vert ∣V∣ + 2 ∣ E ∣ | E \vert ∣E∣) 有向图O( ∣ V ∣ | V \vert ∣V∣ + ∣ E ∣ | E \vert ∣E∣)O( ∣ V ∣ | V \vert ∣V∣ + ∣ E ∣ | E \vert ∣E∣)O( ∣ V ∣ | V \vert ∣V∣ + ∣ E ∣ | E \vert ∣E∣)适用于稠密图稀疏图有向图无向图表达方式唯一不唯一不唯一不唯一存储方式顺序存储顺序+链式存储链式存储链式存储 2、BFS(广度优先遍历)、DFS(深度优先遍历)。
递归 git pull --all 所有子文件夹 参考资料 当项目太多时,全都拉取一下,也很麻烦,直接用这个批处理就好了。
:: 解决读取文件内容中文乱码的问题。当前bat需要保存为utf-8 chcp 65001>nul :: 递归遍历当前路径下所有目录,执行 git pull --all :: 2022-11-25 笑虾 @ECHO OFF TITLE 批量 git pull —— 耀眼的笨笨 :: 使用COLOR命令对控制台输出颜色进行更改 COLOR 2f CLS :: 文件夹,拖拽到批处理上即可获取路径。 SET CURRENT_DIR=%~1 :: 如果没有获取到,则获取当前路径 if not defined CURRENT_DIR ( SET CURRENT_DIR=%~dp0 ) ECHO #################################################### ECHO # ECHO # 当前目录: %CURRENT_DIR% ECHO # 开始批量执行 git pull --all ECHO # ECHO #################################################### ECHO. :: dir 递归查询当前目录下所有子目录,每个结果赋给 i :: /b 使用空格式(没有标题信息或摘要,只有名称)。 :: /s 显示指定目录和所有子目录中的文件。 :: /ad a显示具有指定属性的文件, d目录 for /f %%i in ('dir /b /s /ad "
我们在初学Java语言的时候,老师给我们讲的第一个例子往往是用记事本编写打印“Hello World”的程序。当写完程序后,老师一般都会要求我们把源文件的名称命名为与类名相同,比如,类的名称叫A,那么源文件的名称也叫A。很多同学按老师的要求做了,也成功的运行出了“Hello World”。没按老师要求做的,可能连编译都无法成功。于是很多初学者都认为,Java程序的源文件名必须与类名相同,那么真实情况到底是不是这样呢?我们慢慢道来。
Java程序的源文件名与类名之间存在如下关系:
一个Java源文件中可以定义多个类源文件中定义的类,最多只能有一个类被public关键字修饰如果源文件中有被public关键字修饰所修饰的类,那么源文件名必须与public所修饰的类同名。 根据以上规则,我们就明白了:当年老师让我们把源文件命名为与类名相同的名称,其实是因为我们所定义的那个类前面有个public关键字。接下来我们深入研究一下几种特殊情况:
源文件中如果没有public所修饰的类,源文件该如何命名 这个问题其实很简单,如果源文件中没有任何一个类被public关键字所修饰,那么我们可以用任意名称来命名这个源文件,只要源文件的名称符合命名规范就可以了。
一个源文件中如果定义了多个类,编译之后会形成几个.class文件 大家看下图,我们在一个源文件当中定义了3个类,那么编译之后会产生多少个.class文件呢?
经过编译之后,一共产生了3个.class文件。并且这3个.class文件的名称恰好与源文件中3个类的类名相对应。
通过这个实验我们就可以得到一个结论:源文件与编译后的字节码文件的名称和数量其实没有一一对应关系,字节码文件的名称和数量其实是由源文件中类的名称和数量决定的。
主方法必须定义在public类当中吗 有一种说法,认为主方法必须被定义到public类当中才能运行,其实这也是一种讹传。大家看图1,图1当中主方法并没有被定义到public类当中,但是我们照样能通过相应的命令执行这个主方法
通过这篇小短文,我想初学Java的朋友能够彻底弄清楚Java源文件名、字节码文件名以及类名三者之间的关系了吧?
本专栏每篇文章讲解一个知识点,如果想系统学习Java编程可以点击这里观看我在本站的视频课程,也可以订阅我的免费专栏《Java从小白到高手》。
来源需求
项目宣传海报,海报上有项目入口二维码,由于该海报的二维码是实时生成,因此不能用固定的二维码,所以才需要调用后端接口获取到对应的链接,然后转成二维码,最后拼接到海报图上,再进行展示。功能实现
1、由于项目使用的是vue3框架,所以采用qrcode插件将链接转成二维码。文档地址
2、拼接方式则是通过canvas将上一步生成好的二维码按照指定位置绘至海报图上。canvas文档
3、通过json文件配置海报图和二维码位置。
4、支持区分海报类型。(需要在代码中约定好类型枚举值)
5、支持生成多张,使用van-swipe进行滑动切换海报。具体代码 // 模板 <div class="banner" id="banner"> <van-swipe @change="swipeChange" :loop="false" :initial-swipe="bannerIndex"> <van-swipe-item v-for="(img, index) in posterImage" :key="index"> <img :src="img" /> </van-swipe-item> </van-swipe> </div> // 逻辑 const route = useRoute() const productType = route.query.posterType|| '' // 海报类型 const bannerIndex = ref(0) const posterImage = ref([]) const swipe = ref(null) // 监听轮播图 const swipeChange = index => { bannerIndex.value = index } // 核心方法 const canvasPoster = (imgList, code) => { const images = [] const imagesOnload = [] // 海报处理 imgList.
OpenSSH概述 一、OpenSSH概述二、OpenSSH服务程序 一、OpenSSH概述 OpenSSH是基于SSH(secure shell)协议开发的免费开源软件,用于在网络上由一台计算机远程连接另外一台计算机。当用户使用主控端。
OpenSSH提供了服务器端程序和客户端工具,能够加密服务器和客户端之间在远程文件传输过程中的所有数据,从而规避在非安全网络中的窃听、拦截和其他攻击所造成的危害,并由此来代替传统远程控制方式,如FTP、Telnet等。
SSH是建立在应用层基础上的安全协议,是目前较可靠、专为远程登录会话和其他网络服务提供安全性的协议。利用SSH协议可以有效防止远程管理过程中的信息泄露问题。SSH最初是UNIX系统上的一个程序,后来又迅速扩展到其他操作系统。
二、OpenSSH服务程序 【彩蛋来了】 看完作者写的这篇博文,或许读者还想再找找描述类似内容的博文。预料之中,作者已将它们附上,请参见:
通过可视化的方式为VMware虚拟机中配置静态IP,以及DNS服务器 writen in 2022.12.07, updated in 2022.12.07
1. 项目中的登录过滤器在包里面封装 , 没有办法改原有的登录过滤器 , 现在有一个接口不需要校验登录 , 因此需要在进入登录过滤器之前 , 要进入我自己的过滤器 , 将登录过滤器需要的东西放入到request , 从而骗过登录过滤器.
1. 过滤器代码
package cn.com.baidu.message.filter; import org.springframework.stereotype.Component; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; @WebFilter(urlPatterns = "/app/send/*", filterName = "sendFilter") @Component public class SendFilter implements Filter { public SendFilter() { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest)request; MutableHttpServletRequest mutableRequest = new MutableHttpServletRequest(req); // 业务操作 if(req.
关于scrcpy scrcpy是一款针对Android设备的管理和控制工具,该工具可以通过USB或TCP/IP来帮助广大研究人员显示、管理和控制Android设备。该工具不需要root访问权限,支持GNU/Linux、Windows和macOS系统。
工具特性 1、性能:30~120fps,具体取决于设备
2、分辨率:1920×1080或以上
3、低延迟:35~70ms
4、低启动时间:约1秒显示第一个图像
5、非侵入性:Android设备上未安装任何内容
6、工具优势:无需账户,无需广告,无需上网
7、自由&免费:自由和开源软件
功能介绍 1、屏幕录制
2、设备监控
3、剪切板数据拷贝
4、可配置分辨率
5、将Android设备用作网络摄像头
6、物理键盘模拟(HID)
7、物理鼠标模拟(HID)
8、OTG模式
9、其他...
工具要求 API 21+(Android 5.0+)
设备开启ADB调试模式
工具下载 Linux Debian或Ubuntu:
apt install scrcpy Arch Linux:
pacman -S scrcpy Windows 点击【这里】下载scrcpy-win64-v1.24.zip(包含adb在内的所有依赖组件)。
SHA-256:
6ccb64cba0a3e75715e85a188daeb4f306a1985f8ce123eba92ba74fc9b27367 Chocolatey安装:
choco install scrcpy choco install adb Scoop安装:
scoop install scrcpy scoop install adb macOS brew install scrcpy brew install android-platform-tools sudo port install scrcpy 工具运行 将Android设备和你的电脑连接,然后运行下列命令:
scrcpy 该工具支持的命令参数选项可以使用下列命令查看:
作者:几冬雪来
时间:2022年12月6日
内容:while,do...while,for三大循环
目录
前言: 1.什么是循环语句:
2.三大循环语句:
(1)while循环:
continue语句嵌套入while语句:
(2)for循环:
(3)do...while循环:
(4)三大循环的区别:
(5)死循环:
结尾:
前言: 在上一篇博客中我们了解到了循环与分支中的分支部分,那么接下来我们将进一步的讲解分支与循环之间的循环部分。我们通过学习可以认识到,分支语句的本质就是选择语句,让你在两个或者多个条件中选择一个正确的条件后,执行该条件中的语句。那么循环语句呢?接下来听我来说明。
上图可理解为循环语句的草图。(雾
1.什么是循环语句: 循环语句顾名思义就是循环,重复进行某一动作或者事情,当某一时刻我们打破了循环的必要条件的时候循环也就会停止。这种就类似盗梦空间,一个梦接着一个梦,我们会重复的做让自己醒来这个想法,直到自己回到现实世界,梦空间停止。
这样讲有点抽象,那我就举我们生活中的例子。就例如我们学生,每周的星期一到星期五因为要上学读书,所以我们会一直重复在某个时间被闹钟吵醒,然后起床后洗漱吃早饭后去上学这个动作,当来到星期六的时候,因为没有要上的课,所以我们就可以睡晚一会,这个时候循环的条件就被破坏,循环就会停止下来。我们可以将它初步理解为我们的循环语句。
2.三大循环语句: while循环。
do..while循环。
for循环。
(1)while循环: 相信大家都已经知道if分支语句了吧。我们写一个代码来区别if分支语句和while循环语句的区别。
这便是我们的if语句,当a满足if的条件的时候,执行if中的语句,执行一次后便结束编程。但是当我们将这里的if换为while会发生什么呢?我们来修改一下代码,并将它打印出来。
我们可以看见在我们的编译板上输出了循环的hehe,这就是while语句和if语句的区别。while在我们输入的条件满足while后面()中的条件的时候也就是条件为真的时候while,while中的语句就会反复执行,直到 while的条件为假的时候,循环不成立,这个时候循环就结束。那么我们怎么将这个代码变成如if一样只打印一个hehe的语句?
这里我们只要在printf后面将a进行++循环就只能循环一次。因为这里我们将a++,也就是将a的值从0变为了1,这个时候a再来到while循环语句,while(a(1)== 0)为假不成立,所以循环不成立,所以while中的语句不再执行,程序只执行一次。
同时我们也可以通过使用while循环来限制打印hehe的个数。比如我们想打印5个hehe,我们这个只要把while循环的循环条件设置为a<5即可。
我们也可以把while的循环语句好if的分支语句进行结合,也是嵌套。这样我们可以实现不同的结果。通常情况下while中嵌套if,或者if中嵌套while都是可以的,在这里我们就讲一下while循环语句中嵌套if语句。
这就是循环语句和分支语句的嵌套使用。只是这里有人会不懂是为什么,那我来解释一下。首先我们对a进行初始化,因为a满足while条件却不满足if的条件,所以即使if语句在前面也不执行,当a为5的时候,满足了while的同时满足了if语句,if里面的break语句就起到了作用(注:break的作用是跳出循环而不是if语句)。所以跳出循环,循环结束,最后打印出0--4的数字。
continue语句嵌套入while语句: 我们将while中嵌套if语句的代码进行修改,将if语句的break修改为continue会发生什么呢?我们来试验一下看看。
这里我们将这个代码与上面的break的代码进行对比,我们可以发现continue代码打印出来结果的后面少了一连串的中文结束语。我们要了解为什么的话首先要了解continue的作用是什么。
continue是用来终结此次循环的作用,当循环遇到continue后循环的语句不再执行,代码直接跳到循环部分,进行下一次的循环。
也就是这个代码一直会是a为5,然后无限的循环下去。我们也可以在while条件中输入scanf和getchar等操作符。
但是,我们getchar和putchar操作符还没有详细讲过,所以我们就先暂且搁置,只要知道有这个用法即可。就是是我们while语句的用法。
(2)for循环: for循环是我们三大循环语句的第二种,for循环的写法也是十分的新奇。
第一个空用来初始化值,类似于int a = 0,第二个空便是判断也就是while循环的条件,最后一个是对数值的调整,也就是a++或a--之类的改变某些值的表达式。
现在我们用for循环来代替while循环来输入数字0--10的值。
在for语句中break的使用和在while语句的使用方法和结果是一样的,这里我就不列举出来了,但是break虽然没有区别,但是在while中使用continue和在for循环中使用continue却是两种截然不同的结果。
对比while循环在输出输出4的时候不再往下输出,我们可以看见在for循环中使用continue的话,除了输出结果少了5后,程序依旧会继续输入下去。就是因为我们for循环的特殊性,因为for循环的++是在for循环的调整中的,所以continue跳过接下来的语句并不会影响a进行++。当a++为6后if语句不成立,因此程序继续输出。 建议:
1.循环变量就是我们的for循环中初始化的变量,我们在for循环里面不能对该变量进行二次修改,否则程序很容易发生崩溃。
2. 我们写for循环的时候一般判断条件都是单一的'<'或者'>',少使用'<='和'>='。
同样的for循环也可以scanf输入我们的数组每个arr[]的值。
这里给大家普及一个知识,for循环中初始化,判断和调整3个部分都可以省略【for( ; ; ;)】。但是注意省略掉判断部分,循环会进入死循环。
在此同时我们要知道,for循环的条件并不单调,不是初始化,判断和调整都只能输出一个词,我们也可以输出多个词。但是在输入判断的时候我们要用&&和||进行连接。接下来我就举一个简单的代码来表达一下吧。
for(int x = 0,int y = 0;x<5&&y<7;x++,y++) 那可以可以省略初始化的值呢,那当然是可以的,不过省略了初始化的值,同一个代码可能会出现不同的结果。就比如我下面列举的一个代码。
这是我们的原代码,我们可以看见这里打印了9个hehe,现在我们把代码中for循环里的初始化的区域都去掉后再次编译函数,看看结果有什么不同之处。
我们把两个代码进行对比一下,可看出来第一个代码打印了9个hehe,第二个代码打印了3个hehe。这是什么原因?因为for循环的for中的j = 0被去掉了,i的第一次循环的时候,j就已经变为3了,第二次for循环没有将j重新初始化为0,所以j依旧为3,循环条件不满足跳过循环。这就导致了我们只打印出了3个hehe。
继续学习使用LVGL V8,这一篇使用textarea和keyboard等控件实现一个color seletor
还是通过codeblock来模拟代码的运行,代码如下:
#ifndef _LV_GUI_COLOR_SELECTOR_H #define _LV_GUI_COLOR_SELECTOR_H #ifdef __cplusplus extern "C" { #endif #include <stdio.h> #include <string.h> #include <stdlib.h> #include "lvgl/lvgl.h" // 颜色选择器 void lv_gui_color_selector_display(); #ifdef __cplusplus } /* extern "C" */ #endif #endif #include <stdio.h> #include <string.h> #include <stdlib.h> #include "lvgl/lvgl.h" #include "lv_gui_color_seletor.h" // user_data typedef struct btn_usr_data { lv_obj_t * obj_label_val; lv_obj_t * obj_canvas; lv_obj_t * obj_ta_red; lv_obj_t * obj_ta_green; lv_obj_t * obj_ta_blue; }btn_usr_data_t; // 文本框事件回调 static void text_area_event_callback(lv_event_t * event) { if (event == NULL) { printf("
0x01 前言 看到很多师傅的面经里面都有提到 Weblogic 这一个漏洞,最近正好有一些闲暇时间,可以看一看。
因为环境上总是有一些小问题,所以会在本地和云服务器切换着调试
0x02 环境搭建 太坑了,我的建议是用本地搭建的方法,因为用 docker 搭建,会产生依赖包缺失的问题,本地搭建指南 https://www.penson.top/article/av40 这里环境安装用的是 奇安信 A-team 大哥提供的脚本,不得不说实在是太方便了!省去了很多环境搭建中不必要的麻烦
链接:https://github.com/QAX-A-Team/WeblogicEnvironment
下载对应版本的 JDK 和 Weblogic 然后分别放在 jdks 和 weblogics 中
JDK安装包下载地址:https://www.oracle.com/technetwork/java/javase/archive-139210.html
Weblogic安装包下载地址:https://www.oracle.com/technetwork/middleware/weblogic/downloads/wls-for-dev-1703574.html
我这里直接用的 kali 搭建,需要先把 jdk 和 weblogic 放到文件夹里面,如图
首先要先改写一下 Dockerfile,原作者写的 Dockerfile 有一点小问题
# 基础镜像 FROM centos:centos7 # 参数 ARG JDK_PKG ARG WEBLOGIC_JAR # 解决libnsl包丢失的问题 # RUN yum -y install libnsl # 创建用户 RUN groupadd -g 1000 oinstall && useradd -u 1100 -g oinstall oracle # 创建需要的文件夹和环境变量 RUN mkdir -p /install && mkdir -p /scripts ENV JDK_PKG=$JDK_PKG ENV WEBLOGIC_JAR=$WEBLOGIC_JAR # 复制脚本 COPY scripts/jdk_install.
0. 前言 目标检测是计算机视觉上的一个重要任务,下面这篇文章主要给大家介绍了关于Yolov5训练意外中断后如何接续训练的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
1. 配置环境 操作系统:Ubuntu20.04
CUDA版本:11.4
Pytorch版本:1.9.0
TorchVision版本:0.7.0
IDE:PyCharm
硬件:RTX2070S*2
2. 问题描述 在训练YOLOv5时由于数据集很大导致训练时间十分漫长,这期间Python、主机等可能遇到死机,或者任务量繁重导致功耗过大主机自动重启的情况,如果需要训练300个epoch但是训练一晚后发现在200epoch时停下是十分崩溃了,好在博主摸索到在yolov5中接续训练的方法了。
3. 解决方法 3.1设置需要接续训练的结果 如果你想从上一次训练结果中回复训练,那么首先保证你的训练结果(一般都存放在/runs/train目录下)在保存目录中代号为最大的。
如上图所示,在train文件夹下一共有14个训练结果,假设我的第12次训练中断了,想接着第12次的结果继续训练,那么只需要将比12更大的:exp13、exp14这两个文件夹删除或者移动到其他地方,这样便设置好了需要接续训练的结果。
3.2设置训练代码 代码需要更改yolov5代码中的train.py中的参数设置
if __name__ == '__main__': os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE" parser = argparse.ArgumentParser() parser.add_argument('--weights', type=str, default='../weights/yolov5s.pt', help='initial weights path') parser.add_argument('--cfg', type=str, default='./models/yolov5s.yaml', help='model.yaml path') parser.add_argument('--data', type=str, default='data/car.yaml', help='data.yaml path') parser.add_argument('--hyp', type=str, default='data/hyp.scratch.yaml', help='hyperparameters path') parser.add_argument('--epochs', type=int, default=300) parser.add_argument('--batch-size', type=int, default=32, help='total batch size for all GPUs') parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='[train, test] image sizes') parser.
中级软件设计师备考上午题总结 前言 10月末11月初备考了中级软件设计师,备考时间总计20天整,由于预留的备考时间并不多,上午题复习策略主要是以看别人整理好的笔记为主,不懂的地方以看zst_2001的视频为辅,最后预留了5天时间准备下午题并行刷上午真题,上午真题刷了700+道,此篇博客就是在最后刷真题阶段,个人觉得比较难记的知识点需要记录下来,避免由于忘记而导致返工,最后一晚上又回顾了此笔记2~3遍。
11月初考试完后,本想等出成绩后再共享此笔记。今天恰好整活了笔记脚本,把之前的笔记都一并处理了。成绩要到12月末出了,今天就趁方便提前发布了。
在此感谢b站up主zst_2001:zst_2001个人主页
感谢zst_2001视频笔记创作者@骚戴:软考笔记
此篇博客摘取了@骚戴笔记的部分内容,本意是方便个人学习,如有侵权,请联系笔者,会即刻删除!
1、流水线 吞吐率=指令条数/【一条完整指令的时间+(n-1)*流水线周期】
流水线的总共时间=一条完整指令的时间+(n-1)*流水线周期
流水线周期为执行时间最长(最耗时)的一段
2、IP地址块 IP地址块留给主机的地址码只有6位
IP26是CIDR的格式,全称是classless inter domain route 叫做无类域间路由,就是说32位IP的前26位为网络号,后面的全部都可以分给主机
这些地址都采用222.125.80.10xxxxxx的形式,其中最小地址是222.125.80.10000001,即222.125.80.129,最大地址是222.125.80.10111110,即222.125.80.190
**注意:**在IP地址中,全0代表的是网络,全1代表的是广播
3、关系模式候选键 4、浮点数表示 考查对于浮点数表示。浮点数表示:=尾数*基数指数
其中尾数是用原码表示,是一个小数,通过表格和题干可知,00000000001是尾数部分,共计后11位,其中第1位为0表示正数,展开得2-10
阶码部分是用补码表示,是一个整数,通过表格和题干可知,10001是整数部分,共计前5位,要计算其具体数值需要将其转换成原码,通过第1位符号位1可知其为负数,补码:10001,反码:10000原码:11111,数据为-15,基数在浮点数表示为2,可得2-15×2-10
注意:阶符表示指数的正负,指数是一个整数,数符表示尾数的正负,尾数是一个小数。尾数部分实际上是0.xxxx,这里是0.0000000001,也就是2-10
4、存储器 读写存储:RAM
只读存储:ROM、PROM(可编程)、EPROM(可擦除可编程)、EEPROM(电擦除可编程)
Flash:类似于EEPROM,不同的是,可以在字节水平上进行删除和重新而不是整个芯片重写。断电可保存数据。
5、信号量机制和PV操作 S的值为负数,负几就有几个进程在等待,S值为0就表示没有等待的,但是有一个或多个进程正在运行,S为正数就表示有多少个资源可以使用
这里呢,我理解为做这样的题目入p出V(入屁),也就是观察那个图,如果入度的话就是P操作,出度的话就是V操作,例如上面图中P1有两个出度,那就是V(S1)和V(S2),对于P2来说一个入度一个出度,所以就是P(S1)和V(S3),所以在做题之前要先把S1开始标在那个有向边上,注意我这只是为了快速做题,本身这个说法是不正常的,但是可以快速做对题
6、结构化开发 数据字典会对数据流图中元素进行定义说明
7、面向对象 封装:
不同形式的多态:
面向对象设计原则:
8、关系运算符中的连接 全外连接
9、huffman树 10、防火墙 防火墙技术经历了包过滤、应用代理网关、状态检测技术三个发展阶段
11、ISO IEC 9126软件质量模型 12、软件测试 13、连通图与强连通图 14、最小生成树 最小生成树: 在一个连通网的所有生成树中,各边的代价之和最小的那棵生成树称为该连通网的最小代价生成树, 简称为最小生成树。
15、面向对象分析 16、敏捷开发xp 17、病毒 木马程序一般分为服务器端(Server)和客户端(Client), 服务器端是攻击者传到目标机器上的部分,用来在目标机上监听等待客户端连接过来。客户端是用来控制目标机器的部分,放在攻击者的机器上。
木马(Trojans)程序常被伪装成工具程序或游戏, 一旦用户打开了带有特洛伊木马程序的邮件附件或从网上直接下载, 或执行了这些程序之后, 当你连接到互联网上时, 这个程序就会通知黑客用户的P地址及被预先设定的端口。黑客在收到这些资料后,再利用这个潜伏其中的程序, 就可以恣意修改用户的计算机设定、 复制任何文件、 窥视用 户整个硬盘内的资料等,从而达到控制用户的计算机的目的。
现在有许多这样的程序,国外的此类软件有Back Office、Netbus等, 国内的此类软件有Netspy、YAI、SubSeven、冰河、“广外女生”等。Sniffer是一种基于被动侦听原理的网络分析软件。使用这种软件,可以监视网络的状态、数据流动情况以及网络上传输的信息,其不属于木马程序。
首先来看一段代码
我们把这段代码称为代码①,接下来我们再来看另外一段代码
我们把这段代码称为代码②。
在代码①当中,定义了一个方法,这个方法声明的返回值类型是double,而实际通过return关键字返回的却是一个int型的值,但并没有引起编译错误。而在代码②当中,情况正好相反,方法声明的返回值类型是int,方法内部的return关键字实际返回了一个double类型的值,在这种情况下,编译器却报出了语法错误。
对比一下这两种情况,很多初学Java的小伙伴搞不清:为什么同样是方法声明的返回值类型与实际返回值的类型不相同,第一种情况不报错,而另一种情况却无法通过编译检查呢?要讲清楚这个问题,我们必须从为什么方法要声明返回值类型说起。
在Java语言中,要求程序员在定义一个方法的时候,必须在方法名称的前面声明这个方法的返回值类型。为什么要求你这么做呢?简单来说,就是编译器强制程序员必须公开一个信息,那就是:这个方法在运行之后会返回一个什么类型的值,只有这样,调用方法的人才知道要用一个什么类型的变量接收方法的运算结果。除此之外,编译器还要求:主调方法在接收返回值的过程中,必须以声明的返回值类型作为准,而不是看实际返回值的类型。就拿代码①来说,声明的返回值类型是double,实际返回值是int,我们在程序中用变量接收方法返回值的时候,必须用double型变量接收,即便是它实际返回的只是一个int型数据,也不能用int型变量接收返回值,否则就会出现编译错误
接下来,我们再来观察方法的定义过程。在代码①当中,方法所声明的返回值类型是double型,而实际在方法的内部返回的是一个int型的值,二者之间类型并不一致,但并没有出现语法错误,这又是怎么回事呢?这是因为,Java语言在做语法检查的时候,要求只要实际的返回值类型能够”自动转换”为方法所声明的返回值类型即可,并不要求二者必须完全相同。代码①当中的方法,实际返回值是int类型的,它可以自动转换为一个double类型的值。而代码②当中的方法,实际返回值是double类型的,无法自动转换成int类型,所以报错了。专业上,我们把编译器可以自动完成的类型转换也称之为“隐式类型转换”。
为了说明为什么方法声明的返回值为double类型,但实际却可以在方法中返回一个int型的数据,我们来举个容易理解的例子:你小的时候,你爸爸要出门,告诉你在他回来的时候会带回一个直径50厘米的大蛋糕,那么你肯定会按照他的承诺,准备一个直径50厘米的大盘子用来装这个大蛋糕。但你爸爸回来的时候,实际带回来的却是一个直径只有10厘米的小蛋糕,这时虽然你很伤心也很失望,但是,你所准备的大盘子足够能放得下你爸爸带回来的小蛋糕,不会出什么问题。代码①当中定义的方法就属于这种情况,声明返回一个占8字节的double型数据,但实际返回一个占4字节的int型数据。
但是反过来,你爸爸出门的时候告诉你他回来的时候会带回一个10厘米的小蛋糕,你也按照他的承诺准备了一个直径10厘米的小盘子,打算用来装这个小蛋糕。但当你爸爸回来的时候,带回的却是一个直径达50厘米的大蛋糕!这时,你又惊喜又激动,但是却无法解决一个问题:你所准备的小盘子根本无法盛放这么大的蛋糕!这就好比是代码②中所展现的情况,声明返回一个只占4字节的int型数据,而方法运行实际返回一个8字节的double型数据,让那些准备用int型变量接收方法返回值的人感到“措手不及”。当然,这只是一句玩笑,如果真的出现了实际返回值无法自动转换成声明的类型,编译器根本不允许这样的代码通过编译,所以也更谈不上运行代码了。
接下来再具体说说哪些情况下,编译器能够自动把一种类型”自动转换”成另一种类型,也就是实现我们所说的”隐式类型转换”。我们可以分以下几种情况讨论:
一、我们知道,Java基础数据类型有8种,其中整数类型有4中,分别是long、int、short和byte。这4种整数类型有着明显的“向下兼容”的特性,也就是说,较小的数据类型都可以自动转换为较大的数据类型,比如int类型的数据在赋值给long类型的变量时,可以自动完成从int到long的转换。因此,声明返回值为较大的数据类型,实际返回较小的数据类型,是肯定没有问题。比如,声明返回值为long类型,但实际返回int型数据是完全可以的。在这种情况下,int型的数据返回到主调方法中,在赋值给一个long类型的变量时,可以自动完成类型转换。同样,两种浮点数double和float也能够做到“向下兼容”,声明double型,返回float型也完全可以。
二、我们还知道,表示字符的char类型,在实际存储数据的过程中,存储的也是一个占两个字节的”整数”,这个”整数”其实就是字符的编码值。那么char类型的数据能否与Java的4种整型完成自动类型转换呢?实际情况是:char可以自动转换为long和int,但不能自动转换为short和byte。反过来,short和byte也不能自动转换为char。说的直白一点,就是如果我们把方法的返回值声明为char类型,方法实际返回的是long、int、short和byte型的数据都不行。
三、任意整型和字符型都可以自动转换为浮点型,但反之不成立。也就是说, long、int、short、byte以及char都可以自动转换为double和float。但反过来,double和float都无法自动转换成long、int、short、byte以及char。这里可能有写小伙伴会有一点疑惑:8个字节的long类型数据真的能自动转换为4个字节的float型吗?从语法的角度是没有问题的,我们把一个long类型的数据赋值给一个float类型的变量不需要做强制类型转换,编译器也不会报错。但实际存储过程中,有可能会导致数据损失精度。注意,这里所说的是“有可能”损失精度,而不是”一定”损失精度。
四、boolean类型在8种基础数据类型中是”特立独行”的,它无法与任何其他基础类型的数据完成相互自动转换的操作,如果一个方法声明返回值类型为boolean,那么这个方法只能返回boolean类型的数据,返回任何其他基础数据类型的值都会报错。
以上我们谈到的方法返回值都是基础数据类型,如果是引用数据类型,情况又如何呢?这种情况下,遵循“子类对象可以自动转为父类对象”的原则。也就是说,如果返回值被声明为父类,而实际返回对象为子类对象,完全可以顺利通过编译器语法检查。同样,如果返回值类型被声明为接口,方法实际返回对象为接口的实现类对象,也没有问题。而反过来,方法声明返回值类型为子类,实际返回值为父类对象是无法通过编译检查的。
希望本文对初学Java的小伙伴理解方法的返回值有所帮助。
本专栏每篇文章讲解一个知识点,如果想系统学习Java编程可以点击这里观看我在本站的视频课程,也可以订阅我的免费专栏《Java从小白到高手》。
学习Java编程的时候,无论是谁,当学到面向对象这部分内容时都会遇到一个关键字:this。很多初学者对这个关键字的都会感觉到理解不透,不明白这个神秘的”this”到底表示什么意思。按照官方正规的解释,this关键字的意义被解释为“指向当前对象的引用”。这个解释非常准确并且很精炼,但它太过学术化了,导致很多初学者有点读不懂,更谈不上深入理解它的意义。本文将用大白话的形式帮助初学Java的小伙伴来深入理解this关键字的意义,并且梳理它的各种用法。
其实,我们只要把this理解成”本对象自己的...”就可以了。看到这个解释,很多人可能更懵了,什么叫”本对象自己的...”?不要着急,让我们首先来看一段代码。
在这段代码中,定义了一个表示”人”的类Person,在Person类中,有3个属性name、age和height,分别来表示姓名、年龄和身高。在类当中定义了一个构造方法,构造方法中对3个属性进行了初始化操作。最后定义了一个introduce方法,这个方法能够打印一个Person对象的姓名和年龄。现在,我们在main方法当中创建一个Person类的对象,并且调用这个对象的introduce方法,代码如下:
愉快的运行一下程序,出来的运行结果是这样的:
通过程序的运行结果我们可以看出,在创建对象的时候,对象的属性被赋予了正确初始值。这个程序本身非常的简单,谁都可以理解,但是大家请注意,我们在定义构造方法的时候,把表示姓名、年龄和身高的参数分别命名为:n、a和h,这种命名的可读性有点差,为了提高可读性,我们把构造方法的参数名称修改为name、age和height,如下图所示:
修改之后,再次运行main方法,得到的运行结果变成了这个样子:
为什么这一次的运行结果出现了问题呢?就是因为,修改了构造方法之后,当我们调用构造方法创建对象时,给构造方法所传递的3个参数值“张三”、20和178.5最终并没有赋值到对象的3个属性中。那么,既然参数值没有被赋值到对象的属性中,它们去了哪里呢?修改代码后,构造方法的参数与类所定义的属性同名,根据”同名情况下,局部变量的优先级更高”原则,在构造方法执行的过程中,虚拟机会把参数值赋给”参数本身”,而不是赋值给对象的属性!具体来说,就是我们给构造方法的name参数传递的值是”张三”,而这个”张三”在构造方法执行的过程中,当运行到”name=name;”这条语句时,并没有把”张三”赋值给对象的name属性,而是又重新赋值给了name参数自身。就是因为”张三”最终没有被赋值到对象的name属性中,才导致introduce方法中打印出的name属性是null。当然,age和height这两个参数也是同样的赋值效果。
为了能够让虚拟机明白我们所期望的是:把”张三”这个字符串赋值给对象的name属性,而不是”再一次”把它赋值给构造方法的参数,就需要把构造方法中的赋值语句做出如下修改:
大家来看,这一次,我们在构造方法中,给”=”左边的属性前面都加上了this关键字,经过修改之后,重新运行main方法,就恢复了正常的运行效果。好,现在我们就来探究一下,加了this关键字之后,为什么程序能够”恢复正常”。刚才我们说过,”this”可以被解释为” 本对象自己的...”,按照这个逻辑,”this.name”就可以被解释为”本对象自己的name属性”,所以在执行”this.name=name;”这条语句的时候,虚拟机就会把name参数的值”张三”赋值给对象的name属性。也就是说在这条赋值语句中,”=”左边的”this.name”表示对象的name属性,而”=”右边的name表示方法的name参数。
讲到这里,有的小伙伴可能会问:”this.name”为什么不能被解释为”本对象自己的name参数”呢?因为”参数”这个概念是就某个方法而言的,它相当于某个方法的”局部变量”,只是这个”局部变量”比起在方法中定义的真正的局部变量来讲有点特殊,它能够接收从主调方法中传递过来的值。因此,当我们说到”参数”这个概念的时候,都是相对于一个”方法”而不是一个”对象”而言的,所以也就不会有”某个对象的参数”这一说法。因此,”this.name”只能被虚拟机认定为本对象自己的name”属性”,绝不会被当作name”参数”。
通过这个例子,希望大家能够理解this关键字的意义。在程序中,所出现的”this.属性名”是this关键字最常见的一种用法,也是我们给大家总结的this关键字的第一种用法。既然”this.属性名”可以被解释为”本对象自己的XX属性”,那么会不会有”this.方法名”这种用法呢?当然有这种用法,当程序中出现了”this.方法名”这种写法,就可以被解释为调用”本对象自己的XX方法”。来看下面的代码:
这一次,我们给Person类增加了一个”打招呼”的方法叫做greet。在introduce方法当中,就可以通过”this.方法名”的方式来调用这个方法,表示调用的是”本对象自己的greet”方法。这是this关键字的第二种用法。当然,在introduce方法中并没有出现其他对象,所以方法名前面的this关键字也可以省略不写。
既然this关键字表示的是本对象自己,所以在代码中可以直接用this来代表对象自身。比如说,在Ojbect类当中定义了一个equals()方法,这个方法用来比较自身对象与其他对象是不是相等,就直接可以用this来与其他对象做比较。
上面这段代码就是Object类的equals()方法的源代码,有兴趣的小伙伴可以去看看。在代码中直接用this关键字代表对象本身,并且和另一个对象obj做了比较。(关于==这个运算符到底比的什么,大家可以看我的另一篇博文《你真的掌握了Java语言的"=="运算符吗?我看未必!》)
其实,this关键字还有另外一种很重要的用法,那就是在this关键字的后面加上小括号,这样就表示调用了某个类自身的构造方法,为了讲解这种用法我们再来修改一下Person类。
这一次,我们给Person类又增加了一个构造方法。这个构造方法只有2个参数,并且只初始化2个属性。为了讲述方便,我们把上面的3个参数的构造方法称之为”构造方法①”,把下面的2个参数的构造方法称之为”构造方法②”。通过观察不难发现,这两个构造方法当中前2行代码是相互重复的,为了避免这种重复性的代码出现,我们可以在”构造方法①”当中调用”构造方法②”。调用的方式如下:
在”构造方法①”中,通过”this(参数);”的方式调用了”构造方法②”。这就是this关键字的又一种用法。很多小伙伴可能不理解,为什么要通过这种方式来调用构造方法呢?我们难道不能直接写一个”Person(name,age);”来调用吗?这里必须做出解释:在Java语言中,一个类的构造方法与类名相同。但是,一个类当中也可以定义一个与类名相同的”普通方法”,换句话说就是:并不是只有构造方法与类名相同,”普通方法”也可以取和类相同的名称(只不过全世界的程序员都不会这么干)。那么,在这种情况下,编译器如何区分这个方法是”普通方法”还是”构造方法”呢?很简单,”普通方法”的名称前面必须定义返回值类型,而”构造方法”的名称前面则没有返回值类型的定义。这样,编译器就能够分得清哪个是”构造方法”,哪个是”和类同名的普通方法”。
定义的时候分得清,但是在调用的时候,都是通过方法名来调用的,这时如何分得清代码中哪一句调用的是”构造方法”, 哪一句调用的是”和类同名的普通方法”呢?为了解决这个问题,Java语言规定,在本类中调用构造方法的时候,需要通过”this(参数)”的方式来调用。除此之外,Java语言还规定了这种调用方式所必须遵守的规则。首先,这种”this(参数)”的方式只能在”其他构造方法中”使用,不能在普通方法中用。如果在普通方法中按这种方式使用,将被视为语法错误,如下图所示
可以看到,在普通方法中按这样的方式调用构造方法会出问题。
其次,在一个构造方法中,用”this(参数)”的形式调用构造方法,”this(参数)”必须写在主调方法的第一行。第三,不能出现相互循环嵌套调用,也就是说,不能在构造方法①中调用构造方法②,又同时在构造方法②中调用构造方法①,如下图所示
这种相互调用的写法是绝对不允许的。
接下来我们再来思考两个问题:首先,在main()方法中执行到”new Person("张三",20,178.5);”这句代码时,实际上是调用了构造方法①,而构造方法①中又调用了构造方法②,两个构造方法都被调用到了,那么在内存中会不会创建两个Person对象呢?答案是不会,为什么呢?原因很简单:构造方法①中调用了构造方法②,并没有出现new关键字,调用构造方法②仅仅是完成了name和age这两个属性的初始化,并不会创建出两个对象。
我们要思考的第二个问题是:既然Java语言允许”普通方法”的名称与类名相同,而构造方法也与类名相同,那么在Person以外的类当中如果写上了”Person(参数)”这样的代码,虚拟机如何判断所调用的是普通方法还是构造方法呢?答案也很简单,如果”Person(参数)”的前面出现了new关键字,这就说明调用的是构造方法,否则说明调用的是普通方法。
讲到这里,我们就把this关键字最常用的几种用法讲完了,其实,this关键字在我们编写内部类代码的时候,还有一种用途,那就是区分属性或方法的具体归属。我们来看下面的代码:
在这段代码中,定义了外部类Outter,Outter有一个属性a,并且Outter中又定义了内部类,在内部类的printA()方法中调用了外部类的a属性。我们都知道,一个内部类可以直接访问它所在外部类的属性和方法。这个特性在我们的上面这段代码中得到了体现。但是,如果内部类中出现了与外部类同名的属性或方法时,该如何区分调用的到底是哪个属性或方法呢?比如说,在Inner类中也出现了a属性,那么输出语句中的a到底是指哪个a呢?很简单,如果输出语句中直接写a,那么调用的是内部类的a属性。为了强调它是内部类的a属性,我们也可以在a的前面加this关键字。如果我们希望调用的是外部类的a属性,可以用”外部类名.this.a”的方式来调用,如下图所示:
以上我们就把this关键字的意义和它的各种用法讲完了,简单总结一下:
1、this:表示自身对象,也就是本对象自己
2、this.属性名:表示本对象自己的属性
3、this.方法名:表示本对象自己的方法
4、this(参数)表示本对象自身的构造方法(注:”构造方法”这个概念是相对于”类”而言的,但具体到this(参数)这种用法时,表示”我这个对象自己的构造方法”)
5、外部类名.this.属性:表示在内部类中调用的是外部类的某个属性(调用外部类方法亦同)
希望本文能够帮助初学者深入理解this关键字的作用。
本专栏每篇文章讲解一个知识点,如果想系统学习Java编程可以点击这里观看我在本站的视频课程,也可以订阅我的免费专栏《Java从小白到高手》。
很多初学Java语言的小伙伴,在学到“面向对象”这块内容的时候,都会学到的一个概念,那就是“方法的重写”。重写又叫覆盖,英文名为“Override”。虽然”重写”、 ”覆盖”、“Override”这些名词都很容易记住,但很多人并没有真正理解Java语言为什么要提供“重写”这种编程机制,也不知道什么时候该重写父类中的方法,下面我们通过一篇文章来全面学习一下“方法的重写”。
假设有一个类叫做Father,并且我们假设因为某种原因,我们只能使用这个类,但没有办法修改这个类的源代码。Father类中提供了一个能够求正整数累加之和的方法叫做sum。(所谓“累加”就是从1一直加到某个数,比如1+2+3+...+100)代码如下
后来,我们又编写了一个类叫做Child,它继承了Father类。其他方面都没什么问题,但Father类所提供的这个用于求整数累加之和的方法sum()效率实在太低了,每做一次累加都要执行多次循环。求整数累加之和明明可以用更高效的方法实现,但出于某种原因,我们无法修改Father类的源代码,难道我们继承了Father类就只能被迫选择使用这个效率很低的sum()方法吗?
幸好,Java语言提供了“重写”这种编程机制。重写,顾名思义,就是在子类中把继承自父类的某个方法重新写一遍。这样就能在子类中弄出一个同名的、更适合自身或者是效率更高的方法。于是我们就可以在子类中重写了sum()方法,代码如下
通过观察代码我们不难发现,重写之后的sum()方法摒弃了循环求和的算法,而采用了更高效的等差数列求和的方法完成累加的计算。这样明显提高了运算效率。当我们创建一个子类对象,并且调用该对象的sum()方法时,虚拟机将会调用重写之后的sum()方法,而不是父类中那个老的sum()方法。
但是,如果我们在代码在中,使用了父类的引用去指向子类对象的时候,还能不能调用到那个重写之后的sum()方法呢?看下图
从上面的代码中我们可以看到,创建了一个Child类对象,但是指向这个对象的对象的引用f却是一个Father类的引用。那么在这种情况下,当我们通过引用f调用sum()方法的时候,调用到的父类中的sum()方法,还是子类中重写过的sum()方法呢?执行main()方法,运行结果如下
根据方法的运行结果,我们可以看出,即使我们使用父类的引用去指向子类的对象,只要引用实际所指向的对象是子类的对象,那么通过这个引用调用方法的时候,调用到的就是子类的方法,父类的中的那个方法仿佛被屏蔽了,因此方法的重写也叫“覆盖”。
其实,“重写”和“覆盖”这两个词是从两个不同的角度描述了这种编程机制。“重写”是从编码的角度来说的,它体现了子类“重新编写”了父类的某个方法,因此叫“重写”。而“覆盖”是从代码运行效果的角度来说的,它形象的体现出:当子类重写了父类的某个方法之后,当子类对象通过方法名称调用该方法,不会调用到父类中定义的那个方法,只能调用到子类中所定义的那个同名方法,父类中的那个方法如同被子类中重新定义的同名方法覆盖住不见踪影一样,因此叫“覆盖”。
通过以上这个小例子,我们能够体会到:Java语言中引入重写机制,为的就是让我们在编码的时不必受限于父类。子类可以继承父类的方法以减少编码量,但是如果认为父类的某个方法不适合自身,或者这个方法效率不高,子类完全可以重新编写一个更加适合自身或效率更高的同名方法去代替它。
虽然我们已经理解了什么是方法的重写,但很多小伙伴还是不清楚在什么情况下要重写父类的方法,在此我们总结出需要进行方法重写的三种常见情况:
一、父类要求子类重写
这种情况其实就是指父类无法定义出某个方法的实现过程,于是只能把这个方法定义成抽象方法,从而强制子类去重写这个抽象方法。这个过程虽然被称为“实现”,但它实际上就是对某个方法的重写。因为从本质上来讲,这个过程就是把父类的一个没有实现过程的空方法(即抽象方法)重新编写为一个有具体实现过程的方法。
二、父类中的方法不适合子类
子类如果继承了父类的某个方法,但发现这个方法并不适合自己,就需要重写这个方法。最典型的例子就是表示字符串的String类继承了Object类的equals()方法。但Object类中的equals()方法是用来比较两个对象是否为同一个对象,String类则希望自己的equals()方法能够比较两个字符串的“内容”是否相同,于是在String类当中就重写了equals()方法。有兴趣的小伙伴可以自己去查看一下这两个类当中的equals()方法源码。
三、父类中的方法效率较低或算法陈旧
第三种情况就是:由于各种历史问题的原因,导致原先父类中定义的方法存在效率偏低或算法陈旧,以及线程不安全等情况,并且我们还不能修改父类方法的源代码。在这种情况下,子类就可以用更先进的实现过程来重写父类中的方法。刚才我们看到的Father类和Child类的例子就属于这种情况。
另外,我们还必须要强调一个原则,那就是:子类在重写父类方法的时候,不能更改父类方法的原宗旨。比如说:父类Father中的sum()方法是用来求累加之和的,子类Child在重写父类的sum()方法的时候,就不能把sum()方法改成求阶乘的运算。这个原则适用于所有情况的方法重写,请务必牢记。
接下来我们再来说说子类在重写父类方法的时候,必须遵守的那些语法规则。子类重写父类的方法,需要遵守“三同不降不多抛”的七字规则。
所谓“三同”就是指子类重写的方法要与父类中原方法的名称、参数和返回值都相同。如果方法名称不相同,将被编译器视为子类新扩展出的方法。同理,如果方法的参数不同,则被编译器视为子类新增加了一个“重载”关系的方法。如果返回值不同,则被编译器视为违反重写规则。
但是,关于“返回值相同”,这里需要说的更详细一点。通常情况下,都是父类的原方法声明某种类型的返回值,子类重写的方法也声明相同类型的返回值。但有一种特殊情况,编译器会认为是合法的,那就是:父类原方法声明的返回值是一个父类类型,子类的重写方法声明的是一个子类类型。有的小伙伴可能没理解这句话的意思,我们直接看下图
通过上图我们可以看到,代码中定义了两对父子类,分别是A和B以及SuperClass和SubClass。SuperClass在定义test()方法时声明方法返回A类对象,而SubClass在重写test()方法时声明方法返回B类对象。SuperClass是SubClass的父类,A又是B的父类,它们都有相同的父子继承关系,编译器认为这种重写方式是合法的。但是如果SubClass在重写test()方法时声明方法的返回值为String或者是其他的某个类的对象,只要这个对象不是A类的子类对象,都将被编译器认定为不合法操作。因此,我们要正确理解“返回值相同”这个规则。
语法规则“三同不降不多抛”中的“不降”是指子类重写父类方法时,不能降低方法的访问度。比如说,父类声明方法的访问度为“public”,子类就不能擅自将方法的访问度降为“protected”或者是更低的访问度,否则将无法通过语法检查。
接下来说说“不多抛”。所谓“不多抛”是子类重写父类方法时,不能用throws关键字声明抛出更多的异常。这里的“更多”并不是指数量上的多,而是指范围不能扩大。不理解的小伙伴看下图
从图中我们可以看出,虽然从数量上来讲,父类的test()方法声明抛出两个异常,子类重写的test()方法只声明抛出一个异常,但子类声明的是Exception,Exception代表了所有的异常,换句话说就是:Exception所能代表的异常的种类更多、范围更大。因此虽然从数量上子类的test()方法没有比父类的test()方法抛出更多异常,但范围却扩大了,这也是不允许的。
我们在实际开发过程中,有的时候会因为粗心导致子类并没有真正的重写父类的方法。比如说父类定义的方法名为”sum”,而子类中却把这个方法错误的写成了”snm”。程序员可能因为粗心没有发现这个错误,导致自己写了半天代码却没有实现“覆盖”的效果。为了避免这种错误,我们在重写某个方法的时候,可以在方法的上面加上@Override注解。一旦加上这个注解,编译器就知道这个方法是意图覆盖父类中的某个方法,于是就会检查父类中是否有同名方法,如果发现子类中的方法与父类中任何一个方法都不同名,那么就标出语法错误来提示程序员。同时,其他程序员看到@Override注解,也能立刻明白这个方法是重写了父类的某个方法。因此,我们最好在所有重写的方法前面都要加上@Override注解。
当子类重写了父类中的某个方法之后,如果从子类内部去调用这个方法的时候,调用到的一定是重写之后的那个方法。不理解的同学还是看下图
从图上我们可以看出,在子类的method()方法中去调用test()方法,调用到的是子类重写过的test()方法。但是,如果我们希望在子类内部调用父类中那个被覆盖了的test()方法该怎么办呢?这时候,我们必须在方法的前面加上super关键字,代码如下:
在test()方法的前面加上super关键字,可以从子类的内部调用到那个已经被覆盖了的父类的test()方法。这里插一句:super关键字的用法也有很多,我们会专门写一篇文章介绍super关键字的各种用法。
有小伙伴会问:以上讲解的都是子类重写父类方法的知识点,那么父类是否真的如同“被宰割的羔羊”一般,任由子类重写它所定义的方法吗?如果我们定义一个类,能否不让子类去重写这个类中的方法呢?当然是可以的,我们只要在某个方法的前面加上一个final关键字,那么子类就无法重写这个方法啦!
以上讲了这么多,说的都是子类重写(或覆盖)父类的“方法”,那么子类能否同样也覆盖父类的“属性”呢?既然说到这个问题,我们也来总结一下。
其实子类中确实可以定义一个跟父类同名的属性,并且还能给属性赋一个不同于父类属性的初始值,但这个操作并不叫“重写”或“覆盖”,我们可以把它叫做“屏蔽”。关于屏蔽父类属性这个操作,我们要掌握以下几个知识点:
一、子类屏蔽父类属性与父类属性的类型及访问修饰符无关
话不多说,直接看下图
父类中定义了一个属性名叫a,类型为int,访问度为public,子类中完全可以再定义一个叫a的属性,这个a属性可以与父类中a属性类型不同、访问度不同、初始值不同,完全不会有任何语法问题,只要属性的名称相同就能实现屏蔽效果。
二、属性的访问由引用(而非对象)决定
还是看下图:
通过上图我们可以看到,代码中分别创建了三个对象,其中第二条语句是父类的引用指向了子类的对象。在这种情况下,通过父类的引用super2去访问a属性,访问到的是父类(即SuperClass类) 中的a,而非子类中的a。这一点与方法的访问效果是不同的,小伙伴们一定要注意这个细节。
三、通过super关键字访问被屏蔽的属性
继续看图
子类的方法如果直接访问a,那么肯定是访问子类自身的a。如果我们想要访问被屏蔽的父类a属性,只要加上一个super关键字就可以了,这跟访问被子类覆盖了的方法是一样的效果。
四、final关键字无法阻止屏蔽
继续看图
从图中的代码可以看出,父类的a属性前即使加上了final关键字,子类仍然可以定义一个同名属性来屏蔽父类中的a属性,完全不会出现任何语法问题。有小伙伴会问:既然加上final关键字无法阻止屏蔽,那么这个关键字有什么意义呢?答案是:这个final关键字能够防止父类中的a属性被修改值,使之成为一个常量。
以上几条就是我们总结的关于子类屏蔽父类属性需要小伙伴们记住的几个关键知识点。
本文较长,讲了很多知识点,有遗漏和错误之处欢迎小伙伴们留言指出。
本专栏每篇文章讲解一个知识点,如果想系统学习Java编程可以点击这里观看我在本站的视频课程,也可以订阅我的免费专栏《Java从小白到高手》。
背景说明 有时我们后台管理项目需要部署多个节点,文件也要存到一个统一的地方,这就需要对远程文件仓库进行上传、下载、文件拷贝、执行shell命令等操作。
接下来笔者将使用JSch来实现对远程文件仓库的操作
源码地址:https://gitcode.net/lu993356091/ftptest
代码实现 项目整体结构如下
pom.xml文件引入以下依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- sftp --> <dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.55</version> </dependency> <!-- 连接池 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.11.1</version> </dependency> application.yml
server: port: 80 sftp: #服务器ip host: 192.168.xx.xx #ssh端口 port: 22 #用户名 username: USER001 #密码 password: 123456 #连接池参数 pool: #对象池中管理的最多对象个数。默认值是8 max-total: 10 #对象池中最大的空闲对象个数。默认值是8 max-idle: 10 #对象池中最小的空闲对象个数。默认值是0 min-idle: 5 创建配置类
SftpConfig.java
package org.example.config; import com.jcraft.jsch.ChannelSftp; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.example.ftp.SftpUtil; import org.example.pool.SftpFactory; import org.example.pool.SftpGenericObjectPool; import org.
下载新chrome:
64位:https://www.google.cn/chrome/thank-you.html?statcb=1&installdataindex=empty&defaultbrowser=0
媒体查询语法(2种):
@media not|only mediatype and (expressions) { CSS 代码...; } @media (max-width: 480px) { 相应css语句 } // 设备类型可不写,默认为screen 具体使用如: // 设置el-dialog小屏适配:当屏幕宽度小于768px时,el-dialog宽度变大。 @media (max-width: 768px) { .el-dialog { width: 90% !important; } .el-date-range-picker { // 解决:手机移动端时间筛选下拉选框左侧被覆盖,显示不全问题 width: 100% !important; overflow: auto !important; } } 参考:
@media的用法 - 简书CSS媒体查询_叶子yes的博客-CSDN博客_css 媒体查询 CSS3媒体查询media_queries响应式布局入门指南知识点总结 - 知乎CSS3 多媒体查询 | 菜鸟教程
在做流媒体方案时,尤其时web客户端播放http-flv时,由于浏览器的限制,最大只能播放6路视频的播放。
而在部分客户的实际使用中,会有基于web端的超过6路的视频播放需求,这时候就用到了websocket技术,流媒体服务器通过websocket-flv或websocket-fmp4的方式实现视频播放的数据流推送,web客户端只需要调用,就可以妥妥的支持超过6路以上的音视频服务器。
对于websocket-flv的视频播放器测试地址,可以参考:http://bilibili.github.io/flv.js/demo/
只需要把websocket的地址添加进去即可播放
对于websocket-fmp4的视频播放器,下载地址:https://download.csdn.net/download/hengdela/87253553
对于http-flv播放,可以参考如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/flv.min.js"></script> </head> <body> <div class="mainContainer"> <video id="videoElement" class="centeredVideo" controls autoplay width="1024" height="576">Your browser is too old which doesn't support HTML5 video.</video> </div> <script> let player = document.getElementById('videoElement'); if (flvjs.isSupported()) { let flvPlayer = flvjs.createPlayer({ type: 'flv', hasAudio: false, <!-- 不添加这句会播放一会就出问题 --> isLive: true, url: 'http://ip:port/appx/channelx.flv', }); flvPlayer.attachMediaElement(videoElement); flvPlayer.load(); //加载 setTimeout(function(){ flvPlayer.play();}, 0); } function setPlayUrl() { var playurl = document.
--1.创建密码复杂度函数。
SQL> conn /as sysdba
Connected.
SQL> @?/rdbms/admin/utlpwdmg.sql
--2.创建具有密码复杂度的Profile;
create profile PROF_MYPROFILE limit SESSIONS_PER_USER unlimited --每个用户拥有的会话数不限。 PASSWORD_REUSE_TIME 60 --密码重用次数。
FAILED_LOGIN_ATTEMPTS 10 --失败可尝试登录次数10次。
PASSWORD_LIFE_TIME 180 --密码180天过期。
PASSWORD_GRACE_TIME 7 --最多可以延迟7天必须修改密码。
PASSWORD_REUSE_MAX 1 --密码只能重用一次。
PASSWORD_LOCK_TIME 1/48 --锁定时间30分钟。
IDLE_TIME 4320 --空闲时间。
PASSWORD_VERIFY_FUNCTION verify_function_11G; --指定密码复杂度函数:最少8位,包含大写,小写,数字,特殊符号。
--3.将某个用户xsq加入到这个密码策略中,此用户将使用该策略。
alter user xsq profile PROF_MYPROFILE;
select * from dba_profiles;
select * from dba_users;
--4.创建新用户示例。
create user xsq2 identified by Oracle#123 default tablespace users temporary tablespace temp profile PROF_MYPROFILE;
main 函数传递参数args
public static void main(String[] args) { for (String arg : args) { System.out.println(arg); } } 打印结果:
path=dsadadad/dsad/dasd/asd
idea Edit Configurations…→设置Program arguments
cmd命令 java -jar xxx.jar [mainClass] [args]
例如:java -jar a.jar quality.gui.sdasdsa path=dsadadad/dsad/dasd/asd
网络模式设置为桥接(复制物理网络连接)
共享物理主机的某个目录文件
在CMD命令窗口下使用以下命令,如果在同一个网段且相互都能ping通说明没有问题
ipconfig # 查看ip地址和默认网关 ping IP地址 # 对连接进行测试 在虚拟机上查看网络却是空的,使用\\物理主机IP地址,查看要么是空要么就是打不开,网上找了很多相关问题的文章发现都是相互搬运没有实质性作用,最后在DOS命令时候发现了点搞头
CMD命令提示符下使用net use命令指定用户登录后访问共享文件夹或直接映射到某个盘符
net use \\共享ip /user:用户名 # 连接共享并映射到指定盘符 net use 指定映射盘: \\共享ip\文件目录 查看当前主机连接状态
net use 断开某个连接状态或断开全部
net use 映射盘: \\共享ip\文件目录 /del # 删除所有 net use * /del 要是还不行,重启几次电脑又可以了~
只需要再套一层div,给套的div定宽,最外层的设置滚动条即可
<div class='container'> <div style="width: 300px"> XXXX具体内容 </div> </div> .container{ overflow:auto; }
初学qt的时候发现如下错误:
1.错误代码
connect(zt,&Teacher::hungry,st,&Student::treat);
执行上面语句,出现如下错误
error: no matching function for call to ‘Widget::connect(Teacher*&, <unresolved overloaded function type>, Student*&, void (Student::*)())’
2.错误原因
问题原因是在进行响应调用的时候,不知道该调用哪个函数说明出现函数重载
打开teacher.h头文件
信号与槽函数对应的时候,有几点需要注意:
1.在信号与槽函数的参数数量相同时,它们参数类型要完全一致。
2.信号参数个数必须比槽函数个数多。
综上,保留16行无参函数,删除17行,问题解决。
java实现贪吃蛇游戏需要创建一个桌面窗口出来,此时就需要使用java中的swing控件
文件:url80.ctfile.com/f/25127180-741329966-6cb9eb?p=551685 (访问密码: 551685)
创建一个新窗口
JFrame frame = new JFrame(“贪吃蛇游戏”);
//设置大小
frame.setBounds(10, 10, 900, 720);
向窗口中添加控件
可以直接用add方法往窗口中添加控件
这里我创建GamePanel类继承自Panel,最后使用add方法添加GamePanel
加载图片
图片加载之后可以添加到窗口上
//每次刷新页面需要进行的操作
@Override
public void actionPerformed(ActionEvent e) {
//当游戏处于开始状态且游戏没有失败时
if(gameStart && !isFail) {
//蛇头所在的位置就是下一次蛇身体的位置
bodyX[++bodyIndexRight] = headX;
bodyY[bodyIndexRight] = headY;
//bodyIndexLeft++; //长度到达数组的尾部 if(bodyIndexRight==480) { for(int i=bodyIndexLeft, j=0; i<=bodyIndexRight; i++,j++) { bodyX[j]=bodyX[i]; bodyY[j]=bodyY[i]; } bodyIndexLeft=0; bodyIndexRight=length-1; } //更新头部位置 if(fdirection==1) { //头部方向为上,将蛇头向上移动一个单位 headY-=25; } else if(fdirection==2) { //头部方向为下,将蛇头向下移动一个单位 headY+=25; } else if(fdirection==3) { //头部方向为左,将蛇头向左移动一个单位 headX-=25; } else if(fdirection==4) { //头部方向为右,将蛇头向右移动一个单位 headX+=25; } //当X坐标与Y坐标到达极限的时候,从另一端出来 if(headX<25) headX = 850; if(headX>850) headX = 25; if(headY<75) headY = 650; if(headY>650) headY = 75; //当头部坐标和食物坐标重合时 if(headX==foodX && headY==foodY){ length++; score+=10; //重新生成食物,判断食物坐标和蛇身坐标是否重合,效率较慢 while(true) { foodX = 25 + 25* random.
Android Studio自带的虚拟机(AVD)运行较慢,可以用数据线连载电脑上,将编辑好的Android应用安装到手机上运行 以华为手机为例: 在手机设置上选择更多设置->开发者选项->开启开发者选项、USB调试、USB安装都开启 如果跳出是否允许手机调试同意即可
此时Android Studio即可检测到我们的手机,显示在手机上就会下载app,然后就能在手机上进行展示
目录
前言
一、Python安装
二、idea创建python项目
1.下载Python插件
2.创建Python项目
一、Python安装 下载官网:Download Python | Python.org
1、安装python运行环境
(1) 双击python-3.10.2-64bit.exe
右键以管理员身份运行,出现界面如下:1是自动默认安装,不建议!2是自定义安装,选这个就没错了,3是必须勾选的,加入系统变量。
一般采用自定义安装比较好,不然自动安装会把环境安装到个人目录里,有时要找起来很麻烦
另外红框前面的勾记录打上,不然需要手动在windows环境变量的路径中添加python安装路径
(2)全部勾选
(3)最好更改下路径,放在容量多的一个盘里;
(4)安装完成
2、代码编写
(1)编辑方式一
(2)编辑方式二
打开开始菜单,点击IDLE
File——>New Dile
程序写完之后,先保存,然后Run
二、idea创建python项目 1.下载Python插件 (1)File——Settings——Plugins
下载python插件,下载完成之后,显示 Installed
2.创建Python项目 (1)File——new——Project
1)Django:是用Python开发的一个免费开源的Web框架,可以用于快速搭建高性能,优雅的网站
2)Google App Engine: 是一种让您可以在 Google 的基础架构上运行您的网络应用程序
3)SQL Support: 是支持SQL的框架
Python SDK环境:
第一种:若是没有下载python,可以利用网络环境下载
点击 OK,自动下载;
第二种:使用官网下载:Download Python | Python.org
根据安装,自定义安装路径;
创建项目时,选择自定义的路径即可