题 Tkinter实现用户登录界面。建立一个文本文件users.txt,其中每一行存储一个用户的名字和密码,二者之间使用冒号分割,例如“admin:123456”。用户输入名字和密码后,单击“Login”按钮,根据文件users.txt中存储的信息判断用户输入是否正确。如果不正确就提示“用户名或者密码不正确”,如果正确就提示“登录成功”。请将界面中的文字全部改为中文。
编写带有图形化界面的猜数字游戏,数字为100以内整数。用户输入猜测值,如果正确,弹出“您猜对了!”消息框,否则提示“猜小了”或者“猜大了”消息框。
代码 第一题 思路:首先利用tkinter的Lable来构建主要的功能,然后在按题目给定的文件名来打开文件因为这里题目给定的条件是每一行所一定使用到readlines()来把每一行的转化为列表,然后在利用split(‘:’)来用分开这样做的就是为了然后就可以赋给两个变量了,然后在利用该两个变量与用户输入的姓名与密码分别进行比较然后在利用Button创建按钮,用command来调用方法即可,还厚就是quit退出。
import tkinter denglu=tkinter.Tk() denglu['height']=200 denglu['width']=280 denglu.title("用户登录") Name=tkinter.Label(denglu,text='用户姓名', justify=tkinter.RIGHT,anchor='e' ,width=100) Name.place(x=10,y=5,width=90,height=30) UserName=tkinter.Entry(denglu,width=100) UserName.place(x=120,y=5,width=120,height=30) Name=tkinter.Label(denglu,text='用户密码', justify=tkinter.RIGHT,anchor='e' ,width=100) Name.place(x=10,y=60,width=90,height=30) Possword=tkinter.Entry(denglu,width=100,show='*') Possword.place(x=120,y=60,width=120,height=30) filepath='C:/Users/22231/Desktop/users.txt' def file(): with open(filepath,'r') as f: for line in f.readlines(): name,pwd=line.strip().split(':') if UserName.get()==name and Possword.get()==pwd: tkinter.messagebox.showinfo(title='成功',message="登录成功") return tkinter.messagebox.showinfo(title='失败',message="密码或用户名有误") return Button1=tkinter.Button(denglu,text="登录",width=100 ,command=file) Button1.place(x=20,y=130,width=100,height=30) def Quit(): denglu.quit() Button2=tkinter.Button(denglu,text="退出",width=100,command=Quit) Button2.place(x=150,y=130,width=100,height=30) denglu.mainloop() 运行结果截图:
第二题 思路:也是首先创建一个适应的窗口,然后就是创建一个文本框,然后在利用get()来获取文本框内输入的内容然后在比较随机形成的数NUM与entry.get()来比较输出对应的提示,后面就使用一个按钮来判断是否猜对即可。
import tkinter import random caishuzi=tkinter.Tk() caishuzi.title("猜数字") caishuzi['width']=280 caishuzi['height']=100 Name=tkinter.Label(caishuzi,text='请输入数字:',width=80) Name.place(x=5,y=10,width=80,height=20) entry=tkinter.Entry(caishuzi,width=80) entry.place(x=100,y=10,width=130,height=20) NUM=random.randint(1,100) def caishu(): try: if NUM>int(entry.
文章传送门 前言一、直流(AC)与交流(DC)的区别二、转换步骤:降压+整流+滤波+稳压1. 整流:交流电→直流电2. 滤波:滤除脉动直流的交流部分3. 稳压:稳定到需要的电压值 三、简单分辨直流电与交流电 前言 日常生活中用到的都是220V的交流电,在将其转换为直流并且降压的情况下才能用于日常生活的机器和设备。
一、直流(AC)与交流(DC)的区别 交流(AC):电流方向随时间作周期性变化的为交流电,在一个周期内的运行平均值为零。通常波形为正弦波形、角形波、正方形波,交流电可以有效传输电力。生活中使用的市电就是具有正弦波形的交流电,拿家用的220V电来说,零线的电位是0V,火线因为时间不同分别对零线产生加减的相应电位,加的时候电流是一个方向,减的时候电流又是一个方面,这样就形成了交替变换方向的电流,所以叫做交流电。
直流(DC):方向会随着时间发生改变,但是直流电没有周期性变化。
二、转换步骤:降压+整流+滤波+稳压 1. 整流:交流电→直流电 整流电路是将工频交流电转换为脉动直流电。
原理:一个理想的整流器可视为一个开关,正半周的交流输入时,就有电压输出,如同开关接通一样。反之,如果负半周交流输入,则无电压输出,也就相当于开关切断一样。所以当正半周的交流输入,此开关的有效电阻为零。而在负半周的交流输入时,有效电阻为无穷大。
实际上整流器不可能这样理想,但相差不远。电子管整流器未导电时,其电阻极大,此时的电阻称为逆向电阻。整流器导电时,其电阻很小,此时的电阻为顺向(正向)电阻。无论任何情况,所有的整流器都只允许一个方向导电,此种特性称为单向传导或单向特性。→ 二极管有类似特性
分类:半波整流、全波整流、桥式整流。
半波整流
在变压器后接一个二极管,由于二极管具有单向导电特性,所以在一个周期内只有正半波到达负载。
但是,半波整流负半周期被全部舍弃,效率极低。
全波整流
利用副边有中心抽头的变压器和两个二极管构成的全波整流电路,可以看作由两个半波整流构成,在正半周期上边的二极管导通,在负半周期下边的二极管导通,负半周期的波形被翻上。
正半波和负半波都通过,变为正向电压,效率比半波整流高。
桥式整流
单相桥式整流电路是最常用的、最基本的将交流转换为直流的电路,开关电源、充电器中使用。桥式整流的关键元器件是整流桥,由四个二极管构成,在半个周期内只导通两个二极管,另外两个截止,相互交替。
当正半周时,二极管D1、D3导通,在负载电阻上得到正弦波的正半周。当负半周时,二极管D2、D4导通,在负载电阻上得到正弦波的负半周。在负载电阻上正、负半周经过合成,得到的是同一个方向的单向脉动电压。
效率高、直流电压波纹小。
2. 滤波:滤除脉动直流的交流部分 经过整流电路后,得到了具有波幅的正向电压,普通电子产品无法直接使用。需要通过滤波电路将脉动直流中的交流成分滤除,减少交流成分,增加直流成分。
利用电容器放电和存储电荷特性把正向的半波电压变为平稳的直流电压。
把电解电容并在整流后的电源上,并注意电解电容的正极接到电源的正极上,把电解电容的负极接到电源的负极上。上图是由两个电容并联的滤波电路。
注意:电解电容的耐压一定要比整流前的交流电压高根号2倍以上(二极管反向电压为两倍根号2倍的电容电压,二极管电流为通过负载电流的一半)(整流前电压→负载电容耐压MAX→二极管反向电压MIN)。例如24V交流电通过整流桥后,估算得到的滤波电路电压为24*1.414=33.936≈34V。后通过7824稳压器(后两位为稳压的电压值)稳压得到直流24V。
P.S. 整流桥封装要会看DATASHEET,常见型号如KBJ4005表示通过电流4A、最大反向耐压(maximum recurrent peak reverse voltage)50V,KBJ401最大反向电压100V,KBJ410最大反向耐压1KV。(均为负载电压两倍)
3. 稳压:稳定到需要的电压值 一方面,交流电的供电电压是不稳定的,因此会造成整流滤波电路输出的直流电压也不稳定;另一方面,由于整流滤波电路必然存在内阻,当负载电流发生变化时,输出电压也会受到影响而发生变化。
稳压电路采用负反馈技术,对整流后的直流电压进一步进行稳定。例如:常用的7805稳压器就是稳定到直流5V。
稳压电路繁多,有多种分类方式:
按输出电流的类型分为:直流稳压电路和交流稳压电路。
按稳压电路与负载的连接方式分为:串联稳压电路和并联稳压电路。
按调整管的工作状态分为:线性稳压电源和开关稳压电源。
按电路类型分为:简单稳压电源,反馈型稳压电源和带有放大环节的稳压电路。
最简单的稳压二极管稳压电路
稳压二极管,又叫齐纳二极管,是一种直到临界反向击穿电压前都具有很高电阻的半导体器件。在这临界击穿点上,反向电阻降低到一个很小的数值,在这个低阻区尽管流过二极管的电流变化很大,而其两端的电压却变化极小,并且这种现象的重复性很好,从而起到稳压作用。因为这种特性,稳压管主要被作为稳压器或电压基准元件使用。
其中,Vi为未稳压的输入直流电压,V0为经过稳压的直流电压,R为Dz的限流保护电阻,又起电压调整作用,DZ为稳压二极管,RL为负载电阻。
其工作原理是:此电路主要利用稳压二极管的稳压特性,即Dz反向导通后其两端的压降基本保持不变。当Vi增大引起R上的电流增大,但V0即DZ两端的电压保持恒定不变,这样Vi的增大量全部降在R上,以保持V0不变,反之亦然。在实际应用中RL的特性和DZ的特性对整个稳压过程起关键作用。
但是,稳压电路的工作范围受稳压管最大功耗的限制,即Iz不能超过一定数值。在Vi、RL及V0均为给定的条件下,R值的选取应保证在输入电压为最大值Vimax时,稳定电流Iz和稳压管允许的功耗不超过规定的最大值;在输入电压为最小值时,又能保证Iz不低于最小的稳定电流。
开关型稳压电路
开关稳压电路同样有多种分类方式:
按输入电源和输出电源的类型可分为AC-DC-AC-DC型开关稳压电路和DC-DC型开关稳压电路。
按激励方式可分为自励式和他励式。
按接控制方式分为调宽式和调频式两种,在实际的应用中,调宽式使用得较多,在目前开发和使用的开关电源集成电路中,绝大多数也为脉宽调制型。
有一个计算公式:
对于单极性矩形脉冲来说,其直流平均电压Uo取决于矩形脉冲的宽度,脉冲越宽,其直流平均电压值就越高。直流平均电压Uo可由公式计算,Uo=Um×T1/T。其中,Um为矩形脉冲最大电压值;T为矩形脉冲周期;T1为矩形脉冲宽度。
从上式可以看出,当Um与T不变时,直流平均电压Uo将与脉冲宽度T1成正比。这样,只要我们设法使脉冲宽度随稳压电源输出电压的增高而变窄,就可以达到稳定电压的目的。
三、简单分辨直流电与交流电 用万用表测量:如果用直流电压档量交流电,万用表没有反应;如果用直流电压档量直流电,万用表有正常的指示,那么,红表笔接的是正极黑表笔接的是负极;如果红表笔接的是负极,黑表笔接的是正极,万用表的指针将反起跑(向左边移动)。
目录
一 24种设计模式有哪些
二 单例模式介绍
三 代码
一 24种设计模式有哪些 因为社会化的分工越来越细,对象的创建 和 对象的使用 分开就成为了必然趋势.
对象的创建 会消耗掉系统的很多资源,所以单独对对象的创建进行研究.
六个创建型模式:高效创建对象
1 简单工厂模式
2 工厂方法模式
3 抽象工厂模式
4 创建者模式
5 原型模式
6 单例模式
七个结构型模型:对象的组成以及对象之间的依赖关系
十一个行为型模式:研究 对象的行为,提高对象之间的协作效率
二 单例模式介绍 构造函数私有化,对外提供函数
一个类有且仅有一个实例,并且自行实例化向整个系统提供
解决的问题:
提供全局需要使用的 唯一的数据访问
关键点:
1 某个类只能有一个实例
2 它必须自行创建这个实例
3 它必须自行向整个系统提供这个实例
单例模式UML
成员:静态的实例
方法:私有构造,静态的获取实例方法
创建的时机分类:
饿汉式:在类加载时创建
懒汉式:在使用时做判断,如果需要再创建
三 代码 饿汉式
package com.example.myjava; //饿汉式 public class SingleTonHungry { private static SingleTonHungry singleTonHungry = new SingleTonHungry(); private SingleTonHungry() { } public static SingleTonHungry getInstance(){ return singleTonHungry; } } 懒汉式
简介 github
Viper是适用于Go应用程序的完整配置解决方案,它被用于设计再应用程序中工作,并且可以处理所有类型的配置需求和格式,它支持以下特性:
设置默认值从 JSON、TOML、YAML、HCL、envfile 和 Java properties配置文件读取实时观看和重新阅读配置文件(可选)从环境变量中读取从远程配置系统(etcd 或 Consul)读取,并监控配置变化从命令行标志读取配置从buffer读取配置显式配置值 快速开始 快速开始以YAML为例;YAML教程
YAML name: test redis: host: 127.0.0.1 port: 6379 go package main import ( "fmt" "github.com/spf13/viper" ) type RedisConfig struct { Host string `mapstructure:"host"` Port int `mapstructure:"port"` } type ServerConfig struct { Name string `mapstructure:"name"` RedisConfig RedisConfig `mapstructure:"redis"` } func main() { v := viper.New() // 路径必须要写相对路径,相对于项目的路径 v.SetConfigFile("viper/demo01/config.yaml") if err := v.ReadInConfig(); err != nil { panic(err) } // 单个取值 name := v.
问题1、STM32CubeProgrammer 出现连接错误ST-LINK error (DEV_CONNECT_ERR)
解决方案:下载时按reset重启可以解决该问题。
简单来说就是:一种语言是否牵涉到类型间的强制转换。
C++存在类型间的强制转换,所以它不是类型安全型的语言。
Rubik 先生在发明了风靡全球的魔方之后,又发明了它的二维版本——魔板。
这是一张有 8 个大小相同的格子的魔板:
1 2 3 4 8 7 6 5 我们知道魔板的每一个方格都有一种颜色。
这 8 种颜色用前 8 个正整数来表示。
可以用颜色的序列来表示一种魔板状态,规定从魔板的左上角开始,沿顺时针方向依次取出整数,构成一个颜色序列。
对于上图的魔板状态,我们用序列 (1,2,3,4,5,6,7,8) 来表示,这是基本状态。
这里提供三种基本操作,分别用大写字母 A,B,C 来表示(可以通过这些操作改变魔板的状态):
A:交换上下两行;
B:将最右边的一列插入到最左边;
C:魔板中央对的4个数作顺时针旋转。
下面是对基本状态进行操作的示范:
A:
8 7 6 5 1 2 3 4 B:
4 1 2 3 5 8 7 6 C:
1 7 2 4 8 6 3 5 对于每种可能的状态,这三种基本操作都可以使用。
你要编程计算用最少的基本操作完成基本状态到特殊状态的转换,输出基本操作序列。
注意:数据保证一定有解。
输入格式
输入仅一行,包括 8 个整数,用空格分开,表示目标状态。
输出格式
输出文件的第一行包括一个整数,表示最短操作序列的长度。
如果操作序列的长度大于0,则在第二行输出字典序最小的操作序列。
数据范围
输入数据中的所有数字均为 1 到 8 之间的整数。
给定一个 n×mn×m 的 0101 矩阵:
a11 a12 ... a1m ... an1 an2 ... anm 定义 aijaij 与 aklakl 之间的距离为 D(aij,akl)=|i−k|+|j−l|。
对于每个元素 aij,请求出与它距离最近且值为 1 的元素 aklakl 和它的距离是多少。
另外注意,当元素 aijaij 本身就为 1 时,与它距离最近且值为 1 的元素就是它自己,距离为 0。
输入格式
第一行为两个整数,分别代表 n 和 m。
接下来的 n 行,第 i 行的第 j 个字符代表 aij。
输出格式
共 n 行,第 i 行的第 j 个数字表示 aij 与其距离最近且值为 1 的元素的距离。
数据范围
1≤n,m≤1000
输入样例:
3 4 0001 0011 0110 输出样例:
3 2 1 0 2 1 0 0 1 0 0 1 bfs起点太多可以考虑从终点开始bfs,题目要找最近的1,我们可以让1去找零 #include<bits/stdc++.
大家都知道,在ubuntu中安装一个新的软件包时,直接使用sudo apt-get install命令就好。那么,如果要卸载或者删除一个软件包呢?
1、删除为了满足依赖而安装的,但现在不再需要的软件包(包括已安装包),保留配置文件(这个命令容易导致系统无法进入系统桌面) $ sudo apt-get autoremove 高能警告:慎用本命令!!!
它会在你不知情的情况下,一股脑删除很多“它认为”你不再使用的软件。
如果不幸使用这个命令出现问题,尝试更新库和软件,apt-get update && apt-get upgrade 可能会自己解决依赖版本问题,只要是它能get到的。另外 autoremove 使用过程中千万不要中途打断。
2、删除已安装的软件包(保留配置文件),不会删除依赖软件包,保留配置文件; $ sudo apt-get remove 3、删除已安装的软件包(不保留配置文件),删除软件包,同时删除相应依赖软件包。 $ sudo apt-get purge / sudo apt-get --purge remove 4、删除已经安装过的的软件安装包,即自动将/var/cache/apt/archives/下的 所有 deb 删掉,相当于清理下载的软件安装包。 $ sudo apt-get clean 5、删除为了满足某些依赖安装的,但现在不再需要的软件包。 $ sudo apt-get autoclean apt的底层包是dpkg, 而dpkg安装软件包时, 会将*.deb文件放在/var/cache/apt/archives/中;因此本命令会删除该目录下已经过期的deb。
如何彻底卸载软件呢? 可按如下步骤:
sudo apt-get --purge remove <package> # 删除软件及其配置文件 sudo apt-get autoremove <package> # 删除没用的依赖包 sudo dpkg -l |grep ^rc|awk '{print $2}' |sudo xargs dpkg -P # 清理dpkg的列表中有“rc”状态的软件包 补充:dpkg的简介 Ubuntu是基于Debian的Linux系统,而Debian系统的软件是使用APT和dpkg进行管理。dpkg是"
又重新看了一遍何凯明大神的残差网络,之前懵懵懂懂的知识豁然开朗了起来。然后,虽然现在CSDN和知乎的风气不是太好,都是一些复制粘贴别人的作品来给自己的博客提高阅读量的人,但是也可以从其中汲取到很多有用的知识,我们要取其精华,弃其糟粕。
我只是大概的记录一下ResNet论文讲了什么,希望大家还是可以自己去读几遍。
ResNet论文链接为:https://arxiv.org/abs/1512.03385
1.前言 在读这篇文章之前,希望可以思考一个问题。残差网络到底是用来干什么的?我想很多人思考过后后的回答就是“残差网络不就是解决过深的网络引起的梯度消失和梯度爆炸这种现象嘛。”
这个回答是没问题的,但是梯度消失和梯度爆炸可以通过归一化初始化或中间层归一化来解决,还有最重要的一个原因就是过深的网络会出现网络退化的问题。何为网络退化?这里拿出原论文中的一个插图来解释。
按照正常的逻辑来说,神经网络越深训练的效果应该会越好啊,但实验推翻了我们这个结论。
假设一个比较浅的网络已经可以达到不错的效果,那么即使之后堆上去的网络什么也不做,模型的效果也不会变差。
问题就出现在这里,什么都不做就是神经网络最难做到的东西。
2. 论文解读 1. 摘要 在摘要中,作者主要是提出了一种残差结构,这种结构不需要额外的参数也更容易被优化,结果证明加了这种结构后不管是在ImageNet分类数据集上还是在COCO目标检测数据集上都有很好的效果,啊,不对,不是很好,是在大赛中都取得了第一名。
2. 引言 第一段主要介绍了一些研究背景,深度卷积网络为图像分类带来了一系列的突破。网络深度对训练模型来说也是至关重要的。
作者在第二段就表明了,随着深度的增加会出现梯度消失、梯度爆炸,但是这个问题已经在很大程度上通过归一化初始化和中间归一化层得到了解决。
第三段提出:随着网络深度的增加,精度达到饱和(这可能并不奇怪),然后迅速退化。然而,这种退化并不是由过拟合引起的,在适当深度的模型上添加更多的层会导致更高的训练误差。
第四段提出了一个名词identity mapping,我理解为输入为X,输出也为X。构造深的模型,虽然有解决方案,但是在可行时间内是不可能实现的。
第五段提出了残差网络的结构
X 为浅层网络的输出。如果我们想要得到的映射为H(X),则我们让添加的非线性网络层去拟合残差映射F(X):=H(X)-X。原始的映射就可以写成F(X)+X。图二中右侧连接为一个identity mapping。
第六段提出了shortcut connection的概念。这种连接可以跳过一层或更多层,因为F(X)和X是直接相加的。所以不需要额外的参数和更复杂的计算。
剩余部分都是在说这个模型有多好,在100层,甚至1000层的模型上效果都很好。
我们假设第一个网络在训练集和测试集上可以得到很好的性能(甚至可以理解为接近100%)。
那么在这个新的网络,由于我们copy了前四层的参数,理论上前四层已经足够满足我们的性能要求,那么新增加的层便显得有些多余,如果这个新的网络也要达到性能100%,则新增加的层要做的事情就是“恒等映射”,也即后面几个紫色的层要实现的效果为 。这样一来,网络的性能一样能达到100%。而退化现象也表明了,实际上新增加的几个紫色的层,很难做到恒等映射。又或者能做到,但在有限的时间内很难完成(即网络要用指数级别的时间才能达到收敛)。这时候,巧妙的通过添加”桥梁“,使得难以优化的问题瞬间迎刃而解。
可以看到通过添加这个桥梁,把数据原封不动得送到FC层的前面,而对于中间的紫色层,可以很容易的通过把这些层的参数逼近于0,进而实现的功能。
实际上,网络性能通常未能达到100%,可以假设最初的网络(只有前四层)的性能到了98%等等,如果不添加跳连接,增加三个紫色层之后的新网络同样难以进行优化(由上面极端情况的推广,也即前面四层的性能达到100%)。
而通过跳连接,可以把前四层的输出先送到FC层前面,也就相当于告诉紫色层:”兄弟你放心,我已经做完98%的工作了,你看看能不能在剩下的2%中发点力,你要是找不出提升性能的效果也没事的,我们可以把你的参数逼近于0,所以放心大胆的找吧。"
我们把整个映射看成100%,则前面四层网络实现了98%的映射关系,而残余的映射由紫色层完成,Residual 另一个翻译就是"残余,残留“的意思,也就是让每一个残差块,只关注残余映射的一小部分,真的是恰到好处。
当然了,实际上网络运行的时候,我们并不会知道哪几层就能达到很好的效果,然后在它们的后面接一个跳连接,于是一开始便在两个层或者三个层之间添加跳连接,形成残差块,每个残差块只关注当前的残余映射,而不会关注前面已经实现的底层映射。
不得不佩服他对神经网络的深入理解,从他灵感的来源,让我感觉他就是个数学大佬,结果一查还真是,本科是清华基础科学班的(研究物理数学的)(拿烟的手微微颤抖)。好了,废话不多说,让我们一起来理解什么是残差网络。我们先来看一个现象,假设我们有如下的一个网络,它可以在训练集和测试
这个例子来自于知乎大佬Sakura当时我看到后真的是茅塞顿开。
作者:Sakura
链接:https://www.zhihu.com/question/306135761/answer/2491142607
来源:知乎
3. 相关工作 相关工作是说在这篇论文之前已经有一些人在某些方向上使用本论文中使用的一些方法去做事。这句话很拗口,但是只要你理解了,就会发现所有论文的相关方向都是说的这东西。
4. 深度残差网络 这部分就是介绍了残差模块的构成还有各种ResNet的网络结构。
在上文中,我们说道F(X)和X直接相加,因此需要保证他们的维度一定要一样,否则就对X做投影。
关于残差网络结构(以34层为例),只截取了一部分
图右中的实线表示残差连接,虚线表示升维。
架构图:
更深的ResNet网络:
50层,101层,152层都使用图右中的结构,使用1X1的卷积主要是为了降维和升维。右边结构的参数量明显比左边的少。
总结 网络亮点:
超深的网络结构(突破1000层)提出residual模块使用Batch Normalization加速训练(丢弃dropout)
沐神很形象的描述出了为什么加一个残差连接就可以收敛。 代码实现 只是model模块
import torch.nn as nn import torch ''' 对应18层,34层的残差结构 ''' class BasicBlock(nn.
文章目录 前言 准备 上一篇
一、函数 1、单字节写 /*! \brief FLASH写 @Address 操作地址 @pData 数据指针 @Size 数据长度 */ uint8_t FMC_FLASH_Write( uint32_t Address, uint8_t *pData, uint16_t Size ) { fmc_state_enum FLASHStatus; uint16_t i; uint32_t AddressTemp = 0; /*写入数据*/ AddressTemp = Address; /* 解锁 */ fmc_unlock(); /* 操作FMC前先清空STAT 状态寄存器,非常必要*/ fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR | FMC_FLAG_PGMERR | FMC_FLAG_PGSERR); for (i=0; i<Size; i++) { FLASHStatus = fmc_byte_program(AddressTemp, pData[i]); if (*((volatile uint8_t*)AddressTemp) != pData[i]) { return 1; //校验错误 } if (FLASHStatus !
一、基本概念
1.什么是Nginx Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP代理server。其特点是占有内存少。并发能力强,其并发能力确实在同类型的网页server中表现较好。
http服务器 Web服务器是指驻留于因特网上某种类型计算机的程序。当Web浏览器(客户端)连到服务器上并请求文件时,服务器将处理该请求并将文件反馈到该浏览器上,附带的信息会告诉浏览器如何查看该文件(即文件类型)。服务器使用HTTP(超文本传输协议)与客户机浏览器进行信息交流,这就是人们常把它们称为HTTP服务器的原因。
代理服务器 通常是指局域网内部的机器通过代理服务器发送请求到互联网上的服务器,代理服务器一般作用在客户端。
反向代理 客户端向反向代理的命名空间中的内容发送普通请求,接着反向代理将推断向何处(原始服务器)转交请求,并将获得的内容返回给客户端。
正向代理 正向代理是一个位于客户端和原始服务器之间的代理服务器,为了从原始服务器取得内容,客户端向代理服务器发送一个请求并指定目标原始服务器。然后代理服务器向原始服务器转交请求并将获得的内容返回给客户端。
反向代理vs正向代理 从安全性来讲,正向代理同意客户端通过它访问随意站点而且隐藏客户端自身,因此你必须採取安全措施以确保仅为经过授权的客户端提供服务。反向代理对外都是透明的,访问者并不知道自己访问的是一个代理。
2.Nginx特点 反向代理:
上面已经说过了。
负载均衡:
当请求过多,单个服务器难以负荷时,我们增加服务器的数量,然后将请求分发到各个服务器上,将原先请求集中到单个服务器上的情况改为将请求分发到多个服务器上。
动静分离:
为了加快网站的解析速度,可以吧动态页面和静态页面由不同的服务器来解析,加快解析速度,降低原来单个服务器的压力。具体的内容见本博客后面第五章。
二、安装、常用命令、配置文件 首先你得有一个linux操作系统的环境,要么是你自己的服务器,要么是你自己电脑上的虚拟机,要么是你租的云服务器。以下以centos为例。
1.安装 安装gcc环境,用来将官网下载的源码进行编译:
yum install gcc-c++ 安装 pcre 库:
yum install -y pcre pcre-devel 安装zlib 库:
yum install -y zlib zlib-devel 安装安装 OpenSSL 库:
yum install -y openssl openssl-devel 下载nginx包:
wget -c https://nginx.org/download/nginx-1.12.0.tar.gz 解压nginx包:
tar -zxvf nginx-1.12.0.tar.gz 进入nginx文件夹:
cd nginx-1.12.0 使用默认配置:
./configure 编译安装:
make make install 到此,nginx算是安装好了。
2.常用命令 以下所有命令都必须进入sbin目录以后才能执行:
一、数据条件 二、创建名称管理 Sub 新建名称管理() ' ' 选中数据左上角 ' 依次以左侧单元格为名称,创建数据内容 ' ' 获取选中单元格 Dim rng As Range Dim rng_max As Range Start = Now() Set rng = Selection Set rng_max = Selection.End(xlDown) If rng.Value <> "" Then For i = rng.Row To rng_max.Row Cells(i, rng.Column).Select Range(Selection, Selection.End(xlToRight)).Select Selection.CreateNames Top:=False, Left:=True, Bottom:=False, Right:= _ False Next rng.Select Else MsgBox "当前单元格为空,请重新选择!" Exit Sub End If use_time = Round(Now() - Start, 2) MsgBox "
1. 问题: win10电脑中原本安装的docker,在很长一段时间没有启动之后,再次启动发现无法启动了。直接重装也无法重装。
启动docker桌面管理软件后,一直在docker engine starting卡住。
2. 原因: 因为没有安装wsl或wsl因为某些原因不可用了。
3. 解决: 打开命令行窗口,输入 wsl --list --verbose查看wsl版本,如果输出为空,则没有安装wsl,如果最后一栏version为1,则是wsl1,建议安装版本为wsl2.命令行输入wsl --set-default-version 2,设置wsl版本为2.打开任务管理器,杀掉docker相关进程。打开microsoft store, 搜索ubuntu,找到一个可用版本,点击获取进行安装。安装完成后会让设置用户名和密码,设置完成后就可以了。新打开一个命令行窗口,再次输入 wsl --list --verbose,会看到有了记录,并且version是2.重启docker desktop,会询问是否启动docker service,选择启动,等一会docker就会显示启动成功。
指向子类的指针调用虚函数和调用非虚函数注意事项 1、如果以一个基础类指针指向一个衍生类对象(派生类对象),那么经由该指针只能访问基础类定义的函数(静态联翩) 2、基类指针指向子类对象调用虚函数 class A
{
public:
virtual void foo()
{
cout << “A’s foo()” << endl;
}
};
class B: public A
{
public:
void foo()
{
cout << “B’s foo()” << endl;
}
};
int main()
{
B bobj;
A *aptr = &bobj;
aptr->foo();
}
输出:“B’s foo()”
结论:虚函数是动态绑定
3、基类指针指向子类对象调用虚函数(带默认参数) class Base
{
public:
virtual void fun ( int x = 10 )
{
cout << "Base::fun(), x = "
项目场景: 在MX_USART1_UART_Init中调用HAL_UART_Receive_IT(&huart1, RxBuffer, 1);当串口接收1字节后会调用HAL_UART_RxCpltCallback函数
记录1 HAL_UART_Receive_IT函数需要在HAL_UART_Init函数调用后再调用,因为在HAL_UART_Receive_IT会先判断uart->RxState == HAL_UART_STATE_READY,而在HAL_UART_Init会执行uart->RxState= HAL_UART_STATE_READY
代码如下:
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
if (huart->RxState == HAL_UART_STATE_READY)
{
if ((pData == NULL) || (Size == 0U))
{
return HAL_ERROR;
}
__HAL_LOCK(huart);
huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
return(UART_Start_Receive_IT(huart, pData, Size));
}
else
{
return HAL_BUSY;
}
}
在HAL_UART_Receive_IT中起作用的是UART_Start_Receive_IT函数,此函数会开启串口接收中断
记录2 HAL_UART_Receive_IT调用UART_Start_Receive_IT,在UART_Start_Receive_IT中会使能串口中断,并且执行huart->RxState = HAL_UART_STATE_BUSY_RX;
当中断来临时,USART1_IRQHandler调用HAL_UART_IRQHandler(&huart1),并判断中断类型为接收中断,然后再调用 UART_Receive_IT(huart);
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
概要:使用过 Excel 文件的小伙伴应该都非常清楚,Excel 的格式是有多种的,比如我们常见的就有 xlsx 和 xls 后缀的两种,这两种格式的区别在于是不同版本生成的文件。xls 后缀是 Excel 2003 及以前版本生成的文件格式,xlsx 后缀是 Excel 2007 及以后版本生成的文件格式。这两种格式在大部分时间都是能相互兼容的,也是能相互转化的,所以我们就可能会经常碰到需要将 xlsx 格式转换为 xlsx 格式的需求。
xls 格式是 Excel 2003 及以前版本生成的文件格式,也就是说这种格式相对于 xlsx 格式会比较老。但是在某些场景下,我们对文件的是格式是有一定要求的,比如说我们要求必须为 xlsx 后缀的 Excel 文件,但是我们已有的文件都是 xls 后缀的,那这个时候我们就需要将 xls 格式的 Excel 文档转为 xlsx 格式的文档。
说到这两种格式的转换,微软的 Office 软件都是支持直接的。因为毕竟都是自家定义的格式嘛!但是也仅仅是支持对单个 xls 格式的文档转化为单个 xlsx 格式的文档。当我们大批量大批量的文件都是 xlsx 格式,并且都需要转换为 xlsx 格式的时候。那我们就不可能再去通过 Office 打开文件,一个一个的进行处理了。因为这样不仅效率非常低下,还特别费时费力,并且还可能会容易出错、漏处理文件。
为了能够比较高效、比较方便的将 xls 格式转化为 xlsx 格式,我们就需要借助一个工具「我的ABC软件工具箱」,通过这个工具,我们非常方便的就能够将批量 xls 格式的 Excel 文件快速的转为 xlsx 格式的 Excel 文件,我们可以一起来看下具体的操作。
打开「我的ABC软件工具箱」后在左侧选择「格式转换」,右侧进入「Excel 转换为其它格式」的功能。
按照上图所示,我们点击对应的菜单进入到功能内部,进入后我们就可以按照提示选择需要进行格式转换的 Excel 文件,可以同时选择多个 .
Fcitx5 是继 Fcitx 之后的新一代输入法框架,优麒麟2204 默认安装的是 Fcitx,而 Fcitx 和 Fcitx5 是相互冲突的,因此安装Fcitx5之前需要先卸载 Fcitx。关于 Fcitx5 的学习文档,推荐 Archlinux 关于 Fcitx5 的 wiki 文档
一、卸载 Fcitx 输入法 1.首先看看大概装了哪些 Fcitx 输入法组件 $ apt search fcitx | grep 安装 fcitx/jammy,jammy,now 1:4.2.9.8-5 all [已安装] fcitx-baidupinyin/jammy-partner,now 1.0.1.0 amd64 [已安装] fcitx-bin/jammy,now 1:4.2.9.8-5 amd64 [已安装] fcitx-config-common/jammy,jammy,now 0.4.10-3 all [已安装] fcitx-config-gtk/jammy,now 0.4.10-3 amd64 [已安装] fcitx-data/jammy,jammy,now 1:4.2.9.8-5 all [已安装] fcitx-frontend-all/jammy,jammy,now 1:4.2.9.8-5 all [已安装] fcitx-frontend-gtk2/jammy,now 1:4.2.9.8-5 amd64 [已安装] fcitx-frontend-gtk3/jammy,now 1:4.2.9.8-5 amd64 [已安装] fcitx-frontend-qt5/jammy,now 1.
目录 题意解题思路代码实现运行结果总结 题意 定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
解题思路 使用双栈的方式,一个栈存储输入的数据、另一个存入当前数据位置到第一个数据中最小值。可以使min、push 及 pop 的时间复杂度都是 O(1)。
代码实现 #include <stdio.h> #include <stdlib.h> #include <malloc.h> typedef struct stack { int value; struct stack *next; } stack_t; typedef struct { stack_t *head; stack_t *min; } MinStack; /** initialize your data structure here. */ void stack_push(stack_t *head, int value) { stack_t *node = NULL; if (head == NULL) return ; node = (stack_t *)malloc(sizeof(stack_t)); if (node == NULL) return ; node->value = value; node->next = head->next; head->next = node; } int stack_pop(stack_t *head) { int value = -1; stack_t *node; if (head == NULL || head->next == NULL) return value; node = head->next; head->next = node->next; value = node->value; free(node); return value; } MinStack* minStackCreate() { MinStack *node = NULL; node = (MinStack *)malloc(sizeof(MinStack)); if (node == NULL) return NULL; node->head = (stack_t *)malloc(sizeof(stack_t)); if (node->head == NULL) { free(node); return NULL; } node->head->next = NULL; node->min = (stack_t *)malloc(sizeof(stack_t)); if (node->min == NULL) { free(node->head); free(node); return NULL; } node->min->next = NULL; return node; } void minStackPush(MinStack* obj, int x) { int min = -1; if (obj == NULL || obj->head == NULL || obj->min == NULL) return ; if (obj->head->next == NULL && obj->min->next == NULL) min = x; else min = obj->min->next->value < x ?
gdb基本命令 开始调试:
首先使用gcc命令完成源代码文件的编译
编译完成后,通过gdb命令 进入调试模式
【基本操作】 简写全称含义b 7break在第7行设断点rrun运行程序p iprint打印变量innext单步执行display i监控变量i(=n后p的执行效果)undisplay取消监控回车重复执行上一条命令kill杀死正在调试的程序ccontinue继续运行您的程序 (在停止之后,比如在一个断点之后)infoinformation查看信息set设置变量的值 set var=valuefile指定源代码位置watch为当前表达式设置观察点 【断点操作】 b break 设置断点
info b 显示断点信息
可以看到此时Enb(enable)的值为 y
disable 1(1为断点的Num值)将断点关闭
可以看到此时Enb(enable)的值为 n,且此时执行r(run)命令时,程序执行过程中没有中断,直接执行到了程序结束
dl +断点数字编号 删除断点
clear 删除所有断点
enable 1 将断点开启
此时执行程序过程中遇到Breakpoint后中断
【函数堆栈操作】 函数栈层向上:up
向下:down
fr (frame):显示当前所在层次
frame n/简写:fr n
移动到第n层,n为栈的层次,然后可以用其他命令(info)查看此级别的变量信息
backtrace:查看函数调用的顺序(函数调用栈的信息)
【watch 命令】 watch < expr>
为表达式(变量)expr设置一个观察点,一旦其数值有变化,程序立即停止运行
rwatch < expr>
当表达式expr被读时,程序立即停止运行
awatch < expr>
当表达式expr 的值 被读或被写时程序立即停止运行
info watchpoints
列出当前所设置的所有观察点
【参数操作】 set args (参数列表) 向调试的程序传递参数
第1章 HDFS概述 1.1 HDFS 定义 HDFS(Hadoop Distributed File System),它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
适合一次写入,多次读出的场景,不支持文件修改,可以过来做数据分析。
1.2 优缺点 优点:
(1)容错性高:主要有多个副本
(2)适合处理大数据:数据规模 可达到 PB级别,文件量能够处理百万这个量级
(3)可构建在廉价机器上
缺点:
(1)数据访问有延时,做不到毫秒级别的
(2)大量小文件不能高效存储,NameNode会占用大量内存
(3) 可追加写入,不可随机修改,不支持并发写入(不支持多线程写入)
小知识课堂:
1.什么是分布式?什么是集群? 集群和分布式的区别?
(独立概念,分布式是用多台计算机并行解决不同问题、集群是整合多台计算机解决相同问题)
2.什么是主从模式?
(分布式系统节点为主从关系、分布执行且保证数据一致,相关概念:高可用模式、联邦模式)
3.什么是NameNode 、DataNode 、secondaryNameNode ,以及它们扮演的角色?
(名称节点控制作用、数据节点存储作用、助理节点备份控制节点作用)
第二章 HDFS 组成架构 2.1 组成简单介绍 名词解释:
NameNode(nn) :是一个主管、管理者Master
(1)管理HDFS的名称空间;
(2)配置副本策略;
(3)管理数据块(Block)映射信息;
(4)处理客户端读写请求。DataNode:就是Slave。NameNode下达命令,DataNode执行实际的操作。
(1)存储实际的数据块;
(2)执行数据块的读/写操作。Client:就是客户端。
(1)文件切分。文件上传HDFS的时候,Client将文件切分成一个一个的Block,然后进行上传;
(2)与 NameNode 交互,获取文件的位置信息;
(3)与 DataNode 交互,读取或者写入数据;
(4) Client提供一些命令来管理 HDFS,比如 NaneNode 格式化;
(5) Client可以通过一些命令来访问 HDFS,比如对 HDFS 增删查改操作;Secondary NameNode:并非NameNode的热备。当NameNode挂掉的时候,它并不能马上替换NameNode并提供服务。
(1)辅助NameNode,分担其工作量,比如定期合并Fsimage和Edits,并推送给NaneNode ;
(2)在紧急情况下,可辅助恢复NameNode。 2.
一、更换国内源来获取更快的更新速度 为了解决Ubuntu官方源下载或者更新软件速度慢的问题,我们通常会采用更换国内源来获取更快的速度,常用的源有阿里源,清华源,中科院源等等,
点击名称即可进入对应网站
阿里云镜像开源镜像站(已经更换地址)
阿里云镜像开源社区镜像站(新地址)
网易开源镜像站
清华大学开源镜像站
中科大开源镜像站
这里以阿里源为例。
1、打开终端ctrl + alt +t 输入以下命令,进入存放源的文件目录/etc/apt/
cd /etc/apt/ 2、将存放源的文件备份 sudo mv sources.list sources.list.bak 3、使用vi编辑sources.list文件 sudo vi sources.list
4、复制以下内容到sources.list文件中,并保存 #阿里源(Ubuntu 16.04)
deb http://mirrors.aliyun.com/ubuntu/ xenial main
deb-src http://mirrors.aliyun.com/ubuntu/ xenial main
deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates main
deb http://mirrors.aliyun.com/ubuntu/ xenial universe
deb-src http://mirrors.aliyun.com/ubuntu/ xenial universe
deb http://mirrors.aliyun.com/ubuntu/ xenial-updates universe
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates universe
deb http://mirrors.aliyun.com/ubuntu/ xenial-security main
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security main
deb http://mirrors.
#include <stdio.h> #include <conio.h> #include <windows.h> int main() { int i, j,a=1,b=1,score=0,count=0; int d1 = 1, d2 = 1, d3 = 1, d4 = 1, d5 = 1, d6= 1, d7 = 1, d8 = 1, d9 = 1, d10 = 1, d11= 1, d12 = 1, d13 = 1, d14 = 1, d15 = 1, d16 = 1, d17= 1, d18 = 1, d19 = 1, d20 = 1; char ch,dt[20][30] = { '#','#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#','1', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '*', ' ', ' ', '*', '#', '*', '*', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#', '#',' ', '#', '#', '#', ' ', '#', '#', ' ', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', ' ', '#', '#', '#', '#', '#', '#', '#', ' ', '#', '#',' ', '#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '*', ' ', ' ', ' ', ' ', ' ', '#', ' ', '#', '#','*', '#', ' ', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', ' ', '#', '#', '#', '#', '#', '#', '#', '#', ' ', '#', ' ', '#', '#',' ', '#', ' ', '#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#', ' ', '#', ' ', '#', '#',' ', '#', ' ', '#', ' ', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', ' ', '#', ' ', '#', ' ', '#', '#',' ', '#', ' ', '#', ' ', '#', '*', ' ', ' ', ' ', ' ', '#', ' ', ' ', ' ', ' ', ' ', '*', ' ', ' ', ' ', ' ', '#', ' ', '#', ' ', '#', ' ', '#', '#',' ', '#', '*', '#', ' ', '#', ' ', ' ', ' ', ' ', '*', '#', ' ', '*', ' ', ' ', '#', ' ', '*', ' ', ' ', ' ', '#', ' ', '#', ' ', '#', ' ', '#', '#',' ', '#', ' ', '#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#', ' ', ' ', ' ', ' ', '#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#', ' ', '#', ' ', '#', '#',' ', '#', ' ', '#', ' ', '#', ' ', '*', ' ', ' ', ' ', '#', ' ', ' ', ' ', ' ', '#', ' ', ' ', ' ', ' ', '*', '#', ' ', '#', ' ', '#', ' ', '#', '#',' ', '#', ' ', '#', ' ', '#', ' ', ' ', ' ', ' ', ' ', '#', '*', ' ', ' ', ' ', '#', ' ', '*', ' ', ' ', ' ', '#', ' ', '#', ' ', '#', ' ', '#', '#',' ', '#', ' ', '#', ' ', '#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '*', '#', ' ', ' ', ' ', ' ', ' ', '#', ' ', '#', ' ', '#', ' ', '#', '#',' ', '#', ' ', '#', ' ', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', ' ', '#', ' ', '#', ' ', '#', '#',' ', '#', ' ', '#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '*', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#', ' ', '#', ' ', '#', '#',' ', '#', ' ', '#', '#', '#', '#', '#', ' ', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', ' ', '#', ' ', '#', '#',' ', '#', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#', ' ', '#', '#',' ', '#', '#', '#', '#', '#', '#', ' ', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', ' ', '#', '#',' ', ' ', ' ', ' ', '#', '*', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '*', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '#','#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', }; printf("
由于服务器发挥着至关重要的作用,因此存储在服务器上的机密数据和信息非常具有价值。如今有一种流行的说法,“数据就是新的石油”。
如果不确定如何保护服务器安全,或者不确定是否已涵盖所有基础知识,那么可以了解下面提供一些可用于保护服务器的安全提示。
(1)保持软件和操作系统更新
在服务器安全方面,掌握软件和与操作系统相关的安全性修补程序至关重要。未安装修补程序的软件,经常会发生黑客攻击和入侵系统的情况。通常情况下,软件供应商会将补丁或软件更新的通知发送给客户,因此不应拖延。尽管企业可能需要测试与自己的系统环境之间的兼容性问题,但服务器软件在发布之前已经进行了广泛的测试。补丁程序管理工具、漏洞扫描工具和其他寻找安全漏洞的工具都可以提供帮助。
(2)尽可能地实现自动化和使用人工智能
人类难免犯错,大多数重大的服务器故障都是人为错误造成的。而且工作人员可能在超负荷工作,在安全方面会有一些疏漏。要执行某些功能,需要尽可能实现自动化。例如,大多数系统都支持补丁程序的自动下载和安装,并且越来越多的人工智能产品可以监视、保护和升级企业的系统。
(3)使用虚拟专用网络(VPN)
专用网络基于全球互联网协议地址空间。虚拟专用网络(VPN)是私有的专有网络,因为其互联网协议数据包无需通过公共网络进行传输。
虚拟专用网络(VPN)将允许企业在不同位置的不同计算机设备之间创建连接。它使企业可以安全地在服务器上执行操作。
企业可以与同一帐户上的其他服务器交换信息,而不会受到外界的攻击和损害。为确保服务器安全,企业应该设置虚拟专用网络。
(4)考虑零信任网络
防火墙和VPN的弱点之一是它们不能阻止内部移动。一旦黑客入侵企业的网络,几乎可以在整个网络中自由移动。这就是零信任网络的出现的原因,零信任网络不允许用户或设备访问任何内容,除非得到许可或证明。这就是所谓的“最低特权”方法,它要求对所有内容进行严格的访问控制。
(5)加密所有内容
任何数据都不应在未加密的服务器上移动。安全套接层协议(SSL)是一种安全协议,用于保护互联网上两个系统之间的通信。企业的内部系统也是如此。使用安全套接层协议(SSL)证书,只有预期的接收者才具有解密信息的密钥。
在连接到远程服务器时,使用SSH(安全外壳)对交换中传输的所有数据进行加密。使用SSH密钥进行RSA 2048位加密,对SSH服务器进行身份验证。
要在服务器之间传输文件,就需要使用安全文件传输协议(FTPS)。它可以加密数据文件和身份验证信息。
最后,要求来自防火墙外部的连接使用虚拟专用网(VPN)。虚拟专用网络(VPN)使用自己的私有网络和私有IP在服务器之间建立隔离的通信通道。
(6)不要只使用标准防火墙
防火墙是确保服务器安全的必不可少的工具,但是防火墙不仅仅是企业内部部署的防火墙,也有托管安全服务提供商(MSSP)为企业的网络提供托管防火墙服务。根据服务协议的范围,托管安全服务提供商(MSSP)可以执行防火墙安装、应用程序控制和Web内容过滤,因为它们有助于确定要阻止的应用程序和Web内容(URLS)。他们还将帮助管理补丁和更新。实际上有大量的托管安全服务提供商(MSSP可供选择。
(7)更改默认值
在大多数系统中,默认帐户是root帐户,这是黑客所针对的目标。所以需要进行更改。对于名为admin的帐户也是如此。不要在网络上使用令人关注的帐户名。
企业可以通过减少所谓的攻击向量来提高服务器安全性,这是运行所需的最低限度服务的过程。Windows和Linux的服务器版本附带许多服务,如果不需要这些服务,则应将其关闭。
Wi-Fi接入端口默认会广播其身份,如果在其范围内,则端点设备将会看到它。进入访问端口并关闭广播,因此任何想要使用它的人都必须知道访问点的真实名称。此外,企业的设备不要使用制造商的默认名称。
(8)创建多服务器或虚拟环境
隔离是企业可以拥有的最佳服务器保护类型之一,因为如果一台服务器受到威胁,黑客的攻击行为就会被锁定在该服务器上。例如,标准做法是将数据库服务器与Web应用程序服务器分开。
完全隔离将需要拥有专用的裸机服务器,这些裸机服务器不与其他服务器共享任何组件,这意味着企业需要增加更多的硬件。与其相反,实现虚拟化可以作为隔离环境。
在数据中心中具有隔离的执行环境可以实现所谓的职责分离(SoD)。职责分离(SoD)遵循“最小特权”的原则运行,这实际上意味着用户不应拥有超出其日常任务所需特权的特权。为了保护系统和数据,必须建立用户层次结构,每个用户都具有自己的用户ID和尽可能少的权限。
如果企业负担不起或不需要使用专用服务器组件进行完全隔离,则还可以选择隔离执行环境,也称之为虚拟机和容器。
(9)正确输入密码
密码始终是一个安全问题,因为很多人对密码管理有些草率。他们在多个帐户使用相同的密码,或者使用容易让人猜到的简单密码,如“password”、“abcde”或“123456”。甚至可能根本没有设置任何密码。
在设置密码时需要包含大小写字母、数字和符号的混合。并定期更改密码,另外在使用一次后禁止使用原有的密码。
(10)关闭隐藏的开放端口
网络攻击可能来自人们甚至没有意识到开放的端口。因此,不要以为知道每个端口的情况,这是不可能的事。那些并不是绝对必要的端口都应关闭。Windows Server和Linux共享一个称为netstat的通用命令,该命令可用于确定正在侦听哪些端口,同时还显示当前可能可用的连接的详细信息。
•列出所有端口的信息-“netstat -s”
•列出所有TCP端口-“netstat -at”
•列出所有UDP端口-“netstat -au”
•所有打开的侦听端口-“netstat -l”
(11)经常执行正确的备份
企业不仅需要进行定时备份,而且还应该在网络之外的异地位置进行备份。异地备份是必要的,尤其是对于勒索软件攻击来说,企业可以在其中清理受感染的驱动器。
企业还要考虑将灾难恢复即服务(DRaaS)作为即服务产品之一,该产品可通过云计算模型提供备份。它由许多内部部署供应商以及云计算服务提供商提供。
无论是自动备份作业还是人工执行,需要确保测试备份。这应该包括对管理员甚至最终用户验证数据恢复是否一致的健全检查。
(12)进行定期和频繁的安全审核
如果不进行定期审核,就无法知道可能存在的问题或如何解决这些问题,以确保企业的服务器得到完全保护。检查日志中是否有可疑或异常活动,并检查软件、操作系统和硬件固件更新,以及检查系统性能。通常情况下,黑客攻击会导致系统活动激增,硬盘驱动器或CPU或网络流量出现异常可能是黑客攻击信号。由于服务器的部署并不是一劳永逸的,必须经常对其进行检查。
前提:自行安装VMWare 1.准备至少三套CentOS7系统,入门配置:master节点需要4G4C,worker节点需要2G2C
2.每台机器配置好静态IP
3.保证各个机器之间和宿主机之间通信没有问题
一、多master节点单node节点机器配置 集群角色IP主机名安装的组件Master-1192.168.74.10master01apiserver、controller-manager、scheduler、kubelet、etcd、docker、kube-proxy、keepalived、nginx、calicoMaster-2192.168.74.11master02apiserver、controller-manager、scheduler、kubelet、etcd、docker、kube-proxy、keepalived、nginx、calicoWorker-1192.168.74.12worker01kubelet、kube-proxy、docker、calico、corednsWorker-2192.168.74.13worker02kubelet、kube-proxy、docker、calico、corednsvirtual-ip(VIP)192.168.74.110 二、各机器实验环境准备 配置虚拟机静态IP vim /etc/sysconfig/network-scripts/ifcfg-ens33 配置主机名 # 每一台机器都操作 # 机器之间可以通过主机名访问 hostnamectl set-hostname master1 && bash # 查看主机状况 hostnamectl 配置主机host文件 vim /etc/hosts # [ip] [hostname] 192.168.74.10 master01 # 【验证】互相ping域名,能够通 ping master02 ping www.baidu.com 配置主机之间无密码登录 # 要在每一台机器上都执行,且都需要拷贝(两两相互) # 使得机器之间可以无密码相互访问 ssh-keygen #一路回车,不输入密码 # 把本地生成的密钥文件和私钥文件拷贝到远程主机 ssh-copy-id master1 ssh-copy-id master2 ssh-copy-id worker1 ssh-copy-id -i /root/.ssh/id_rsa.pub master1 #【验证】在master1上执行 ssh root@master2 # 是否可以无密码跳转登录 ls -a #查看隐藏文件夹 .ssh 关闭交换分区swap # 要在每一台机器上都操作 # 避免资源耗尽导致k8s异常,提升性能 #1.
SpringBoot 整合 Redis 时间日期类转换出错 报错信息 com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.LocalDateTime` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: java.util.ArrayList[0]->com.zym.entity.Banner["gmtCreate"]) 原因:将集合等数据存入 redis 需要将其序列化,jackson 不支持数据中的 LocalDateTime 类型的属性
解决办法: 引入额外的依赖 com.fasterxml.jackson.datatype:jackson-datatype-jsr310
<dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <version>2.13.0</version> </dependency> 然后在对应的使用了 LocalDateTime 的实体类属性上添加序列化和反序列化注解,并指定对应的序列化类
@JsonDeserialize(using = LocalDateTimeDeserializer.class) // 反序列化 @JsonSerialize(using = LocalDateTimeSerializer.class) // 序列化 @TableName("edu_teacher") @ApiModel(value = "Teacher对象", description = "讲师") public class Teacher implements Serializable { private static final long serialVersionUID = 1L; @ApiModelProperty("
方案一:
之前想在本地添加个域名,解析到127.0.0.1,以为只要在host文件下加上 127.0.0.1 www.xxx.com 就行了,结果一直ping,试了多次发现 应该再加上 ::1 www.xxx.com 就行了!!!。就是这么简单
转载于:https://www.cnblogs.com/wkyhky/p/11302081.html
方案二:
如果还是无效,看一下是不是用的管理员权限修改的。
在开始图标右键->选择powerShell(管理员),然后输入一下命令:
cd C:\Windows\System32\drivers\etc notepad .\hosts 在弹出的记事本中修改并保存
方案三:
1、将hosts文件重命名为hosts.bak。
2、新建一个hosts文件放到C:\Windows\System32\drivers\etc目录下,并把hosts.bak的内容复制到hosts中。
3、添加自己的IP hostname保存。
4、ping hostname正常。
开始上手的第一步就是安装,虽然工作电脑已经尝试过,但是自己的私人电脑还没有,所以今天试着安装一下。
顺序是:node.js vue 创建 目录
一、node.js安装和配置
1.安装前,先看看自己电脑上有没有node.js
2.官网下载
3.配置环境
4.版本切换(可跳过)
5.npm安装淘宝镜像(可跳过)
二、Vue和脚手架安装
1.安装vue.js
2.安装webpack模板
3.安装vue-router
三、创建项目
1.命令创建项目
2.新手推荐
3.打包上线
4.更新
一、node.js安装和配置 1.安装前,先看看自己电脑上有没有node.js 打开命令提示符,尽量选择管理员身份打开,或者按win+R,输入cmd打开也行
打开后输入node -v 查看自己电脑是否安装node,以及版本号
node -v 我这里显示v16.13.2 就是已经安装了node,还是比较新的版本,我一般开发用v14的多,所以我等下改成14版本的,可以不改,不过有时候开发,下载依赖会有版本冲突。 2.官网下载 最新版本:Download | Node.js(点击下载) 因为node里面带npm,所以等下配置好环境就可以用npm了,这里下载的时候可以看到下载的版本。
3.配置环境 下载node后记住自己的安装位置,然后配置环境,这一步很多人都发过,可以点击node安装看看博主们发的过程。
4.版本切换(可跳过) 如果版本不适配,想换版本,可以直接在官网下载新的版本,卸载现在的版本再安装就行,也可以通过gnvm或者nvm,所以我通过nvm将版本改成v14.17.5的了,这篇文章可以看详细过程。
nvm安装、使用与报错处理(电脑安装过node版本)
我现在的版本是v14.17.5
5.npm安装淘宝镜像(可跳过) npm全称Node Package Manager,是node.js的模块依赖管理工具。由于npm的源在国外,所以国内用户使用起来各种不方便。
cnpm与npm都是下载依赖,不过cnpm有时候真的很有用,所以还是有配置一下的必要。
npm镜像的切换
查看当前库:npm config get registry 或者 npm get registry
设置官方库:npm config set registry https://registry.npmjs.org
设置淘宝镜像:npm config set registry https://registry.npm.taobao.org/
npm config set registry https://registry.
读后感《00后杀入职场:浅做一下,不行再说》 前言 今天看了一篇文章《00后杀入职场:浅做一下,不行再说》,挺有代表性的。
文章目录 读后感《00后杀入职场:浅做一下,不行再说》前言内容文章基本内容趋势预测 结尾 内容 文章基本内容 作者是2022年6月6日发布的这篇文章,核心观点是:从今年开始,大批00后将涌入职场,正式成为打工人。虽然00后才晋升为新鲜出炉的职场小鲜肉,但职场江湖上已经到流传着关于00后的传说,这不继躺平和内卷之后,00后又开始流行起「浅学」。
因为毕业的关口越是逼近就越迷茫,心有宏图而不敢展。
他们一边担心在体制内养老失去竞争力,一边又希望能有一份稳定的收入兜底;一边对大厂的996加班35裁员深恶痛绝,一边又渴望高薪有保障的大公司长脸;一边深知学历贬值让考研性价比越来越低,一边又不得不为了那零星丁点的竞争力,与千军万马再过独木桥; 这批陷入矛盾的00后,正在日益逼仄的职场现实中,负重前行。
这和我当时毕业的情况类似,大学生毕业一般就是三条路:考研留学、考公考编、工作。巧的是这三件事我都干过,不过都没走通,因为都是随大流浅尝一下,所以没有尽全力,只是主动去尝试了一下。
一、浅学
内卷:主动做,不断的卷,多做事;
躺平:主动做,不卷,做范围内的事;
摆烂:不做,不卷,摆烂;
浅学:主动做,什么都试一下,行就做,不行就不做;
其实这四种情况一直存在,甚至在不同时间段存在,不过之所以会慢慢被流行,是因为其权重在增加,最后被议论。谁都有内卷、躺平、摆烂、浅学。
二、过渡
00后正在面临**「进步式落后」**的处境。
大学毕业生规模逐年攀升,2022年中国大学毕业生预计将达到1076万人,规模和增量均创历史新高。宏观的学历「进步」下,却导致了个人因学历贬值而遭遇的「落后」。
根据教育部官方数据,2022年全国硕士研究生报名人数457万,创下历史新高,增幅达到21%。新东方发布的《23考研年度报告》预计,2023年考研全国报名人数可能突破520万,《2022中国大学生学习与发展白皮书》显示,面对“毕业后是继续深造还是直接工作”的问题,有54%的受访者希望继续深造。
与此同时,中高端岗位的增速并不能追赶上研究生人数的增速。低端蓝领岗位招不到人、中端岗位招研究生不招本科,本科生就只能继续考研。高端岗位僧多粥少,进一步造成人才学历挤压,不卷就会被别人挤下去。
而对于那些「不想卷,也卷不动」的00后来说,考研只是一个过渡期,拖延一些时间,希望未来能有别的契机。
这种情况一届比一届严重,主要是因为中高端岗位的增速并不能追赶上大学生毕业人数的增速,大学毕业后高不成低不就,要么选择低就,要么选择继续深造,这就是躺平和内卷的选择。
三、回家
996、猝死、裁员、35瓶颈……短短几年间,大厂的关键词已经不再只有光鲜亮丽。虽然依然有前仆后继的毕业生削尖脑袋想挤入大厂的围城,但越来越多00后在认识到大厂工作现实后选择了进入另一座围城:体制内。
除了「养老」,许多00后进入体制内的另一个原因是:能够有充足的时间发展副业。只有在拥有「铁饭碗」兜底的前提之下,年轻人才敢将天马行空付诸实践。
当然,父母的支持,对习惯了中国式家庭庇护的00后,也至关重要。
想考公的理由很简单:不会被辞退,考上了就可以躺一辈子了;按时按点下班、有休息日、不用为了留下来去加班内卷;可以有自己的空余时间,做点别的事情。
简直真实,卷成功的终究是少数,大部分人没卷成功,但是又不甘心,于是就衍生出了浅学,少数人选择躺平或者摆烂,大部分人还是想翻身。
趋势预测 大学毕业生规模逐年攀升,2022年中国大学毕业生预计将达到1076万人,这个其实是源自于18年前的出生率,终究会有峰值。
于是我查了一下历年出生人口。
年份总人口*出生率(万人)19491925195020101951211519522171195321231954230819552259195621311957229319582053195915681960170319611343196223781963296919642721196527711966275719672535196827901969271019702767197128081972264019732645197425141975231519762251197719711978210319792138198020301981209219822379198320701984208819852106198623881987270119882566198927791990292619912245199221581993215619941947199518641996164119971570199816851999143320001484200114612002139920031373200415122005150320061551200715522008158720091588201015882011160020121635201316402014168720151655201617862017172320181523201914652020120020211062 从1949-2021总共72年,中间有三次人口骤减,第一次是1959-1961三年自然灾害,出生人口从两千多万降到一千三百多万;第二次是计划生育落实,1994年开始的出生人口从两千多万控制到了一千三百多万;第三次是年轻育龄妇女婚育推迟,2018年开始的出生人口从1723万降到了1523万,并且逐年递减。
现在2022年,第一批00后毕业了,他们2000年的出生人口是1484万人,这个人口波动一直持续到了2018年。也就是以后每一年的大学生毕业人数峰值在他们出生人口那个数,也就是最多一千四百多万,或者1786万人(2016年出生人口)。到2042年,那一年的大学生毕业人数最多一千二百万人。
九年制义务教育将裹挟后面的三年高中和四年大学,平均受教育年限16年,如果加上幼儿园的三年,一个22岁的成年人受教育年限将达到19年。必须扣一个666。从三岁开始学,持续到大学,然后看情况步入社会或者继续深造。
社会越来越稳定,每个人都被安排得稳稳当当,每年大约两千万人左右出生和去世,每个年代大约两亿人,七个年代就是十四亿人。0-20岁的人大约有四亿人,20-50岁的人大约六亿人,50-70大约四亿人。每年有四亿人在受教育,四亿人准备养老,中间还有六亿人在工作。教育、医院、社会各行各业,每个人在这三大块中做着自己的事情。
结尾 随便写写,想到哪写到哪。
今天是2022年6月8日祝高考学子(2004年出生)高考顺利(预计中的2026年大学毕业生)
首先定义全局变量变量
app.config.globalProperties.name = '我爱L' 应用配置 | Vue.js
获取实例,访问全局属性
const internalInstance = getCurrentInstance() internalInstance.appContext.config.globalProperties // 访问 globalProperties 访问某个全局属性
<template> <div>{{proxy.name}}</div> </template> <script setup> import { getCurrentInstance } from 'vue' const {proxy} = getCurrentInstance(); </script> 如果是想使用某个组件的api,可以挂载全局,但是css不显示咋办?
官网有写到
快速开始 | Element Plus
因为是ElMessageBox,所以按照他的规则找到
import 'element-plus/es/components/message-box/style/css' 完整代码
<script setup> import { getCurrentInstance } from 'vue' import 'element-plus/es/components/message-box/style/css' const {proxy} = getCurrentInstance() proxy.$Alert('This is a message', 'Title', { confirmButtonText: 'OK', callback: (action ) => { ElMessage({ type: 'info', message: `action: ${action}`, }) }, }) </script>
1、 flex
justifyContent: 'center', // 控制水平居中
alignItems: 'center' // 控制垂直居中
<div style={{ background: 'pink', width: '400px', height: '400px', display: 'flex', justifyContent: 'center', alignItems: 'center' }}> <div style={{ background: 'white', width: '50px', height: '50px' }}> 1111 </div> </div> 2、定位(父元素相对定位,子元素绝对定位)
<div style={{ background: 'pink', width: '400px', height: '400px', position: 'relative' }}> <div style={{ background: 'white', width: '50px', height: '50px', position: 'absolute', top: '50%', left: '50%', marginLeft: '-25px', marginTop: '-25px' }}> 1111 </div> </div> 3、css3的transform
当我们在 LIiux 中输入 ll-i 指令时,会显示文件信息:
权限、拥有者、所属组等这些我都知道,但是最前面的比如 1051810 是什么,还有权限后面的3和6是什么呢?本章我们就来讲解一下 inode 和 硬链接数。
透析文件系统: 在磁盘文件中,包含了文件属性+文件内容,文件属性包含了文件的元信息,每一个文件为了方便查找,会起一个唯一的编号:inode,为了方便理解,inode 号我们可以认为它是一个文件的身份证。
inode 是任何一个文件的属性集合,是储存文件元信息的区域,中文译名为"索引节点"。Linux 中几乎每个文件都有,因为存在大量的文件,为了区分才有的 inode。我们的文件内容一般存在硬盘中,硬盘中会有许多扇区,扇区中的块,块就是用来储存内容的,现在的块一般大小是 4k。
我们日常输入的 ls 和 cat 指令,其实本质就是指令变成进程,在磁盘上找到对应的文件信息和文件内容,把其加载到操作系统上,给到用户。
磁盘结构: 我们先来了解一下磁盘文件系统图:
1 和 2 一般是用来描述 inode 和 data blocks 的使用情况,使用了多少?还剩多少?
inode Table 中包含了文件属性信息,而 Data table 包含了文件的数据,它们的空间使用由对应的位图 Bitmap 决定。
iode Table 中包含了属性 inode ID 和 数据 inode blocks[15] 等,数组中的每个下标对应的是使用的块,每一块储存数据后,写入到 blocks 中,每一块是 4kb。
查看文件信息时,就是通过指针或者 inode ID 找到属性,在找到数据;而 inode Bitmap 和 Block Bitmap 是为了查看 inode Table 和 Data Blocks 有哪些被占用,用位图查看比特位的方式。
pinia-学习之路 03,storeToRefs 及 改变数据状态 引言 本系列会以我的一个理解,来介绍并开始学习 Pinia。
中间会插入自己所联系到的 乱七八糟 的 知识点。
问题 通过上一节中,我们发现,通过解构赋值这种形式,发现数据它并不是响应式的。
那其实问题还是挺严重的,因为我们如果修改了这个值,其它地方引入的这个值,按理来说也应该需要跟着进行变动,是需要保证它是响应式数据才不会出错。
所以这里通过 Pinia 提供的响应式方法,storeToRefs 来处理。
storeToRefs 内部主要做了什么?
进入 hello.vue 文件中,改变文件内容为
import { mainStore } from '../store/index' import { storeToRefs } from 'pinia' const store = mainStore() const { hello: myHello } = storeToRefs(store) // 响应式数据 console.log('myHello', myHello) // 非响应式数 const hello2 = 'hello2 world2' console.log('myHello2', hello2) 这样我们的数据就会是响应式数据。
这里再次注意!!!
这里再次注意!!!
这里再次注意!!!
上述情况的发生,是因为我们定义的是基本数据类型,而且没有使用 storeToRefs,所以出现了上述解构赋值,没有发生响应式数据。
下面我会再测试一下引用数据类型的解构赋值,是否会出现同样的情况。
改变数据状态 上面我们只是使用了 store 的 state,还并未对 state 里面的数据进行修改,下面我们尝试改变一下 state 里面的数据状态。
文章目录 🧑🎓前言🥃安装前准备🍉安装🤝 总结 🧑🎓前言 大家好,本篇为本人在学习linux过程中所需要的软件以及安装过程,随手记录一下,写得不是很好,还请大家批评指正!
🥃安装前准备 软件:VMware
下载地址:https://www.vmware.com/
安装直接一路点确认就行很简单的,我用的是16版本的
镜像:CentOS7
下载地址:
官网:https://www.centos.org/download/
阿里云https://developer.aliyun.com/mirror/
或华为云https://mirrors.huaweicloud.com/os/image
这个进去界面就有各种镜像版本和下载,相信这个就不用我多说了哈
各版本的区别,我用的是DVD标准版本的
1、CentOS-7-DVD版本:DVD是标准安装盘,一般下载这个就可以了。
2、CentOS-7-NetInstall版本:网络安装镜像。
3、CentOS-7-Everything版本:对完整版安装盘的软件进行补充,集成所有软件。
4、CentOS-7-LiveGnome版本:GNOME桌面版。
5、CentOS-7-KdeLive版本:KDE桌面版。
6、CentOS-7.0-livecd版本:光盘上运行的系统,类拟于winpe
🍉安装 1.打开我们的虚拟机选择新建虚拟机
2.典型安装与自定义安装
典型安装:VMware会将主流的配置应用在虚拟机的操作系统上,对于新手来很友好。
自定义安装:自定义安装可以针对性的把一些资源加强,把不需要的资源移除。避免资源的浪费。
这里我选择自定义安装。
3.这里选择稍后安装,当然也可以选择安装安装程序光盘映像文件
4.选择操作系统,这里选择linux的CentOS7版本
5.设置虚拟机的名字(随意)和选择安装的位置
6.设置磁盘大小(建议根据实际来),一般默认就够用了但是注意不要勾选立即分配所有磁盘,否则虚拟机会将100G直接分配给CentOS,会导致宿主机所剩硬盘容量减少。接着勾选将虚拟磁盘拆分成多个文件,这样可以使虚拟机方便用储存设备拷贝复制。
7.接着选择自定义硬件(当然也可以点完成后在外面进去设置)
8.进去之后选择DVD勾选使用ISO映像文件,浏览把之前下载好的镜像找到放进去
9.接着设置一些基本的虚拟机设置
设置虚拟机网络:
网络连接类型一共有桥接、NAT、仅主机和不联网四种。
桥接:选择桥接模式的话虚拟机和宿主机在网络上就是平级的关系,相当于连接在同一交换机上。
NAT:NAT模式就是虚拟机要联网得先通过宿主机才能和外面进行通信。
仅主机:虚拟机与宿主机直接连起来
桥接与NAT模式访问互联网过程,如下图所示
我这边选择的是桥接模式
设置内存大小(根据需求来)一般按照他这边建议来差不多够用,我这边设置的为4GB
还有就是可以把不需要的一些给删掉如下
10.上述工作完成之后就可以进入虚拟机里完成里面的一些设置了
11.开启虚拟机后会出现以下界面:
Install CentOS 7 安装CentOS 7
Test this media & install CentOS 7 测试安装文件并安装CentOS 7
Troubleshooting 修复故障
通过键盘的上下键来选择进行哪项操作(记得先把鼠标点进去哈)
我们选择第一项直接安装即可
12.选择安装语言,我这边选择中文(英文水平太低😂😂😂)键盘的话先选美式的暂时(不会影响安装,进去后还可以设置)
13.设置时间,地区选择亚洲,上海,在把时间也设置成当前时间即可
14.接着选择软件安装,这个根据需求来,这边我选择的是GNOME桌面,右边的附加选项同理,
15.设置安装位置,进行磁盘的分区(不会的话也可以选择自动),这边我的分区情况如下图所示
设置完后点击我接受更改
一、安装nodejs
官网直接下载 Node.js
This package has installed: Node.js v16.15.1 to /usr/local/bin/nodenpm v8.11.0 to /usr/local/bin/npm Make sure that /usr/local/bin is in your $PATH.
二、使用 npm安装cnpm
sudo npm install -g cnpm --registry=https://registry.npm.taobao.org
sudo npm install -g cnpm --registry=https://registry.npm.taobao.org Password: npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead. added 361 packages in 17s 11 packages are looking for funding run `npm fund` for details npm notice npm notice New minor version of npm available!
准备工作: 电脑一台并下载和解压好adb工具包 1.打开ADB模式 按如下路径进入: 选择【设置】-【关于】 选中【版本号】(或【产品型号】)快速多次按遥控器【确认】键,得到提示电视进入“开发者模式” 然后选择【设置】-【账户与安全】 选中【ADB调试】设置为“允许” 至此,电视机就可以进行adb连接啦。 查看电视机ip地址(后续连接电视机需用到): 【设置】-【网络】-【有线网络】或【无线网络】:IPV4地址:192.168.2.4 2.电脑连接电视机 win+R 输入 cmd 进入电脑的dos界面; 进入到adb所在目录: cd C:\Users\marshal\Desktop\adb 连接电视: adb connect 192.168.2.4:5555 再按回车 连接成功后接下来就可以远程控制电视了; 3. 卸载软件 复制下列命令后按回车即可 软件和服务包名卸载操作命令备注系统更新升级adb shell pm uninstall --user 0 com.xiaomi.mitv.upgrade开机广告 adb shell pm uninstall --user 0 com.miui.systemAdSolution
adb shell pm uninstall --user 0 com.xiaomi.mitv.advertise
视频头条adb shell pm uninstall --user 0 com.duokan.videodaily小米商城adb shell pm uninstall --user 0 com.xiaomi.mitv.shop时尚画报adb shell pm uninstall --user 0 com.xiaomi.tv.gallery定时提醒adb shell pm uninstall --user 0 com.
1.top 用法
top [-d number] | top [-bnp]
-d:number代表秒数,表示top命令显示的页面更新一次的间隔。默认是5秒。
-b:以批次的方式执行top。
-n:与-b配合使用,表示需要进行几次top命令的输出结果
-p:指定特定的pid进程号进行观察
这个命令用于动态监控进程所占系统资源,每隔 3 秒变一次。这个命令的特点是把占用系统资源(CPU,内存,磁盘 IO 等)最高的进程放到最前面。top 命令打印出了很多信息,包括系统负载(loadaverage)、进程数(Tasks)、cpu 使用情况、内存使用情况以及交换分区使用情况。其实上面这些内容可以通过其他命令来查看,所以用 top 重点查看的还是下面的进程使用系统资源详细状况。这部分东西反映的东西还是比较多的,不过需要关注的也就是几项:%CPU, %MEM, COMMAND,RES 这一项为进程所占内存大小,而 % MEM 为使用内存百分比。在 top 状态下,按 “shift + m”, 可以按照内存使用大小排序。按数字 ‘1’ 可以列出各颗 cpu 的使用状态。
2. uptime 这个命令可以一次显示为:现在时间,系统运行了多久时间,目前有多少登录用户,系统过去的1分钟,5分钟,15分钟的平均负载。
3.free free 命令显示系统内存的使用情况,包括物理内存、交换内存(swap)和内核缓冲区内存。
并且有时我们需要持续的观察内存的状况,此时可以使用 -s 选项并指定间隔的秒数n。
空闲内存 :availavle =free+buffer(缓冲)+cache(缓存) 4. mpstat 这个命令主要是查看CPU核状态。
5.ifstat 这个命令展示的是网卡网络状态。
6.df 这个是查看磁盘使用率。
通过这几个命令我们就可以了解到我们的系统的负载情况,从而进行优化提高系统性能。
【时间】2022.06.07 周二
【题目】【Flink入门(5)】Flink的时间语义与Watermark
本专栏是尚硅谷Flink课程的笔记与思维导图。
目录
引言
一、时间(Time)语义
三种时间语义
二、Watermark(水位线)
2.1 概述
乱序数据的影响
2.2 特点
2.3 Watermark相关知识
1)向下游传递
2)在stream中引入(代码)
3)设置合适的WaterMark延时时间 4)窗口起始点计算
2.4 Flink处理迟到数据的3层保障
总思维导图
引言 flink中有3种时间语义,这里主要讲EvenTime事件时间,从数据的时间戳中提取,属于事件创建(数据产生)的时间,区别于数据到达时间(Ingestion Time)和处理时间(Processing Time)。 Watermark(水位线)是一种处理乱序数据的机制,相当于扩宽window窗口以处理迟到数据。 一、时间(Time)语义 三种时间语义 二、Watermark(水位线) 2.1 概述 乱序数据的影响 2.2 特点 WaterMark的作用是延迟关闭前一个窗口的时间,以处理迟到的数据:
2.3 Watermark相关知识 1)向下游传递 上游Task的watermark广播给下游Task,下游Task取最小WM:
2)在stream中引入(代码) 例子:
public class WindowTest3_EventTimeWindow { public static void main(String[] args) throws Exception { StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); // Flink1.12.X 已经默认就是使用EventTime了,所以不需要这行代码 // env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime); env.getConfig().setAutoWatermarkInterval(100); // socket文本流 DataStream<String> inputStream = env.
文章目录 前言一、贝叶斯优化是什么?二、贝叶斯优化基本流程二、贝叶斯优化用于HPO总结 前言 目前机器学习领域中常见的超参数优化方法包括网格搜索、随机网格搜索、Halving网格搜索与贝叶斯优化。
其中网格搜索、随机网格搜索与Halving网格搜索,无论具体每种网格搜索的思想如何变化,网格优化都是在一个大参数空间中、尽量对所有点进行验证后再返回最优损失函数值的方法,这一类方法在计算量与计算时间上有着不可避免的缺陷,因此才会有随机、Halving等试图缩短训练时间、让整体网格搜索更加适合于大型数据和大型空间的手段。然而,尽管sklearn在提高网格搜索效率方面做出了种种优化,但上述方法仍然无法在效率和精度上做到双赢,若希望更快速的进行参数搜索、并且搜索出一组泛化能力尽可能强的参数,目前的常见做法还是选用一些带有先验过程的调参工具,即一些基于贝叶斯过程调参工具。
一、贝叶斯优化是什么? 贝叶斯优化方法是当前超参数优化领域的SOTA手段(State of the Art),可以被认为是当前最为先进的优化框架,它可以被应用于AutoML的各大领域,不止限于超参数搜索HPO的领域,更是可以被用于神经网络架构搜索NAS以及元学习等先进的领域。现代几乎所有在效率和效果上取得优异成果的超参数优化方法都是基于贝叶斯优化的基本理念而形成的,因此贝叶斯优化是整个AutoML中学习的重点。
二、贝叶斯优化基本流程 首先,我们不理会HPO的问题,先来看待下面的例子。假设现在我们知道一个函数 f ( x ) f(x) f(x)的表达式以及其自变量 x x x的定义域,现在,我们希望求解出 x x x的取值范围上 f ( x ) f(x) f(x)的最小值,你打算如何求解这个最小值呢?面对这个问题,无论是从单纯的数学理论角度,还是从机器学习的角度,我们都已经见过好几个通俗的思路:
1 我们可以对 f ( x ) f(x) f(x)求导、令其一阶导数为0来求解其最小值 函数 f ( x ) f(x) f(x)可微,且微分方程可以直接被求解
2 我们可以通过梯度下降等优化方法迭代出 f ( x ) f(x) f(x)的最小值 函数 f ( x ) f(x) f(x)可微,且函数本身为凸函数
3 我们将全域的 x x x带入 f ( x ) f(x) f(x)计算出所有可能的结果,再找出最小值 函数 f ( x ) f(x) f(x)相对不复杂、自变量维度相对低、计算量可以承受
package cn.weblab.plugin.util; import java.io.*; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; /** * ZipUtils * * @author shuai * @date 2021/7/30 */ public class ZipUtils { public static void main(String[] args) throws Exception { File sourceFile = new File(System.getProperty("user.dir")); fileToZip(sourceFile); } /** * sourceFile一定要是文件夹 * 默认会在同目录下生成zip文件 * * @param sourceFilePath * @throws Exception */ public static void fileToZip(String sourceFilePath) throws Exception { fileToZip(new File(sourceFilePath)); } /** * sourceFile一定要是文件夹 * 默认会在同目录下生成zip文件 * * @param sourceFile * @throws Exception */ public static void fileToZip(File sourceFile) throws Exception { if (!
UE5 物体高速移动产生拖影(运动残影) 给一个物体加上一个location的变化,当这个值达到一定大小时,运动会产生残影
速度较小时则不会,或者说不那么明显
这个是因为UE5的抗锯齿采样方法方法改成了 TSR- Temporal Super Resolution
该方法主要是将低分辨率游戏画面扩展至高分辨率,类似英伟达的DLSS,减轻显卡压力从而提高游戏帧率。
但这也是产生运动拖影的原因。
解决方案就是将抗锯齿方法改成 TAA,就会消除拖影
但同时会产生另外一个问题,就是闪面较严重
解决方法就是调整材质里的像素深度偏移值或者直接拉远两个物体的距离
问题描述
输入格式
输入的第一行包含空格分隔的三个正整数 、 和 ,分别表示出行计划数目、查询个数以及等待核酸检测结果所需时间。
接下来输入 行,其中每行包含用空格分隔的两个正整数 、,表示一项出行计划;出行计划按时间顺序给出,满足 。
最后输入 行,每行仅包含一个正整数 ,表示一个查询。 个查询亦按照时间顺序给出,满足 。
输出格式
输出共 行,每行一个整数,表示对应查询的答案。
样例输入
#70分
import java.util.Scanner; public class Main{ public static void main(String[] args) { // TODO Auto-generated method stub Scanner in=new Scanner(System.in); int n,m,k; n=in.nextInt(); m=in.nextInt(); k=in.nextInt(); int x,y; int t[]=new int [n]; int t_s[]=new int [n]; for(int i=0;i<n;i++) { x=in.nextInt(); y=in.nextInt(); t[i]=fun(x,y); t_s[i]=x; } int resout[]=new int[m]; for(int i=0;i<m;i++) { int count=0; int tcheck=in.
在数字图像处理领域,对于时空域图像的增强一般包括运用直方图均衡、亮度变换、空域平滑和锐化等方法实现对于给定图像的时空域的增强。
本文所展示的内容包括:
(1)计算并绘制图像直方图,编程实现图像的直方图均衡化处理,显示均衡前后的直方图和图像;
(2)编程实现亮度变换函数;
(3)编程实现图像的空域平滑和锐化。
数字图像时空域增强原理:
在对图像进行处理之前,了解图像整体或局部的灰度分布情况非常必要。对图像的灰度分布进行分析的重要手段就是建立图像的灰度直方图(Density Histogram),利用图像灰度直方图,可以直观地看出图像中的像素亮度分布情况;通过直方图均衡化,可以对图像的质量进行调整。
(1)生成并绘制图像的直方图
假设一幅数字图像的像素总数为N,在范围[0,G]内共有L个灰度级,其直方图定义为离散函数,其中,rk是区间[0,G]内的第K级的亮度,nk是灰度级为rk的图像中的像素数。
对于uint 8类图像,G的值为255;对于uint 16类图像,G的值为65535;对于double类图像,G的值为1.0。记住,MATLAB中的索引不能为0,故r1相当于灰度级0,r2相当于灰度级1,如此等等,rL相当于灰度级G。其中,uint 8类图像或uint 16类图像中G=L-1。
通常,会用到归一化直方图,即用所有元素h(rk)除以图像中的像素总数N所得到的图形:
P(rk)表示灰度级rk出现的频数。
MATLAB图像处理工具箱提供了imhist函数来计算和显示图像的直方图,其调用格式为:
imhist(I,b)
[COUNTS,X] = imhist(I)
其中I为输入图像,b为指定的灰度级数目,默认值为256。[COUNTS,X]=imhist(…)返回直方图统计的数据和相应的灰度级向量X。使用表达式p= imhist(I,b)/N就可简单地获得归一化直方图,这里N为图像中的像素总数。显示图像’lean.bmp’的直方图及归一化直方图,如图1所示。
(a) 原图 (b) 直方图 (c) 归一化直方图
图1 灰度图像的直方图及归一化直方图
如果图像的灰度分别集中在较窄的区间,从而引起图像细节的模糊,为了增强图像,可通过改善各部分亮度的比例关系,即通过直方图的方法来实现。这种方法是以概率论为基础的,常用的方法有直方图均衡化和直方图匹配(规定化)。
(2) 直方图均衡化
直方图均衡化也叫做直方图均匀化,是将一已知灰度概率密度分布的图像,经过某种变换,变成一幅具有均匀灰度概率密度分布的新图像,此时图像的熵最大,图像所包含的信息量最大,且扩展了像元取值的动态范围,从而达到增强图像整体对比度的效果。
设一幅图像总像元数为N,灰度级的个数为L,第K个灰度级rk出现的频数为nk,则第k灰度级出现的概率为
此时变换函数可表示为
根据原图像的直方图统计值就可算出均衡化后各像元的灰度值。直方图上灰度分布较密的部分被拉伸;灰度分布较稀疏的部分被压缩,使图像对比度总体上得到增强。
MATLAB图像处理工具箱提供了直方图均衡函数histeq。其调用格式为:
J = histeq(I,n);
[J,T] = histeq(I,…);
其中,n是均衡化后的灰度级数目,是一个可选参数,缺省值是64。[J,T]=histeq(I,…)返回能从图像I的灰度直方图变换成图像J的直方图的变换函数T。显示图像’RSImg.gif’的直方图均衡化前后的图像及对应的直方图,如图2所示
(a)原图像 (b) 直方图均衡化后图像
(c) 原图的直方图 (d) 均衡化后的直方图
图2 直方图均衡化前后的图像及其直方图
经过均衡化后,原图中较暗区域中的一些细节更清晰。
(3) 亮度变换函数
空域处理图像增强中,令T表示对输入图像f的一种操作,即,T可针对像素(x, y)的邻域定义;或针对一系列的输入图像(例如多幅图像按像素求和去噪)定义。
T最简单的形式1×1邻域,此时s=T(r)称为灰度级变换函数、亮度变换函数、或映射变换函数。由于对图像中某点的增强只与该点的灰度级有关,此类技术也称点处理。常用的三种基本类型函数:线性(正比,反比)、对数(对数,反对数)、幂次(n次幂,n次方根)。如图3所示。
图3 基本亮度映射函数
①反比变换(负片变换)
作用:增强嵌入于图像暗区的白色或灰色细节。 ②对数变换
,c为常数。
对数变换的作用:对低灰度值的窄范围进行展宽,对高灰度值的宽范围进行压缩。对数变换使图像的低灰度值范围得以扩展;高灰度值范围得以压缩,使图像的灰度分布与人的视觉特性相匹配。另外,对数变换可压缩图像的动态范围。
引擎版本:5.0.2
博主在写BUG的过程中,遇到了问题,我需要在UObject中调用WorldSubsystem。但是呢,当我在继承自UObject类的蓝图类中调用WorldSubsystem时,就会出现以下报错:
Function’Get XXXXSubsystem’ is unsafe to call from blueprints of class ‘XXXBlueprint’。
Pin ‘Context Object’ must have a connection。
这是因为在蓝图中 Get XXXSubsystem函数会自动调用UObject的GetWorld函数,但我们的UObject当前并没有被生成,是没有Outer的,所以自然没有办法获取到World的。
首先,我们需要重写GetWorld函数。
当我尝试了GEngine->GetWorld(),发现其为空之后,再翻阅许多文献之后,发现GEngine->GetWorldContexts()可以获取到当前所有的WorldContext。所以,为了确定我们需要的World,我们需要定位WorldContext。因此,我在GetWorld中添加了以下代码:
for (auto WorldContext : GEngine->GetWorldContexts()) { if (UXXXSubsystem* TempUADS = WorldContext.World()->GetSubsystem<UXXXSubsystem>()) { return WorldContext.World(); } } 这样,就总能定位到具有WorldSubsystem的那个GameWorld了。
51单片机简介
\\\插播一条:文章末尾有惊喜哟~///
一、51单片机标识信息
通常我们所说的51单片机是指以51内核扩展出的单片机。出产51单片机的厂商很多,51单片机的型号也很多。下表列出了一些51单片机的厂商和型号。
以上提到的单片机都是51内核扩展出来的单片机,只有学会了51单片机的应用,这些单片机也就根本都能使用了。单片机都是相通的,不管是51单片机还是其它单片机,都是用户编程控制来实现一定的功能。
接下来的一个系列的文章中以STC89C516RD+单片机为根底进行讲解。下面我们对这个单片机的标识进行解释:
STC—前缀,表示芯片为STC公司生成的产品。
8—表示该芯片为8051内核的芯片。
9—表示内部含FLASH存储器,还有如80C51中的0表示内部含Mask ROM(掩模ROM)存储器;如87C51中7表示内部焊EPROM存储器(紫外线可擦除ROM)。
C—表示该器件为CMOS产品。还有如89LV52和89LE58中的LV和LE都表示该芯片为低电压产品(通常为3.3V电压供电);而89S52表示该芯片含有可串行下载功能的FLASH存储器,即具有ISP可在线编程功能。
5—固定不变。
16—表示该芯片内部程序存储空间的大小。16为63KB,还有如1为4KB,2为8KB,3为13KB,4为16KB,8为32KB。程序空间大小决定了一个芯片所能装入执行代码的多少。一般来说,程序存储空间越大芯片价格也越高,所以我们在选择芯片时要依据自己须要对单片机型号进行选择。只有程序能装的下,同类芯片的不同型号不会影响其功能。
RD+—表示单片机内部RAM的代销,RD+表示内部RAM为1280B,还有如RC为512B。
二、 51单片机外部引脚介绍
51单片机有多种封装,我们这个系列文章对应的单片机是40脚的PDIP封装。该封装的引脚图如下图所示。
PDIP封装的单片机的实物图如下图所示。
另外,还有20,28,32,44等不同引脚数的51单片机。44脚PQFP/LQFP封装的单片机的引脚图如下图所示。
PQFP/LQFP封装的单片机的实物图如下图所示。
44引脚的单片机还有PLCC封装,引脚图如下图所示。
PLCC封装单片机的实物图如下图所示。
虽然单片机的封装和引脚定义不同,但是其只是外在形式的不同,内部构造和使用方法是相同的,接下来我们以PDIP封装的单片机为例对单片机的引脚进行讲解。
VCC(40脚)、VSS(20脚)—单片机的电源引脚,不同型号的单片机须要接入对应的电源电源电压。开发板上配带的单片机的供电电压为5V,低压单片机的电压为3.3V,用户在使用时要查看芯片手册,确保接入正确的电压。
XTAL1(19脚)、XTAL2(18脚)—外部时钟引脚,XTAL1为内部振荡电路的输写端,XTAL2为内部振荡电路的输出端。8051的时钟有两种方式,一种是片内时钟振荡方式,须要在这两个引脚上外接石英晶体和振荡电容,振荡电容的值一般为10pf~30pf;另一种是外部时钟方式,须要将XTAL1接地,外部时钟信号由XTAL2脚输写。
RST(9脚)—单片机复位引脚。当输写不间断两个机器周期以上为高电平时为有效,用来完成单片机的复位初始化操作,复位后程序计数器PC=0000H,即复位后将从程序存储器的0000H单元读取第一条指令码,通俗的讲,就是单片机从头初始执行程序。
PSEN(29脚)—程序存储器允许输出控制端。在读外部程序存储器时PSEN低电平有效,以实现外部程序存储器单元的读操作,由于此时我们使用的单片机内部已经有足够大的ROM,所以简直没有人再去扩展外部ROM,因此这个引脚大家只需了解即可。
ALE/PROG(30脚)—在单片机扩展外部RAM时,ALE用于控制把P0口的输出低8位地址送锁存器锁存起来,以实现低位地址和数据的隔离。ALE有可能是高电平也可能是低电平,当ALE是高电平时,允许地址锁存信号,当访问外部存储器时,ALE信号会跳变(即由正变负)将P0口上低8位地址信号送入锁存器;当ALE是低电平时,P0口上的内容和锁存器输出一致。关于锁存器的内容,我们后面会有详细介绍。在没有访问外部存储器期间,ALE以1/6振荡周期频次输出(即6分频),当访问外部存储器时,以1/12振荡周期输出(即12分频)。从这里能够看到,当系统没有进行扩展时,ALE会以1/6振荡周期的固定频次输出,因此能够作为外部时钟,或作为外部定时脉冲使用。PROG为编程脉冲的输写端,单片机的内部有程序存储器(ROM),它的作用是用来寄存用户须要执行的程序,那么我们怎样才能将写好的程序存入这个ROM中呢?实际上,我们是通过编程脉冲输写才写进去的,这个脉冲的输写端口就是PROG。此时有很多单片机都已经不须要编程脉冲引脚往内部写程序了,假如我们用的STC单片机,它能够直接通过串口往里面写程序,只须要三条线与计算机相连即可。而且此时的单片机内部都已经带有丰盛的RAM,所以也不须要再扩展RAM了,因此ALE/PROG这个引脚的用途也已经不大。
EA(31脚)— EA接高电平时,单片机读取内部程序存储器。当扩展有外部ROM时,当读取完内部ROM后自动读取外部ROM。EA接低电平时,单片机直接读取外部ROM。8031单片机内部是没有ROM的,所以在使用8031单片机时,这个引脚是一直接低电平的。8751单片机烧写内部EPROM时,利用此引脚输写21V的烧写电压。由于此时我们用的单片机都有内部ROM,所以一般在设计电路时此引脚始终接高电平。
I/O口引脚—P0口、P1口、P2口和P3口。
P0口(32脚~39脚)—双向8位三态I/O口,每个口可独立控制。51单片机P0口内部没有上拉电阻,为高阻状态,所以不能正常地输出高/低电平,因此该组I/O口在使用时务必要外接上拉电阻,一般我们选择接入10k欧的上拉电阻。
P1口(1脚~8脚)—准双向8位I/O口,每个口可独立控制,内带上拉电阻,这种接口输出没有高阻状态,输写也不能锁存,故不是真正的双向I/O口。之所以称它为“准双向”是由于该口在作为输写使用前,要先向该口进行写1操作,然后单片机内部才可正确读出外部信号,也就是要使其先有个“准”备过程,所以才称为准双向口。单片机P1.0引脚的第二功能为T2定时器/计数器的外部输写,P1.1引脚的第二功能为T2EX捕捉、重装触发,即T2的外部控制端。
P2口(21脚~28脚)—准双向8位I/O口,每个口可独立控制,内带上拉电阻,与P1口相似。
P3口(10脚~17脚)—准双向8位I/O口,每个口可独立控制,内带上拉电阻,作为第一功能使用时就当做普通I/O口,与P1口相似,作为第二功能使用时,各引脚的定义如下表所示。值得强调的是,P3口的每一个引脚均可独立定义为第一功能的输写/输出或第二功能。
P3口的第二功能定义
51单片机与STM32单片机架构的区别
佳沫
单片机第一步——51单片机
俗话说:“天才第一步,XX纸尿裤。”哈哈!扯远了。不过,我们今天说的,的确可能是绝大多数嵌入式工程师或者电子爱好者接触的第一款单片机——51单片机。图为51单片机驱动LED点阵的电子制?
嵌入式Li...发表于嵌入式
单片机51和stm32编程步骤一样吗?
我是在10年前自学的单片机。那个时候主要是学的51单片机入门的,从零根底到靠这个找到工作前后大略花了3-5个月左右,详细多久我忘记了。那个时候竞争还没此时这么大,很多新型的单片机也?
没际单片机
单片机是什么?51单片机和stm32有什么区别?
我是10年前就接触单片机了,当时这个名字其实听着挺low的,也很冷门。假如在几年前,你说没听过单片机那很正常,假如放到今天,你没听过,那只能说你有点掉队了。由于你每天接触单片机的?
没际单片机发表于没际百科
彩蛋:最近有同学跟我要单片机的资料,我特意花几个月时间,总结了我10年产品研发经验,资料包几乎覆盖了C语言、单片机、模电数电、原理图和PCB设计、单片机高级编程等等,非常适合初学者入门和进阶。除此以外,再含泪分享我压箱底的22个热门开源项目,包含源码+原理图+PCB+说明文档,不是市面上打包卖的那种课程,我认为教程多未必是好事,10年前我自学快,除了自身执行力以外,还有就是教程少。不要害羞做伸手党,等你一个小红点。后期我也会组建一些纯技术交流的小圈子,让大家能认识更多的大佬,有个好的圈子,你对行业的认知一定是最前沿的。
Idea常用快捷键 Tab,代码标签输入完成后,按 Tab,生成代码 Ctrl+E,最近的文件 Ctrl+X,删除行 Ctrl+D,复制行 Alt+1,快速打开或隐藏工程面板 ctrl+alt+t 快速代码块(try catch等) ctrl+/ 快速注释(单/多行) ctrl+shift+/ 快速注释 Alt+Shift+Up/Down,上/下移一行 alt+shift+m 将选中的代码抽取出来 Idea快捷键(全) Ctrl+Shift + Enter,语句完成 “!”,否定完成,输入表达式时按 “!”键 Ctrl+E,最近的文件 Ctrl+Shift+E,最近更改的文件 Shift+Click,可以关闭文件 Ctrl+[ OR ],可以跑到大括号的开头与结尾 Ctrl+F12,可以显示当前文件的结构 Ctrl+F7,可以查询当前元素在当前文件中的引用,然后按 F3 可以选择 Ctrl+N,可以快速打开类 Ctrl+Shift+N,可以快速打开文件 Alt+Q,可以看到当前方法的声明 Ctrl+P,可以显示参数信息 Ctrl+Shift+Insert,可以选择剪贴板内容并插入 Alt+Insert,可以生成构造器/Getter/Setter等 Ctrl+Alt+V,可以引入变量。例如:new String(); 自动导入变量定义 Ctrl+Alt+T,可以把代码包在一个块内,例如:try/catch Ctrl+Enter,导入包,自动修正 Ctrl+Alt+L,格式化代码 Ctrl+Alt+I,将选中的代码进行自动缩进编排,这个功能在编辑 JSP 文件时也可以工作 Ctrl+Alt+O,优化导入的类和包 Ctrl+R,替换文本 Ctrl+F,查找文本 Ctrl+Shift+Space,自动补全代码 Ctrl+空格,代码提示(与系统输入法快捷键冲突) Ctrl+Shift+Alt+N,查找类中的方法或变量 Alt+Shift+C,最近的更改 Alt+Shift+Up/Down,上/下移一行 Shift+F6,重构 – 重命名 Ctrl+X,删除行 Ctrl+D,复制行 Ctrl+/或Ctrl+Shift+/,注释(//或者/**/) Ctrl+J,自动代码(例如:serr) Ctrl+Alt+J,用动态模板环绕 Ctrl+H,显示类结构图(类的继承层次) Ctrl+Q,显示注释文档 Alt+F1,查找代码所在位置 Alt+1,快速打开或隐藏工程面板 Ctrl+Alt+left/right,返回至上次浏览的位置 Alt+left/right,切换代码视图 Alt+Up/Down,在方法间快速移动定位 Ctrl+Shift+Up/Down,向上/下移动语句 F2 或 Shift+F2,高亮错误或警告快速定位 Tab,代码标签输入完成后,按 Tab,生成代码 Ctrl+Shift+F7,高亮显示所有该文本,按 Esc 高亮消失 Alt+F3,逐个往下查找相同文本,并高亮显示 Ctrl+Up/Down,光标中转到第一行或最后一行下 Ctrl+B/Ctrl+Click,快速打开光标处的类或方法(跳转到定义处) Ctrl+Alt+B,跳转到方法实现处 Ctrl+Shift+Backspace,跳转到上次编辑的地方 Ctrl+O,重写方法 Ctrl+Alt+Space,类名自动完成 Ctrl+Alt+Up/Down,快速跳转搜索结果 Ctrl+Shift+J,整合两行 Alt+F8,计算变量值 Ctrl+Shift+V,可以将最近使用的剪贴板内容选择插入到文本 Ctrl+Alt+Shift+V,简单粘贴 Shift+Esc,不仅可以把焦点移到编辑器上,而且还可以隐藏当前(或最后活动的)工具窗口 F12,把焦点从编辑器移到最近使用的工具窗口 Shift+F1,要打开编辑器光标字符处使用的类或者方法 Java 文档的浏览器 Ctrl+W,可以选择单词继而语句继而行继而函数 Ctrl+Shift+W,取消选择光标所在词 Alt+F7,查找整个工程中使用地某一个类、方法或者变量的位置 Ctrl+I,实现方法 Ctrl+Shift+U,大小写转化 Ctrl+Y,删除当前行 Shift+Enter,向下插入新行 psvm/sout,main/System.
我们首先要明确的是,互联网大厂,在整个互联网行业里面,它是金字塔的塔尖儿,诸如BATTMD等大厂是在这十几年互联网浪潮中的成功案例。但他们在整个行业里面就像宇宙中那的耀眼的几颗明星,不代表大厂一裁员了,整个行业进入寒冬了。
大家自己观察大厂的人员调整,往往是根据业务线和部门来进行优化的,这是因为现在大厂普遍进入到了一个阶段性瓶颈期,在之前砸了几十上百亿对于去布局各条赛道业务线,
但是大家注意,这背后需要业务线第一年可以烧钱试错,第两年就得小步快跑,第三年就得见到效。一旦某个业务线发现距离盈利预期还很遥远,互联网的玩法就不能继续再支持下去了,那这个部门就会被优化掉,而公司的核心,那些真正盈利的那些部门还都在。
所以大可不必担心大厂裁员会对行业产冲击
下一期我们跟大家谈一谈
大厂裁员现象背后的深层原因?
用到的数据库表:
用户表:chat-user,用于存放用户的基本信息,比如账号、密码、头像等等
用户的注册
1.先获取用户信息
使用wx.getUserProfile接口,获取用户的基本信息
功能描述 获取用户信息。页面产生点击事件(例如 button 上 bindtap 的回调中)后才可调用,每次请求都会弹出授权窗口,用户同意后返回 userInfo。该接口用于替换 wx.getUserInfo,详见 用户信息接口调整说明。 可以与一个事件进行绑定。
2.用户输入账号密码,把基本信息添加到数据库chat-user中
wx.cloud.database().collection("chat-user").add({ data:{ number:Date.now(),//账号 pas:that.data.pas1,//密码 touxiang:that.data.userInfo.avatarUrl,//头像 name:that.data.userInfo.nickName,//用户微信名 admin:that.data.zh//用户 }, 完成这一步,用户的基本信息就上传到数据库中了。
同时为了之后更好的调用程序,可以将获取到的值赋值给本页的data和全局的globalData。
注意:
2.1.账号为了防止重复,我们使用data.now时间函数生成。
2.2.在用户进行输入的时候,我们有两个框让让他们进行输入,一个是昵称,另外一个是密码。为了防止用户密码出现失误,可以让用户输入两次密码一致后才注册成功。
2.3.灵活的使用 wx.showToast,弹出窗口进行提示是否成功。
3.页面跳转
调用组件wx.switchTab,直接跳转到tabar页面。
进行登录
1.获取用户的账号和密码
使用input组件就就可以实现。
以获取密码为例
getpassword(e){//获取输入框密码 console.log(e.detail.value) this.setData({ pas1:e.detail.value }) }, 在js页面中,把获取到的信息负责给此页面中的data,为了下一步的数据中查询用户账号信息做准备。
2.根据获取到的账号密码,对数据库进行查询,获取查询到的结果。
注意:res._id是已经获取到的用户输入的账号。
//查询数据库获取这个数据 wx.cloud.database().collection("chat-user").doc(res._id).get({ success(res1){ app.globalData.userInfo=res1.data//赋值给全局 wx.switchTab({ url: '/pages/message/message', }) wx.showToast({ title: '登录成功!', }) } }) 查询成功后,把返回的值赋值给全局data和本页面的data,以便进行接下来的操作。
综合使用
1.用户点击登录进入界面,可以选择直接登录或者注册。
2.若直接登录,则执行登录逻辑。
3.如果用户进行注册,则执行注册逻辑。
首先跳转到注册页面,之后判断获取用户是否获取微信信息,若没有获取,可以加一个提升窗口。
如果已经获取用户信息,则执行注册逻辑。
4.每一次获取数据库表中的内容之后,都需要将内容赋值给本页的data和全局的data。
5.注册或者登录成功后,跳转到页面首页。
单片机和FPGA的区别 FPGA更偏向于硬件电路,是用来设计芯片的芯片(FPGA)。通过硬件编程语言在FPGA芯片上自定义集成电路的过程;单片机偏向于软件,是在已有的固化电路的芯片(单片机)上设计开发。通过软件编程语言描述软件指令在硬件芯片上的执行; FPGA简介 FPGA(Field-Programmable Gate Array), 即现场可编程门阵列,它是在PAL、GAL、CPLD等可编程器件的基础上进一步发展的产物。它是作为专用集成电路(ASIC)领域中的一种半定制电路而出现的,既解决了定制电路的不足,又克服了原有可编程器件门电路数有限的缺点。 FPGA的工作原理 FPGA采用了逻辑单元阵列LCA(Logic Cell Array)这样一个概念,内部包括 可配置逻辑模块CLB(Configurable Logic Block)、输出输入模块IOB(Input Output Block)和内部连线(Interconnect)三个部分。现场可编程门阵列(FPGA)是可编程器件,与传统逻辑电路和门阵列(如PAL,GAL及CPLD器件)相比,FPGA具有不同的结构。FPGA利用小型查找表(16×1RAM)来实现组合逻辑,每个查找表连接到一个D触发器的输入端,触发器再来驱动其他逻辑电路或驱动I/O,由此构成了既可实现组合逻辑功能又可实现时序逻辑功能的基本逻辑单元模块,这些模块间利用金属连线互相连接或连接到I/O模块。FPGA的逻辑是通过向内部静态存储单元加载编程数据来实现的,存储在存储器单元中的值决定了逻辑单元的逻辑功能以及各模块之间或模块与I/O间的联接方式,并最终决定了FPGA所能实现的功能,FPGA允许无限次的编程。 FPGA的特点 采用FPGA设计ASIC电路(专用集成电路),用户不需要投片生产,就能得到合用的芯片。FPGA可做其它全定制或半定制ASIC电路的中试样片。FPGA内部有丰富的触发器和I/O引脚。FPGA是ASIC电路中设计周期最短、开发费用最低、风险最小的器件之一。FPGA采用高速CMOS工艺,功耗低,可以与CMOS、TTL电平兼容。 单片机简介 单片机,全称为单片微型计算机(Single-Chip Microcomputer),又称微控制器(Microcontroller),是把中央处理器、存储器、定时/计数器(Timer/Counter)、各种输入输出接口等都集成在一块集成电路芯片上的微型计算机。它的最大优点是体积小,可放在仪表内部,但存储量小,输入输出接口简单,功能较低。由于其发展非常迅速,旧的单片机的定义已不能满足,所以在很多应用场合被称为范围更广的微控制器。 单片机的工作原理 单片机自动完成赋予它的任务的过程,也就是单片机执行程序的过程,即一条条执行的指令的过程,所谓指令就是把要求单片机执行的各种操作用的命令的形式写下来,这是在设计人员赋予它的指令系统所决定的,一条指令对应着一种基本操作;单片机所能执行的全部指令,就是该单片机的指令系统,不同种类的单片机,其指令系统亦不同。为使单片机能自动完成某一特定任务,必须把要解决的问题编成一系列指令(这些指令必须是选定单片机能识别和执行的指令),这一系列指令的集合就成为程序,程序需要预先存放在具有存储功能的部件——存储器中。存储器由许多存储单元(最小的存储单位)组成,就像大楼房有许多房间组成一样,指令就存放在这些单元里,单元里的指令取出并执行就像大楼房的每个房间的被分配到了唯一一个房间号一样,每一个存储单元也必须被分配到唯一的地址号,该地址号称为存储单元的地址,这样只要知道了存储单元的地址,就可以找到这个存储单元,其中存储的指令就可以被取出,然后再被执行。 单片机的特点 体积小,结构简单控制能力强低电压,低功耗优异的性能、价格比 FPGA和单片机的区别 结构上的区别 单片机是一种微处理器,类似于电脑CPU的,它一般采用的是哈佛总线结构,或者冯诺依曼结构,对单片机的编程很大程度上要考虑到它的结构和各个寄存器的作用,单片机用途比较广,一般用在控制流水线上。FPGA 它的结构是查找表结构,其程序不用去太考虑芯片的结构,要注意的是时序上问题,它的结构比较复杂,功能也很强大,一般应用在通信领域等比较高端的场合。单片机是一个微控制器,通过加载模块软件来实现某种功能,单片机是成型的芯片;FPGA是用来设计芯片的芯片。 速度上的区别
FPGA由于是硬件电路,运行速度直接取决于晶振速度,系统稳定,特别适合高速接口电路。单片机由于是单线程,哪怕是常用的M3系列流水线也是单线程执行,程序语句需要等待单片机周期才能执行。本质上的区别 FPGA和单片机的区别,本质上是软件和硬件的区别,FPGA更偏向于硬件电路,而单片机更偏于软件。单片机设计属软件范畴;它的硬件(单片机芯片)是固定的,通过软件编程语言描述软件指令在硬件芯片上的执行;FPGA设计属硬件范畴,它的硬件(FPGA)是可编程的,是一个通过硬件描述语言在FPGA芯片上自定义集成电路的过程; 应用上的区别
应用上,差别更大。MCU(Microcontroller Unit,微控制单元)最终所有的指令在一个MCU中都是顺序执行的,而FPGA由于是逻辑单元,很容易做到并行执行。
MCU:微控制单元(Microcontroller Unit;MCU) ,又称单片微型计算机(Single Chip Microcomputer )或者单片机,是把中央处理器(Central Process Unit;CPU)的频率与规格做适当缩减,并将内存(memory)、计数器(Timer)、USB、A/D转换、UART、PLC、DMA等周边接口,甚至LCD驱动电路都整合在单一芯片上,形成芯片级的计算机,为不同的应用场合做不同组合控制。入门的难易程度
单片机比FPGA简单些,价格也低一些。要做PID算法控制的用单片机可以,STM32F4系列已经到300M+跑PID完全足够,如果是跑嵌入式的话可以上ARM芯片。涉及通信、图像等高速部分可以采用单FPGA模块。
目录
一、从a++说起为什么使用AtomicInteger
二、原理分析
三、总结
java并发包里面的类一直是学习和面试的重点,这篇文章主要是对java并发包的其中一个类AtomicInteger的讲解。从为什么要出现AtomicInteger再到其底层原理来一个分析。
一、从a++说起为什么使用AtomicInteger 我们知道java并发机制中主要有三个特性需要我们去考虑,原子性、可见性和有序性。volatile关键字可以保证可见性和有序性却无法保证原子性。而这个AtomicInteger的作用就是为了保证原子性。我们先看一个例子。
在上面的这个例子中,我们定义了一个变量a。并且使用了5个线程分别去增加。为了保证可见性和有序性我们使用了volatile关键字对a进行修饰。在这里我们只测试原子性。如果我们第一次接触的话肯定会觉得5个线程,每个线程加10,最后结果一定是50呀。我们可以运行一边测试一波
很明显,可能跟你想象的不一样。为什么会出现这个问题呢?这是因为变量a虽然保证了可见性和有序性,但是缺没有保证原子性。其原因我们可以来分析一下。
对于a++的操作,其实可以分解为3个步骤。
(1)从主存中读取a的值
(2)对a进行加1操作
(3)把a重新刷新到主存
这三个步骤在单线程中一点问题都没有,但是到了多线程就出现了问题了。比如说有的线程已经把a进行了加1操作,但是还没来得及重新刷入到主存,其他的线程就重新读取了旧值。因为才造成了错误。如何去解决呢?方法当然很多,但是为了和我们今天的主题对应上,很自然的联想到使用AtomicInteger。下面我们使用AtomicInteger重新来测试一遍:
在上面的代码中我们使用了AtomicInteger来定义a,而且使用了AtomicInteger的函数incrementAndGet来对a进行自增操作。现在我们再来测试一遍。
现在使用了AtomicInteger,不管你测试多少次,最后结果一定是50。为什么会出现这样的结果呢?AtomicInteger又是如何保证了这样的特性呢?下面我们就正式的开始揭开其面纱。
二、原理分析 上面的例子中我们只是调用了incrementAndGet函数来进行自增操作。其实AtomicInteger类为我们提供了很多函数。可以先使用一下。
1、基本使用
最常用的方法就是这么几个。当然了还有很多其他的方法。对于上面几个函数,每一个函数的意思都已经列了出来。意思都很简单。下面我们就通过源码的角度分析一下AtomicInteger的真正原理。
2、源码分析
既然AtomicInteger使用了incrementAndGet函数,那我们就直接来看这个方法,对于其他的方法也是同样的道理。我们直接看源码,这里使用的是jdk1.8的版本,不同的版本会有出入。
在这里我们会看到,底层使用的是unsafe的getAndAddInt方法。这里你可能有一个疑问了,这个unsafe是个什么鬼,而且还有一个valueOffset参数又是什么,想要看明白,我们从源码的开头开始看起。
开头在Unsafe的上面会发现,有一行注释叫做Unsafe.compareAndSwapInt。这又是什么?带着这些疑问我们开始一点一点揭开其面纱。
(1)compareAndSwapInt的含义
compareAndSwapInt又叫做CAS,如果你将来找工作,这个不清楚的话,基本上可以告别java这个方向了。
CAS 即比较并替换,实现并发算法时常用到的一种技术。CAS操作包含三个操作数——内存位置、预期原值及新值。执行CAS操作的时候,将内存位置的值与预期原值比较,如果相匹配,那么处理器会自动将该位置值更新为新值,否则,处理器不做任何操作。
我看过无数篇文章,对这个概念都是这样解释的,但是一开始看会一脸懵逼。我们使用一个例子来解释相信你会更加的清楚。
比如说给你儿子订婚。你儿子就是内存位置,你原本以为你儿子是和杨贵妃在一起了,结果在订婚的时候发现儿子身边是西施。这时候该怎么办呢?你一气之下不做任何操作。如果儿子身边是你预想的杨贵妃,你一看很开心就给他们订婚了,也叫作执行操作。现在你应该明白了吧。
对于CAS的解释我不准备长篇大论讲解。因为里面涉及到的知识点还是挺多的。在这里你理解了其含义就好。
(2)Unsafe的含义
在上面我们主要是讲解了CAS的含义,CAS修饰在Unsafe上面。那这个Unsafe是什么意思呢?
Unsafe是位于sun.misc包下的一个类,Unsafe类使Java语言拥有了类似C语言指针一样操作内存空间的能力,这无疑也增加了程序发生相关指针问题的风险。在程序中过度、不正确使用Unsafe类会使得程序出错的概率变大,使得Java这种安全的语言变得不再“安全”,因此对Unsafe的使用一定要慎重。
这里说一句题外话,在jdk1.9中,对Usafe进行了删除,所以因为这,那些基于Usafe开发的框架慢慢的都死掉了。
在这里也就是说,Usafe再进行getAndAddInt的时候,首先是先加1,然后对底层对象的地址做出了更改。这个地址是什么呢?这就是涉及到我们的第三个疑问参数了。
(3)valueOffset的含义
这个valueOffset是long类型的,代表的含义就是对象的地址的偏移量。下面我们重新解释一下这行代码。
unsafe.getAndAddInt(this, valueOffset, 1) + 1。这行代码的含义是,usafe通过getAndAddInt方法,对原先对象的地址进行了加1操作。现在应该明白了。我们return的时候,也是直接返回的最新的值。这一点我们对比另外一个方法incrementAndGet就能看出。
在这个方法的源代码中我们可以看到最后的+1操作没有了,也就是说,直接返回的是旧地址的值,然后再进行自增操作。如何去拿的地址的偏移量呢?是通过下面这个代码。
OK,到了这一步相信你已经知道了,usafe对a的值使用getAndAddInt方法进行了加1操作。然后返回最新的值。那么这个getAndAddInt方法是如何实现的呢?我们可以在进入看看:
这段代码的含义也很清晰。底层还是通过compareAndSwapInt这个CAS机制来完成的增加操作,
第一个参数var1表示的是当前对象,也就是a。
第二个参数var2表示的是地址偏移量
第三个参数var3表示的是我们要增加的值,这里表示为1
对于AtomicInteger的原理就是这,主要是通过Usafe的方式来完成的。Usafe又是通过CAS机制来实现的,因此想要弄清整个原子系列的真正实现,就是要搞清楚CAS机制。不过我会在下一章节进行讲解。
3、其他方法
对于其他方法其实也是同样的道理,我们可以给出几个看看。
我们可以看到底层基本上还是Usafe来实现的。Usafe又是经过CAS实现。
三、总结 对于jdk1.8的并发包来说,底层基本上就是通过Usafe和CAS机制来实现的。有好处也肯定有一个坏处。从好的方面来讲,就是上面AtomicInteger类可以保持其原子性。但是从坏的方面来看,Usafe因为直接操作的底层地址,肯定不是那么安全,而且CAS机制也伴随着大量的问题,比如说有名的ABA问题等等。关于CAS机制,我也会在后续的文章中专门讲解。大家可以先根据那个给儿子订婚的例子有一个基本的认识。
一.Redis的淘汰策略 1.为什么要淘汰 Redis的数据读写基于内存,Redis虽然快,但是内存成本还是比较高的,而且基于内存Redis不适合存储太大量的数据。Redis可以使用电脑物理最大内存,当然我们通常会通过设置maxmemory参数限制Redis内存的使用, 为了让有限的内存空间存储更多的有效数据,我们需要设置淘汰策略,让Redis自动淘汰那些老旧的,或者使用频率很低的数据。
Redis 确定删除某个键值对后,会删除这个数据并将这个数据变更消息发布到本地(AOF 持久化)和从机(主从连接)。
如果不设置太太策略的话,当Redis中的数据越来越多,如果达到堆限制,将导致Redis的内存不足异常而终止所以我们在使用Redis时一定要配置淘汰策略。 关于设置Key过期时间的方式方法前面文章有详细介绍,知道你们懒得找,把传送门也给你们附上 Redis如何设置Key的过期时间
2.淘汰策略有哪些 volatile-lru:使用LRU算法从已设置过期时间的数据集中淘汰最近最少使用的数据(expires)
allkeys-lru:根据LRU算法从所有数据集中淘汰最近最少使用的数据(dict)
volatile-lfu:从已设置过期时间的数据集挑选使用频率最低的数据淘汰(expires)
allkeys-lfu:从数据集中挑选使用频率最低的数据淘汰(dict)
volatile-random:从已设置过期时间的数据集中随机淘汰数据(expires)
allkeys-random:所有数据集中随机淘汰数据(dict)
volatile-ttl:从已设置过期时间的数据集中淘汰最近过期的数据(expires) noeviction:不会过期,当内存超过设置的最大内存时写操作报错,读操作正常(默认配置)
分类的方法很多,我是按照算法分类的,即分为LRU、LFU、TTL和RANDOM四种
LRU和LFU算法的区别:
LRU是从满足算法条件的数据中选择空闲时间最长的
LFU是从满足算法条件的数据中选择使用频率最低的
两者功能没有太大差别,具体性能没有做过测试,我都是随便选一种用就可以啦,如果想继续深入研究的话欢迎交流
3.淘汰策略配置 3.1.最大内存配置
方式一:修改配置文件中的 maxmemory,放开注释, 根据业务需求设置大小
maxmemory <100mb #设置最大内存大小为100MB 方式二:命令行设置
127.0.0.1:6379> config get maxmemory #命令行查看当前设置最大内存 127.0.0.1:6379> config set maxmemory 100mb #设置Redis最大占用内存大小为100MB 3.2.淘汰策略配置
方式一:修改配置文件中的 maxmemory-policy ,放开注释,根据业务需求修改即可
maxmemory-policy noeviction #noeviction 为默认的策略,根据业务需求修改即可 方式二:命令行设置
127.0.0.1:6379> config get maxmemory-policy #命令行查看当前淘汰策略 127.0.0.1:6379> config set maxmemory-policy noeviction #noeviction 为默认的策略 至此,Redis的淘汰策略就到这里吧,下面几期会跟大家聊聊我们的代码中该如何操作Redis。看情况可能还会跟大家聊一些关于Redis的主流客户端和集群,因为我发现越深入浏览量越低,所以在考虑要聊点其他的还是再稍微深入一些。ps因为五一假期玩的太爽啦,酝酿了点也都已经发出来了,上周末调休加上最近手头的项目有点赶进度,所以这一期有点短。还望各位看官点个赞再走吧,给您劈个叉~
1、recv()函数的返回值:
>0:接收到的数据大小;
=0:连接关闭;
<0:出错。
在出错的情况下,
这三种错误下认为连接是正常的,继续接收
if(errno == EINTR ||(errno == EAGAIN)||errno == EWOULDBLOCK)
continue;
if(FD_ISSET(connfd,&r_set) { int irecv,iunrecv; iunrecv = length; while(iunrecv>0) { irecv = recv(concfd,buff,iunrecv,0) if(irecv==0) { printf("recv error:%s",strerror(errno)); return -1; } if(irecv<0) {//这条判断是针对非阻塞的情况下,会发生的错误//当阻塞的情况下,recv函数会直接阻塞在调用的地方,不会执行到这里。 if(errno == EINTR ||(errno == EAGAIN)||errno == EWOULDBLOCK) continue; //阻塞和非阻塞都会产生 printf("recv error:%s",strerror(errno)); return -1; } iunrecv -= irecv; buff += irecv; } } 注意:
recv的返回值为0时,表示连接关闭,并不是说没有读到数据,
因为,对于阻塞的套接字,没有读到数据,函数不会返回,会阻塞等待。
对于非阻塞的套接字,没有读到数据,函数会返回-1,错误号时 EAGAIN。
每日分享:
别人拥有的,你不必羡慕,只要努力,你也会拥有。
文章目录 一、Nginx简介1、什么是Nginx2、Nginx和Apache的优缺点 二、Nginx的编译安装三、添加nginx系统服务四、Nginx配置文件1、全局配置2、I/O事件配置3、HTTP配置4、日志格式设定5、访问状态统计配置6、基于授权密码的访问控制7、基于基于域名的nginx 虚拟主机8、 基于端口的nginx虚拟主机9、 基于端口的Nginx虚拟主机 一、Nginx简介 1、什么是Nginx Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点开发的。因它的稳定性、丰富的功能集、简单的配置文件和低系统资源的消耗而闻名。
Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好。
2、Nginx和Apache的优缺点 nginx相对于apache的优点∶
轻量级,同样起web服务,比apache占用更少的内存及资源
抗并发,nginx处理请求是异步非阻塞的,而apache是阻塞型的在高并发下,nginx能保持低资源低消耗高性能
高度模块化的设计,编写模块相对简
apache相对于nginx的优点∶
Rewrite比nginx的rewrite强大 (rewrite的主要功能就是实现统一资源定位符URL的跳转)
模块多,基本想到的都可以找到
少bug,nginx的bug相对较多
稳定性强
总的来说,需要性能的web服务,用nginx。若不需要性能只求稳定,就选用apache。
二、Nginx的编译安装 ##关闭防火墙 systemctl stop firewalld systemctl disable firewalld setenforce 0 ##安装依赖关系包 yum -y install pcre-devel zlib-devel gcc gcc-c++ make useradd -M -s /sbin/nologin nginx ##解压安装包 tar zxvf nginx-1.12.0.tar.gz ##编译安装nginx cd nginx-1.12.0/ ./configure \ > --prefix=/usr/local/nginx \ > --user=nginx \ > --group=nginx \ > --with-http_stub_status_module make && make install ##做软连接,让系统识别nginx的操作命令 ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin/ ##检查配置文件是否正确 nginx -t nginx netstat -natp | grep :80 ##停止nginx服务 cat /usr/local/nginx/logs/nginx.
错误:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc5 in position 13: invalid continuation byte
编码错误,主要是有中的编码
例如:
b'\r\nWindows IP \xc5\xe4\xd6\xc3\r\n\r\n\r\n\xd2\xd4\xcc\xab\xcd\xf8\xca\xca\xc5\xe4\xc6\xf7 \xd2\xd4\xcc\xab\xcd\xf8:\r\n\r\n \xc3\xbd\xcc\xe5\xd7\xb4\xcc\xac . . . . . . . . . . . . : \xc3\xbd\xcc\xe5\xd2\xd1\xb6\xcf\xbf\xaa\xc1\xac\xbd\xd3\r\n \xc1\xac\xbd\xd3\xcc\xd8\xb6\xa8\xb5\xc4 DNS \xba\xf3\xd7\xba . . . . . . . : \r\n\r\n\xd2\xd4\xcc\xab\xcd\xf8\xca\xca\xc5\xe4\xc6\xf7 \xd2\xd4\xcc\xab\xcd\xf8 2:\r\n\r\n \xc1\xac\xbd\xd3\xcc\xd8\xb6\xa8\xb5\xc4 DNS \xba\xf3\xd7\xba . . . . . . . : \r\n \xb1\xbe\xb5\xd8\xc1\xb4\xbd\xd3 IPv6 \xb5\xd8\xd6\xb7. . . . . . . .
首先澄清MCG和SCG两个概念。MCG和SCG的全称如下:
MCG:Master Cell group,主小区组
SCG:Secondary Cell group,辅小区组
MCG和SCG是双链接(DC,Dual connectivity)下的概念,可以简单理解为UE首先发起随机接入(RACH)的Cell所在的Group就是MCG。如果没有进行双链接,也就没有MCG和SCG的概念。或者也可以理解为,如果没有进行双链接,那么该小区组就对应MCG。
假设现在进行了双链接,那么我们就有了MCG和SCG的概念。现在澄清PCell,SCell,PSCell这三个概念。
PCell:Primary Cell,主小区
SCell:Secondary Cell,辅小区
PSCell:Primary Secondary Cell,主辅小区
在MCG下,可能会有很多个Cell,其中有一个用于发起初始接入的小区,这个小区称为PCell。顾名思义,PCell是MCG里面最“主要”的小区。MCG下的PCell和MCG下的SCell通过载波聚合(CA,Carrier aggregation)技术联合在一起。
同样地,在SCG下也会有一个最主要的小区,也就是PSCell,也可以简单理解为在SCG下发起初始接入的小区。SCG下的PSCell和SCG下的SCell也是通过CA技术联合在一起。
因为很多信令只在PCell和PSCell上发送,为了描述方便,协议中也定义了一个概念sPCell(special Cell):
sPCell = PCell + PSCell
目录
1.什么是缓存
2.mybatis的缓存
2.1一级缓存
2.2 二级缓存
2.2.1 开启二级缓存
2.2.2 在映射文件中使用二级缓存
2.2.3 实体一定要实现序列化接口
2.2.4 二级缓存测试
1.什么是缓存 缓存就是数据交换的缓冲区,当某一硬件要读取数据时,会首先从缓存中查找需要的数据,如果找到了则直接执行,找不到的话则从内存中找。由于缓存的运行速度比内存快得多,故缓存的作用就是帮助硬件更快地运行。
例如 mysql数据库中的数据存在表内也就是在磁盘上。 查询时程序IO读取磁盘的数据,添加时io向磁盘添加数据。
经常查询并且不经常改变的,数据的正确与否对最终结果影响不大的; 这些数据适合放在缓存中。经常改变的数据;数据的正确与否对最终结果影响很大的;---数据安全性要求不高。例如:商品的库存,银行的汇率,股市的牌价; 这些数据不适合放在缓存区。
2.mybatis的缓存 MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。
mybatis支持两种缓存:
(1)一级缓存----基于SqlSession级别的缓存,底层就是一个hashmap。默认一级缓存是开启的,不能关闭。同一个sqlsession中执行相同的sql查询(相同的sql和参数),第一次会去查询数据库并写到缓存中,第二次从一级缓存中取。当执行SQL时候两次查询中间发生了增删改的操作,则SQLSession的缓存会被清空,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
(2)二级缓存--基于SqlSessionFactory级别的缓存,它可以做到多个SqlSession共享数据。默认它是关闭。需要手动开启。 要启用全局的二级缓存,需要在你的 SQL 映射文件中添加一行语句。
2.1一级缓存 一级缓存基于sqlSession完成的一级缓存,第一次查询编号=2的用户信息--缓存不能命中,则向数据库查询发送sql语句、把查询的结果放入缓存中。当sqlSession不关闭时,不需要再在数据库调数据,而是在缓存中直接调取。下面是测试类及控制台显示只调取一次sql语句。
@Test public void testSession(){ User user = userMapper.getUser(2); User user1 = userMapper.getUser(2); } 2022-06-06 19:07:21,399 [main] DEBUG [com.qy151wd.mapper.UserMapper.getUser] - ==> Preparing: select * from tb_user where id=?
2022-06-06 19:07:21,448 [main] DEBUG [com.qy151wd.mapper.UserMapper.getUser] - ==> Parameters: 2(Integer)
写在开篇 关于prometheus的高可用方案,经过笔者不断的研究、对比、和搜索,发现不管是官方、还是各大搜索引擎搜索出来的方案,都不符合笔者的需求。因此,笔者自己设计了一套prometheus主备的方案。该方案是一个很low的方案,但经过不断的实践、验证,最后发现还挺实用。关于本方案,笔者以后还会找机会用go或者python开发一个带UI界面的prometheus主备管理器,让它的功能更加完善,做到更自动化和智能化。Prometheus是监控领域的新启之秀,潜力非常大,K8S内置对它直接支持,直接有提供exporter,而K8S又是未来基础架构的主力军。而监控方面,prometheus成为未来的主力军是胜券在握,把它玩透了你绝对不吃亏。好了,前戏有点多了。敬请大家的关注、点赞、转发。下面的正式进入主题!!!
DIY的prometheus主备方案架构图 方案说明
两台主机(master和slave)分别部署keepalived,让master主机接管VIP,注意:keepalived建议配置成非抢占模式之所以采用VIP的原因如下: 为了方便日常访问Prometheus页面和Alertmanager页面,在主备切换时,可无需更换访问ip。上层可视化应用(如grafana)通过VIP来对接Prometheus的数据源,当主备切换时,无需在grafana上修改对应的数据源。 日常由master主机处于工作状态,在master中,启动Promethues和Alertmanager组件,启动webhook脚本(告警消息推送脚本,用于将告警推送到其他平台)。slave主机备用状态,在slave中,需要启动Promethues组件(用于拉取指标数据),启动Alertmanager组件(用于接收警报消息),这里注意,webhook脚本需处于停止状态(不进行告警推送到其他平台)。这样做是为了规避推送重复告警的问题,虽然Alertmanager有自身的去重告警功能,但这样的设计根本就没有告警重复,已经将重复扼杀在摇篮里了。在接入监控对象时(部署对应的exporter),切记,仅需要在master上做配置即可, slave定期从master拉取配置文件(包括主配置文件、警报规则文件等),定期和master保持配置同步。master和slave的配置保持同步,意味着两边都会拉取被监控对象的监控指标数据。监控指标的拉取、警报的触发两台均一起工作,但告警的推送只有master在负责,slave不负责告警的推送,如果master不可用了,就需要将slave上的webhook脚本手动拉起来,由slave上的webhook脚本接管告警推送的任务。配置文件同步的做法是采用最原始、最简单、最粗暴的办法,master和slave的配置文件同步方案如下: Master主机:
master提供配置文件下载服务,由python自带的SimpleHTTPServer模块实现,且需要在prometheus或alertmanager规范安装路径下(如/usr/local/prometheus)进行SimpleHTTPServer模块的启动,拉起后,默认的监听端口是8000。master检测配置文件变化情况,如达到条件则触发备份和打包新的配置目录。在master上,设计了一个保存通知动作的文件notice_slave.action,配置发生变化写入1,配置没有发生变化写入0。同时,该检测脚本作为常驻进程在后台运行。 Slave主机:
slave从master下载通知动作的文件notice_slave.action,根据状态码(1和0)来决定接下来的动作,如果是1,则:从master下载配置压缩包、备份原有配置目录、解压新下载后的配置压缩包、热重启相关组件(prometheus、alertmanger),如果是0则什么都不做。 对于配置文件的同步,也是有两种实现方式的,要么是推,要么是拉,笔者的这个方案里是后者,笔者目前之所以折腾零散的shell脚本来去做高可用的管理,是为了能快速解决需求,因此才做了这个简陋的方案,笔者的原则是:困难的事情简单做,简单的事情咱不做(开玩笑哈!!!)。 当然,笔者以后会通过Go或者Python打造一个管理Promtheus主备的工具,且是带UI的管理工具,敬请期待推出!我不造车,我只造零件。
一、规划和规范 1. 设备规划(本示例为测试环境) 角色物理IPVIP安装组件告警推送方式master192.168.11.146192.168.11.203(当前接管)prometheus、alertmanager(均拉起)webhook方式,脚本拉起slave192.168.11.147prometheus、alertmanager(均拉起)webhook方式,脚本不拉起(备用) 2. 统一安装路径规范 master和slave主机的标准安装路径均为:/usr/local/,笔者安装组件后的环境如下:
/usr/local/keepalived (注意:建议keepalived配置成非抢占模式) /usr/local/prometheus /usr/local/alertmanager 至于安装路径的规范,请自行根据实际情况敲定。
3. prometheus组件配置文件和目录规范 所有配置文件统一标准路径:/usr/local/prometheus/conf/prometheus主配置文件:/usr/local/prometheus/conf/prometheus.yml按业务粒度,一个业务对应一个目录,业务下不同的监控对象都放在对应的业务目录下:/usr/local/prometheus/conf/business 特别说明1:请自行在prometheus组件的安装目录下创建conf目录,并将默认的prometheus.yml配置文件移动进去
特别说明2:请自行在prometheus组件的配置文件统一标准路径(./conf)下创建业务目录business
特别说明3:业务目录下,又包含两个目录:job和rule,job用于存放监控拉取配置文件,rule用于存放警报规则配置文件
配置文件目录和业务目录规划示范,如下:
/usr/local/prometheus/ # 这是规范的安装路径 /usr/local/prometheus/conf/ # 这是规范的配置目录 /usr/local/prometheus/conf/prometheus.yml # 这是主配置文件 /usr/local/prometheus/conf/business 这是按业务粒度规划的业务根目录 # 如下是业务A的规划案例: /usr/local/prometheus/conf/business/a_business/ 这是业务a的目录 /usr/local/prometheus/conf/business/a_business/job/oracle.yml 这是业务a下拉取oracle监控配置数据的yml配置文件 /usr/local/prometheus/conf/business/a_business/rule/oracle.rules 这是业务a下oracle的警报规则rules配置文件 特别说明:上述对业务A的配置文件规划案例非常重要,请务必参照此规范。
4. alertmanager组件配置文件和目录规范 关于Alertmanager组件的配置文件,相对来说没prometheus那么复杂,主要的规划还是在prometeus中
alertmanager的主配置文件统一标准路径放在prometeheus的conf中:/usr/local/prometheus/conf/alertmanager.yml 5. 备份路径规范 在master主机上,会自动备份原有的conf配置文件目录
Prometheus组件 统一备份路径为:/usr/local/prometheus/backup/
Alertmanager组件 不涉及到备份
6. 日志目录规范 在master主机和slave主机上运行的脚本日志均统一存放在指定目录
Prometheus组件 统一日志目录:/usr/local/prometheus/logs/
问题: available List里面没东西
官方方法: 点击上图窗口左下角的问号以查看解决方案
数据库角色成员身份:
db_accessadmin 固定数据库角色的成员可以为 Windows 登录名、Windows 组和 SQL Server 登录名添加或删除数据库访问权限。
db_backupoperator 固定数据库角色的成员可以备份该数据库。
db_datareader 固定数据库角色的成员可以从所有用户表中读取所有数据。
db_denydatawriter 固定数据库角色的成员不能添加、修改或删除数据库内用户表中的任何数据。
db_ddladmin 固定数据库角色的成员可以在数据库中运行任何数据定义语言 (DDL) 命令。
db_denydatareader 固定服务器角色的成员不能读取数据库内用户表中的任何数据。
db_denydatawriter 固定服务器角色的成员不能添加、修改或删除数据库内用户表中的任何数据。
db_owner 固定数据库角色的成员可以执行数据库的所有配置和维护活动,还可以删除数据库。
db_securityadmin 固定数据库角色的成员可以修改角色成员身份和管理权限。向此角色中添加主体可能会导致意外的权限升级。
public 每个数据库用户都属于 public 数据库角色。如果未向某个用户授予或拒绝对安全对象的特定权限时,该用户将继承授予该对象的 public 角色的权限。
视频链接:https://www.bilibili.com/video/BV14Z4y1u7pi?p=1
1. TypeScript 介绍 1.1 TypeScript 是什么 1.2 TypeScript 为什么要为 JS 添加类型支持? 1.3 TypeScript 相比 JS 的优势 2. TypeScript 初体验 2.1 安装编译 TS 的工具包 2.2 编译并运行 TS 代码 2.3 简化运行 TS 的步骤 注意:若ts-node hello.ts执行报错,需要先执行命令tsc --init创建一个 tsconfig.json 文件,该文件是 TypeScript 项目的配置文件tsconfig.json 包含 TypeScript 编译的相关配置,通过更改编译配置项,我们可以让 TypeScript 编译出 ES6、ES5、node 的代码。 3. TypeScript 常用类型 3.1 类型注解 3.2 常用基础类型概述 3.3 原始类型 3.4 数组类型 3.5 类型别名 3.6 函数类型 如果函数没有返回值,那么,函数返回值类型为:void。 3.7 对象类型 3.8 接口 3.9 元组 3.10 类型推论 3.
随着时间的流逝,用户和计算机可能变为不活跃,需要定期进行清理。ADManager Plus帮助您快速筛选出Active Directory中的所有不活动、已禁用、帐户已过期用户和计算机。根据您公司的Active Directory整理工作政策,您可通过删除来定期清理僵尸用户,或通过禁用、启用或移动帐户以有效地清理您的Active Directory。
这样可增强Active Directory的安全性和提高其性能,无需使用命令行工具和脚本,您也可节省大量时间。
Active Directory
功能
找到 X 天内未登录的用户或计算机帐户 找到已过期和未使用的Active Directory帐户 禁用、移动、删除用户或计算机帐户,并在短时间内禁用、删除、移动或启用Active Directory帐户。 显示已禁用的帐户、最后登录/注销时间、操作系统类型等。 将报表导出为CSV、XLS、HTML、PDF和CSVDE 找到您网络中的过时帐户
使用ADManager Plus的以下报表有助于检测和删除Active Directory中的休眠帐户:
生成已禁用帐户列表 生成不活动帐户列表 生成帐户已过期的用户列表 管理休眠或过时帐户 被禁用的用户
使用ADManager Plus,您可轻松地生成因为某些原因而被禁用的用户/计算机帐户的列表。userAccountControl属性用于确定域中被禁用的用户。您可通过删除帐户或将它们移至另一个OU,从而轻松管理这些帐户。您也可以同时删除/启用/移动两个或更多被禁用的帐户。参见如何移动用户帐户。
ADManager Plus
帐户过期的用户
长时间不活动的AD域用户账户可能已经过期,而用户或管理员不知道它们的情况。编写脚本来找到已过期的帐户非常繁琐,而ADManager Plus报表生成器会扫描Active Directory并为您提供所有已过期帐户的列表。您可在结果页面删除用户、禁用用户或将已过期用户移至权限最低的OU,从而积极保护网络。您也可以将已锁定用户的结果数据打印和输出为XLS、CSV、PDF、HTML等格式。
非活动\休眠用户
使用ADManager Plus,您可检索过去30、60或更多天内未登录到域的不活动用户帐户。参见找不到活动用户
AD域管理
移动、禁用或删除用户或计算机休眠或过时帐户
可靠的Active Directory基础设施应始终确保启用现存帐户并禁用/删除过时帐户,以便实现最优工作效率和安全性。Active Directory用户帐户状态非常不确定,因为它取决于众多密码策略和其他限制;所以在小组织中,管理员可手动检查帐户状态并最终修改它们,但对于中等和大型组织,优先考虑使用可检测用户和计算机帐户状态并在随后删除、禁用、移动它们的工具。
ADManager Plus利用其内置的删除、禁用、移动功能帮助管理员将Active Directory帐户的状态保持最新。通过删除帐户来清理Active Directory,或通过从任一个用户或计算机报表中选择单个或多个帐户,即可使用禁用或移动功能来管理它们。参见如何移动用户帐户
C++进程间通信之SendMessage和PostMessage
1,使用介绍
2,需要注意的地方
3,WM_COPYDATA的原理
SendMessage和PostMessage在Win32编程中是很常见的,主要是用来发送消息到指定的窗口,一般用于工作线程传输数据到UI线程。其中SendMessage函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回。而函数PostMessage不同,将一个消息寄送到一个线程的消息队列后立即返回。
同样的,对于多个Win32进程,只要它有窗口,我们也可以通过SendMessage和PostMessage来实现两个进程间的数据通信。进程内传输时,由于在同一个进程中,所有数据都是存在于相同的虚拟内存空间中,可以通过传输数据地址直接达到数据传输的目的。而不同两个进程,它们是两个独立的虚拟内存空间,同一地址对不同的进程来说并不一定指向同一物理内存,内容也就不一定一样,因此不同进程无法通过传地址的方式传递字符串。下面分别介绍SendMessage和PostMessage在跨进程传输数据时的使用。
1,使用介绍
(一) PostMessage
PostMessage发送时只需要把消息丢到窗口所属线程的消息队列中就会立即返回,不会阻塞发送端线程,但是在多线程中由于使用不同的虚拟地址空间,不能进行寻址操作,因此不能直接发送数据。换一种思路,我们可以为自己的业务定义不同的多种消息,不同消息代表不同的含义:
#define WM_WORK1_START WM_USER+1000
#define WM_WORK2_STOP WM_USER+1001
#define WM_WORK2_START WM_USER+1002
#define WM_WORK2_ STOP WM_USER+1003
发送消息通知后直接返回,由服务端接收不同的消息id进行业务处理,这种方式处
理起来比较简陋,但是也可以实现基本命令传输的目的。这里可能会有人提到WM_COPYDATA消息,它可以很好地传输我们需要交互的数据,但是由于系统必须管理用以传递数据的缓冲区的生命期,如果使用了PostMessage(),数据缓冲区会在接收方(线程)有机会处理该数据之前,就被系统清除和回收。
(二) SendMessage
SendMessage是一种阻塞的消息模式,它会等待消息处理结果返回才执行完毕。那
么这里我们就可以通过WM_COPYDATA来进行字符串数据的传输。WM_COPYDATA主要用到一个结构体COPYDATASTRUCT,定义如下:
typedef struct tagCOPYDATASTRUCT {
ULONG_PTR dwData;
DWORD cbData;
_Field_size_bytes_(cbData) PVOID lpData;
} COPYDATASTRUCT, *PCOPYDATASTRUCT;
其中dwData为32位的自定义数据, lpData为指向数据的指针,cbData为lpData指针指向数据的大小(字节数)。
我们需要定义一个结构体来进行数据的传输,比如:
struct tagMESSAGE
{
char szMsg[256];
};
又看到了熟悉的字符串操作,填充需要传输的字符串数据,lpData也就是该结构体的指针,大概代码如下:
tagMESSAGE msg;
memset(&msg, 0, sizeof(tagMESSAGE));
strncpy(msg.szMsg, (*it).c_str(), sizeof(msg.szMsg) - 1);
COPYDATASTRUCT cpd;
cpd.cbData = sizeof(tagMESSAGE) + 1;
STM32 CAN知识总结 一、CAN物理特性 can总线显性为0,隐形为1,类似线与的特点
二、CAN帧有五种:数据帧、远程帧、错误帧、过载帧、 帧间隔。其中数据帧最为常见 CAN数据帧结构上由7个段组成
CAN总线ACK应答机制:确认数据是否正常接收,所谓正常接收是指不含填充错误、格式错误、 CRC 错误。发送节点将此位为1,接收节点正常接收数据后将此位置为0;(1 bit)
三、帧仲裁 当多个单元同时开始发送时,各发送单元从仲裁段的第一位开始进行仲裁。连续输出显性电平最多的单元可继续发送
四 、CAN过滤器 过滤器一共有4种工作模式:32位宽的掩码模式,32位宽的列表模式, 16位宽的列表模式,16位宽的掩码模式
以下代码为CAN过滤器设置代码例子:该例子只会接收ID为Can_Address的数据帧
CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0 CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; //掩码模式 CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位宽 CAN_FilterInitStructure.CAN_FilterIdHigh=Can_Address<<5; //验证码(ID)左移5为的原因是CAN_FilterIdHigh包含的是STD[0~10]和EXID[13~17],标准CAN ID首先应左移5位后才能对齐.EXID[13~17]是5位 CAN_FilterInitStructure.CAN_FilterIdLow=0x0000; CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xffff;//都不屏蔽 CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xffff; CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0 CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;//激活过滤器0 CAN_FilterInit(&CAN_FilterInitStructure); //滤波器初始化 五 、CAN波特率 STM32单片机中CAN的波特率主要由4个参数共同决定。他们分别是重新同步跳跃时间单元(tsjw)、时间段1的时间单元(tbs1)、时间段2的时间单元(tbs2)、波特率分频器(brp)。对应到STM32单片机的库函数中,分别对应的是CAN_SJW、CAN_BS1(即tbs1+1)、CAN_BS2(即tbs2+1)、CAN_Prescaler等4个参数。库函数中只需完成这4个参数的设定即可。比如设置CAN_SJW=1tq,CAN_BS1=6tq,CAN_BS2=1tq,CANPrescaler=9,则波特率=36M/[(1+6+1)*9]=500Kbps。(APB1总线时钟(PCLK1)=36M)
Vue2的生命周期 vue2生命周期:vue实例从创建到销毁的过程;主要是在不同的时段执行不同的事情;通俗来讲就是 出生到死亡的过程
常见的8个生命周期钩子函数 beforeCreate created创建前后 beforeCreate 里获取不到data数据和dom元素
created 里可以获取data数据但是获取不到dom元素
一般在created 里进行数据请求和获取本地的数据
如果说想在created内获取dom元素,我们可以使用nextTick
beforeMount mounted挂载前后、 beforeMount 里可以获取data数据但是获取不到dom元素(因为这时候vue实例并未挂载)
mounted 里可以获取data数据和dom元素
一般在mounted里进行获取dom元素,获取不到的话使用nextTick方法
beforeUpdate updated更新前后、 beforeUpdate 视图更新前触发
updated 更新后触发 ,是数据变化推动视图更新后才会触发(v2会出现数据更新视图不更新的情况可以使用this.$set()来解决)
beforeDestroy destroyed销毁前后 beforeDestroy 实例销毁前触发
destroyed 实例销毁后触发 销毁页面定时器、页面监听。
另外三个不常用:
activated: 组件激活时
deactivated: 组件未激活时
errorCaptured: 当捕获一个来自子孙组件的错误时被调用
注意点: 生命周期在创建之后才能够获取data数据;在挂载之后才能够获取dom元素
执行顺序如图:
信创办公–基于WPS的Word最佳实践系列(应用导航窗格:轻松掌握文章结构) 1.应用背景 一些文档的页数太多,要掌握其脉络结构非常困难,如果是纸质书籍我们可以查看目录,快速清晰地掌握文章的脉络结构,在电子文档中可以利用【导航窗格】实现使文章的结构清晰。
2.如何打开导航窗格 在【视图】选项卡上有【导航窗格】的命令,点击下方的倒三角图标,勾上【靠左】或【靠右】即可打开【导航窗格】,如图1所示。
图1 3.导航窗格的常用功能 3.1 快速定位文档 比如说要快速对某一部分进行修改,只需在【导航窗格】中点击该部分就可快速去到该部分进行修改(下面以第四部分为例)。点击前页面如图2所示,点击后页面如图3所示。
图2 图3 3.2 清晰展现文档的目录层级 点击【导航窗格】目录下面的三角图标可快速折叠目录层级,清晰的看清楚文章的脉络。若需要展开目录层级,还可以点击倒三角符号实现快速展开,如图4所示。
图4 3.3 快速调换文章层级顺序 如果想快速移动文章的内容,可以直接选择该部分的【大标题】,拖动到指定位置即可实现顺序的快速调换(下面以第二部分快速移动到第五部分后面为例),如图5所示。
图5 3.4 快速为该文章插入目录 鼠标右键单击导航窗口里的任意一个标题,选择【插入目录】选项,可实现快速插入目录的功能。插入目录前的操作如图6所示,插入目录后的情况如图7所示。
图6 图7 制作成员: 潘伟圳
排版: 郑伟钦
初审: 王乐平
复审: 二月二
点击下方“正月十六工作室”查看更多学习资源
正月十六工作室
作为一名新媒体工作者,经常会用到gif动图来填充公众号文章、视频内容,可是并不是每一个小伙伴都会GIF图片制作,又不知道哪款gif图片在线制作工具好用,小白对于复杂的软件又很头疼,那么怎么才可以让零基础的我们也可以做出gif动图呢?今天就分享给大家一款在线gif图片制作的工具:利用它强大的gif合成功能,简单几步一键生成gif图片,大家快来试试吧!
点击【GIF合成】选择需要制作gif的图片,修改gif图片高度、宽度,播放速度,图片质量调整,设置完成后开始生成gif。
PS:图片若超过1920px系统会自动等比例压缩,无需担心图片变形。
图片预览界面,然后下载保存即可。
以上就是GIF制作的方法啦,是不是很简单,而且没有水印,在没有电脑的情况下,使用手机浏览器也可以操作,还有GIF裁剪、压缩等更多功能等你来使用。
有时候我们会遇上gif动图出现黑、白边,或者有很多空白的时候,这样的图片会影响我们的使用也不好看,gif图片裁剪有什么好的方法吗?有没有既不影响图片质量又方便的gif裁剪工具呢?今天小编就给大家介绍一个gif在线裁剪的方法,GIF中文网就支持gif裁剪,还支持gif压缩、合成、视频转gif等功能,下面来看一下具体操作步骤吧!
使用浏览器进入GIF中文网,选择GIF裁剪。
上传需要裁剪的图片文件,设置图片尺寸,点击裁剪。
预览图片效果,下载保存。
图片裁剪前: 图片裁剪后: 按照以上的步骤,我们就可以在不影响图片质量的基础对gif图片进行裁剪了,如果裁剪后还觉得图片体积过大,还可以使用GIF中文网的gif压缩功能,想要试试的小伙伴快来了解一下吧!
摘要:运行npm install 命令的时候带上ignore-scripts, 可以避免一个恶意包里的病毒。 本文分享自华为云社区《运行npm install 命令的时候带上--ignore-scripts有什么好处吗?》,作者:gentle_zhou。
在npm依赖库里,当前有超过130多万的依赖包可以被下载使用(数据来源:https://en.wikipedia.org/wiki/Npm_(software) )。但其中会不会有一些是恶意依赖包呢,这真的说不定。
因此在Predicting the Future of the Web Development (2020 and 2025)这场演讲中,推荐我们设置:npm config set ignore-scripts true:
或则就如我们标题里说的,在安装依赖包时,确保添加–ignore-scripts后缀以禁止npm里第三方依赖包的预先安装脚本或则安装后脚本被执行;这样就可以避免一个恶意包里的病毒。
但是问题来了,有些依赖包就是需要这些预先安装脚本或则安装后脚本来配置环境;如果如果我们在下载的时候,命令里用了–ignore-scripts后缀,那么是可以减轻恶意代码的危害,但同时也会导致下载的依赖包没有正常发挥作用。
那么我们如何知道什么时候可以使用–ignore-scripts后缀享受它的好处呢?就是说我们怎么样可以预先了解哪些依赖包需要脚本文件,我们不能使用–ignore-scripts后缀呢?
我们可以预先先去下载can-i-ignore-scripts 这个依赖包:
A service and cli to analyze your dependencies and check what’ll break when you switch from npm ci to npm ci --ignore-scripts can-i-ignore-scripts工具,可以帮助我们分析各个依赖包是否可以使用--ignore-scripts命令。该工具可以帮助我们确定哪些依赖包可以使用--ignore-scripts命令;实际上呢,一些我们已经运行了几个月的脚本是没啥问题的,而该工具可以帮助我们确定新加入的依赖包是否可以加入到没问题列表中。
如何下载这个工具呢?很简单,可以直接在工具官网下载或则通过npx命令行npx can-i-ignore-scripts (npx是什么?后面计划会出一篇文章介绍一下;现在可以就理解成是npm的一个包执行器,能让npm包中的命令行工具和其他可执行文件在使用上变得更加简单)。
如何使用这个工具呢?我们去安装了node_modules包的目录下运行can-i-ignore-scripts命令去查看(下面是官方给出的例子):
naugtur@localtoast:~/repo/ [main]$ can-i-ignore-scripts █▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█ ▄▄· ▄▄▄· ▐ ▄ ▄ ▪ ▄▄ ▐ ▄ ▄▄▄ ▄▄▄ ·▄▄▄▄• ▐█ ▌▪▐█ ▀█ •█▌▐█ ██ ██ ▐█ ▀ █▌▐█ ▐▄ █· █ ▀· .
记一次升级node版本后,运行原vue项目报错问题解决方法
因种种原因把node版本升级了,运行项目后发现报错,一顿搜索后得出以下结果,并成功解决了 “Node Sass could not find a binding for your current environment: Windows 64-bit with Node.js 10.x”
同时,命令行提示: This usually happens because your environment has changed since running `npm install`. Run `npm rebuild node-sass` to download the binding for your current environment. 看这个说明,大概意思就是说,因为我在执行了 npm install 指令安装好了依赖之后,环境又发生了改变(node版本变更),所以不能将当前的node环境与项目中的sass依赖建立绑定关系,需要执行“npm rebuild node-sass”来重新下载依赖。
所以,按他说的,执行命令npm rebuild node-sass
一通下载之后,运行项目,依然报错,于是开始百度,按照其他网友的指示,再执行一次npm update 来更新项目里的依赖包,然后,大功告成。
一、测试说明 JDBC (Java Database Connectivity) 是 Java 应用程序与数据库的接口规范,旨在让各数据库开发商为 Java 程序员提供标准的数据库应用程序编程接口 (API)。JDBC 定义了一个跨数据库、跨平台的通用 SQL 数据库 API。
DM JDBC 数据库驱动程序是一个能够支持基本 SQL 功能的通用应用程序编程接口,支持一般的 SQL 数据库访问。通过 JDBC 驱动程序,用户可以在应用程序中实现对 DM 数据库的连接与访问
实验目标:部署DM8数据库,编写简单脚本测试JDBC驱动,完成数据库连接,简单SQL查询,并发连接等测试。
环境规划:
IP地址:192.168.50.100
数据库版本: DM8
软件路径规划
Linux系统目录
说明
1
/dm8
DM8安装路径
2
/home/dmdba/scrdir
脚本路径
二、软件安装 1、DM8图形化界面安装
略
2、安装JDK
yum install –y java-1.8.0-openjdk.x86_64
三、驱动测试 1、简单连接测试
编写测试脚本:vim jdbc_conn.java
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class jdbc_conn { static Connection con = null; static String cname = "
C++定义常量的两种方式: #define 宏常量 值(不可以修改)限定符:const 数据类型 常量名 = 常量值(表示不可修改)const比#define好:1.它能够明确指定类型。2.可以使用c++的作用域规则将定义限制在特定的函数或文件中。3.const可用于更复杂的类型。4.在c++中可以声明数组的长度。 常识 c++编程风格:main()放在最前面,使用自定义函数时先声明,即函数原型。标识符的第一个字符只能是字母或下划线namespace是指标识符的各种可见范围,作用:定义标示符using namespace std,写c++代码时一般都要加上。上面using编译指令使得std名称空间中的所有名称都可用,在大型项目中是个问题,更好的办法是只使所需的名称即可,这样可以通过using声明来实现:using std ::cout; using std :: cin;。c++中默认最多显示6位有效数字3e2 = 3*10^23e-2 = 3*0.1^2x.xxxE+n:小数点向右移动n位:x.xxxE-n:小数点向左移动n位。做除法时:有一个数为浮点值时,结果为浮点值,否则为整数。除法有3种运算符:int 除法,float除法,double除法。使用相同的符号进行多种操作叫:运算符重载。字符型变量将对应的ASCII码放到存储单元水平制表符:\t:表前面的内容占8个字符,可以整齐的输出字符字符串:1.类似c语言,2.string a = “…”; (#include < string >)三目运算符:表达式1?表达式2:表达式3;水仙花数 = 每位数字^3的和system(“pause”);暂停黑窗口c++中可以直接使用 “+” 进行字符串的拼接清屏操作:system(“pause”)按任意键继续…; system(“cls”);清屏c中字符串比较用strcmp(); 相同返回0,错误比较:temp = “xxxx”; 两者比较的是地址,而不是字符串。使用string类型的字符串可以直接比较。c风格的字符串:char *类型,当参数传递时,实际上传递的是字符串的第一个字符的地址处理字符串错误的标准方式:当str == '\0’时,*str = 0; while (*str) { .......; str++; } 重定向运算符:<输出时(cout<<):<<运算符将字符串插入到输出流中输入时(cin>>):>>运算符从输入流中抽取字样 >>和<<:表示信息流动的方向。 auto可以在声明变量的时候根据变量初始值的类型自动为此变量选择匹配的类型,类似的关键字还有decltype。关键字typedef创建数据类型的别名
cin/cout 输出:cout<<…<<endl;,cout<<“…\n”;类似于字符串的拼接(要拼接的字符串之间使用空格或‘+’)。成员函数:cout.put(); 通过类对象来使用函数put()。
输入:cin>>变量名; 缺点:不能读取空格。循环读取时读取空格后面的内容。
读取一行字符串:
1.cin.getline(数组名称,大小); 它通过换行符来确定末尾,将换行符替换为‘\0’,并且丢弃换行符。
输入到string对象中:getline(cin,string str);
2.cin.get(数组名称,大小).get(),能够读取多行。如果读取一个字符:cin.get(); 读取字符串:cin.get(数组名称,大小),它不抛弃换行符。
3.如果多次使用cin.get(name,size);进行输入时,要使用cin.get();进行处理换行符(为下一行输入做准备),如果不这样做,则下一行无法输入。
可以使用cin的返回值判断输入类型是否正确。如果输入错误,则删除错误输入:cin.clear();
cin用于输出字符串时,遇到空白(空格、制表符、换行符)时结束。如果空白后面还有内容,并且往下面还有cin时,则留给下一次输入,没有则本次输入cin结束。
cin.ignore(n); 忽略输入行的前n个字符
作者 | 阮一峰
1、概述 Cookie 是服务器保存在浏览器的一小段文本信息,一般大小不能超过4KB。浏览器每次向服务器发出请求,就会自动附上这段信息。
Cookie 主要保存状态信息,以下是一些主要用途。
对话(session)管理:保存登录、购物车等需要记录的信息。
个性化信息:保存用户的偏好,比如网页的字体大小、背景色等等。
追踪用户:记录和分析用户行为。
Cookie 不是一种理想的客户端储存机制。它的容量很小(4KB),缺乏数据操作接口,而且会影响性能。客户端储存应该使用 Web storage API 和 IndexedDB。只有那些每次请求都需要让服务器知道的信息,才应该放在 Cookie 里面。
每个 Cookie 都有以下几方面的元数据。
Cookie 的名字
Cookie 的值(真正的数据写在这里面)
到期时间(超过这个时间会失效)
所属域名(默认为当前域名)
生效的路径(默认为当前网址)
举例来说,用户访问网址www.example.com,服务器在浏览器写入一个 Cookie。这个 Cookie 的所属域名为www.example.com,生效路径为根路径/。如果 Cookie 的生效路径设为/forums,那么这个 Cookie 只有在访问www.example.com/forums及其子路径时才有效。以后,浏览器访问某个路径之前,就会找出对该域名和路径有效,并且还没有到期的 Cookie,一起发送给服务器。
用户可以设置浏览器不接受 Cookie,也可以设置不向服务器发送 Cookie。window.navigator.cookieEnabled属性返回一个布尔值,表示浏览器是否打开 Cookie 功能。
window.navigator.cookieEnabled // true document.cookie属性返回当前网页的 Cookie。
document.cookie // "id=foo;key=bar"
不同浏览器对 Cookie 数量和大小的限制,是不一样的。一般来说,单个域名设置的 Cookie 不应超过30个,每个 Cookie 的大小不能超过4KB。超过限制以后,Cookie 将被忽略,不会被设置。
浏览器的同源政策规定,两个网址只要域名相同和端口相同,就可以共享 Cookie(参见《同源政策》一章)。注意,这里不要求协议相同。也就是说,http://example.com设置的 Cookie,可以被https://example.com读取。
2、Cookie 与 HTTP 协议 Cookie 由 HTTP 协议生成,也主要是供 HTTP 协议使用。
资料 GitHub: https://github.com/microsoft/reverse-proxy
YARP 文档:https://microsoft.github.io/reverse-proxy/articles/getting-started.html
主动和被动健康检查 : https://microsoft.github.io/reverse-proxy/articles/dests-health-checks.html#active-health-check
gRpc:https://microsoft.github.io/reverse-proxy/articles/grpc.html
实战项目概览 Yarp Gateway 示意图
共享类库 创建一个 .Net6.0 的类库,项目名称:Artisan.Shared.Hosting.AspNetCore, 其它项目公用方法放在这个项目。
Serilog 日志 需要的包:
<PackageReference Include="Serilog.AspNetCore" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> 代码清单:Artisan.Shared.Hosting.AspNetCore/SerilogConfigurationHelper.cs
using Serilog; using Serilog.Events; namespace Artisan.Shared.Hosting.AspNetCore; public static class SerilogConfigurationHelper{ public static void Configure(string applicationName) { Log.Logger = new LoggerConfiguration()#if DEBUG .MinimumLevel.Debug()#else .MinimumLevel.Information()#endif .MinimumLevel.Override("Microsoft", LogEventLevel.Information) .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning) .Enrich.FromLogContext() .Enrich.WithProperty("Application", $"{applicationName}") .WriteTo.Async(c => c.
一、保存一次查询结果至redis String key=keyword+"_"+books+"_contents"; List<String> contents_json=new ArrayList<>(); for(ContentInfo c:contents){ contents_json.add(ObjectMapperUtil.toJSON(c)); } RedisUtil.rpush(key,contents_json); String key1=keyword+"_"+books+"_pageSum"; RedisUtil.set(key1, String.valueOf(x)); 将结果以list格式保存至redis
List<String> contents_json=new ArrayList<>(); for(ContentInfo c:contents){ contents_json.add(ObjectMapperUtil.toJSON(c)); } RedisUtil.rpush(key,contents_json); 二、redis分页查询 先在redis数据库查询
if(RedisUtil.exists(key)){ List<String> contends_json=RedisUtil.hZget(key,(page-1)*pagenum,page*pagenum); List<ContentInfo> contents= JSONArray.parseArray(contends_json.toString(),ContentInfo.class); return new R(true,Integer.parseInt(RedisUtil.get(key1)),contents); } 若查询不到则在数据库查询并添加数据至redis,即调用上述方法
else{ return getCont2(keyword,page,books,request); }
项目场景: java实现简单的银行存款取款系统
本次代码适合初学者小白,连数据库都没有运用。一次性程序哈哈。
备学内容: 你得先了解java中以下基本内容。
1、 数组
2、 方法
3、 类
4、 Scanner扫描器
学习产果: :
在写这段代码的过程中,我学到了以下几个知识点:
1、 类和方法的灵活应用。
2、类既然可以数组来使用!!!
3、 数据的相互传递:
系统描述: 当我学完java中的基本知识点之后想实现一个银行存取款系统,就简单实现:
登录,注册,退出,存款,取款转账,查询个人信息等功能。
首先写一个main方法
import java.util.Scanner; //扫描器 public class bank{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); } } main方法创建好之后再 创建一个geren1类,就是保存用户各类信息。
class geren1{ private String zhanghao; private String mima; private int zijin=0; private String name; private int xuhao; private String phone; //构造方法 public geren1(String zhanghao,String mima,String name,String phone,int xuhao){ this.
Java 值拷贝(值传递)与引用拷贝(引用传递)的区别以及数组的Copy 值拷贝 基本数据类型赋值,赋值方式为值拷贝
n2的变化,不会影响到n1点值
引用拷贝 数组在默认情况下是引用传递,赋的值是地址,赋值方式为引用传递,是一个地址
arr2的变化会影响到arr1
详情看代码及运行结果 public class ArrayAssige { // 编写一个main方法 public static void main(String[] args) { // 基本数据类型赋值,赋值方式为值拷贝 // n2的变化,不会影响到n1点值 byte n1 = 10; byte n2 = n1; n2 = 80; System.out.println("n1=" + n1 + "\nn2=" + n2); // 数组在默认情况下是引用传递,赋的值是地址,赋值方式为引用传递,是一个地址 // arr2的变化会影响到arr1 byte[] arr1 = { 1, 2, 3 }; byte[] arr2 = arr1; arr2[0] = 10; System.out.println("===arr1的元素==="); for(byte i=0;i<arr1.length;i++) { System.out.println("arr1[" + i + "
面试题 Category能否添加成员变量?如果可以,如何给Category添加成员变量?
答:不能直接添加成员变量,但是可以通过runtime的方式间接实现添加成员变量的效果。为什么Category 不能添加成员变量?
我们从分类的结构的角度来考虑一下分类中为什么不能添加成员变量: 通过分类的底层结构我们可以看到,分类中可以存放实例方法,类方法,协议,属性,但是没有存放成员变量的地方。所以不能添加.
使用Runtime给系统的类添加属性,首先需要了解对象与属性的关系。对象一开始初始化的时候其属性为nil,给属性赋值其实就是让属性指向一块存储内容的内存,使这个对象的属性跟这块内存产生一种关联。而想要给系统的类添加属性,可以通过分类。
这里给NSObject添加name属性,创建NSObject的分类
我们可以使用@property给分类添加属性
@property(nonatomic,strong)NSString *name; 通过探寻Category的本质我们知道,虽然在分类中可以写@property
添加属性,但是不会自动生成私有属性,也不会生成set,get方法的实现,只会生成set,get的声明,需要我们自己去实现。
RunTime提供了动态添加属性和获得属性的方法。
-(void)setName:(NSString *)name { objc_setAssociatedObject(self, @"name",name, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -(NSString *)name { return objc_getAssociatedObject(self, @"name"); } 动态添加属性
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy); 参数一:id object : 给哪个对象添加属性,这里要给自己添加属性,用self。
参数二:void * == id key : 属性名,根据key获取关联对象的属性的值,在objc_getAssociatedObject中通过次key获得属性的值并返回。推荐直接使用 @"变量名" 或者 @selector(变量的set/get方法) . 参数三:id value : 关联的值,也就是set方法传入的值给属性去保存。
参数四:objc_AssociationPolicy policy : 策略,属性以什么形式保存。
有以下几种, 可以看到并没有weak这样的修饰词, 最后会有weak的实现方式
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) { OBJC_ASSOCIATION_ASSIGN = 0, // 使用assign关联对象 OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, // 指定相关对象的强引用,非原子性 OBJC_ASSOCIATION_COPY_NONATOMIC = 3, // 指定相关的对象被复制,非原子性 OBJC_ASSOCIATION_RETAIN = 01401, // 指定相关对象的强引用,原子性 OBJC_ASSOCIATION_COPY = 01403 // 指定相关的对象被复制,原子性 }; 获得属性
数据压缩实验六--MPEG 感知音频编码设计思想多相滤波器组心理声学模型临界频带掩蔽值计算心理声学模型I的具体过程 码率分配LayerILayerII 实验过程输出音频的采样率和目标码率某个数据帧的比特数,比例因子,比特分配结果选择不同特性的音频文件 感知音频编码设计思想 MPEG-1 Audio LayerII编码器原理
基本思想:分析信号,去掉不能被感知的部分。
通过子带分析滤波器组使信号具有高的时间分辨率,确保在短暂冲击信号情况下,编码的声音信号具有足够高的质量。
又可以使信号通过FFT运算具有高的频率分辨率,因为掩蔽阈值是从功率谱密度推出来的。
输入声音信号经过一个多相滤波器组,变换到多个子带。同时经过心理声学模型计算以频率为自变量的噪声掩蔽阈值。量化和编码部分用信掩比SMR决定分配给自带信号的量化位数,使量化噪声<掩蔽阈值。最后通过数据帧包装将量化的子带样本和其它数据按照规定的帧格式组装成比特数据流。
多相滤波器组 先分成32个相等的子带。
对每个子带每12个样点进行一次比例因子计算。先定出12个样点中绝对值的最大值。查比例因子表中比这个最大值大的最小值作为比例因子。用6比特表示。
第2层的一帧对应36个子带样值,是第1层的3倍,原则上要上传三个比例因子。为了降低比例因子的传输码率,采用了利用人耳时域掩蔽特性的编码策略。
每帧中每个子带的三个比例因子被一起考虑,划分成特定的几种模式。根据这些模式,1个,2个或3个比例因子和比例因子选择信息(每子带2比特)一起被传送。如果一个比例因子和下一个只有很小的差别,就只传送大的一个,这种情况对稳态信号经常出现。
使用这一算法后,和第1层相比,第2层传输的比例因子平均减少了2个。
多相滤波器组的缺点
等带宽的滤波器组与人类听觉系统的临界频带不对应。在低频区域,单个子带会覆盖多个临界频带。在这种情况下,量化比特数不能兼顾每个临界频带。
心理声学模型 人耳听觉系统大致等效于一个信号通过一组并联的不同中心频率的带通滤波器。
临界频带 临界频带是指当某个纯音被以它为中心频率,且具有一定带宽的连续噪声所掩蔽时,如果该纯音刚好被听到时的功率等于这一频带内的噪声功率,这个带宽为临界频率带宽。
临界频带是研究窄带噪声对纯音掩蔽量的规律时被发现的。
使噪声的中心频率等于信号频率,只改变噪声的带宽同时保持噪声的功率谱密度不变,测试纯音听阈随掩蔽噪声带宽变化的特性。纯音的听阈随掩蔽噪声带宽的增大而增大,在带宽增加到某一特定值之后听阈恒定保持不变。
通常认为从20hz到16khz有25个临界频带,单位为bark,越靠近低频,临界频带越细。
掩蔽值计算 音频信号通常有较为复杂的频谱结构,因此能产生掩蔽阈值的掩蔽音分量也有许多。
掩蔽音与被掩蔽音的组合方式有四种,它们可以分别是乐音信号和窄带信号。
Lutfi对多个掩蔽音同时存在时的综合掩蔽效果进行了研究:每个掩蔽音的掩蔽效果先独立变换再线性相加。
心理声学模型I的具体过程 1.采用512(Layer I)或1024(Layer II)样本窗口
Layer I:每帧384个样本点,512个样本点足够覆盖
Layer II和Layer III:每帧1152个样本点,每帧两次。
2.确定声压级别
3.考虑安静时阈值
也即绝对阈值。在标准中有根据输入PCM信号的采样率编制的“频率,临界频带和绝对阈值”表。此表为多位科学家经多次心理声学实验所得。
4.将音频信号分解为“乐音”和“噪声”部分:因为两种信号的掩蔽能力不同。
根据音频频谱的局部功率最大值确定乐音成分,局部峰值为乐音,然后将本临界频带内的剩余频谱合在一起,组成一个代表噪声频率。
5.音调和非音调掩蔽成分的消除
利用标准中给出的绝对阈值消除被掩蔽的成分;考虑在每个临界频带内,小于0.5bark的距离中只保留最高功率的成分。
6.单个掩蔽阈值的计算
音调成分和非音调成分单个掩蔽阈值根据标准中给出的算法求得。
7.全局掩蔽阈值的计算
还要考虑别的临界频带的影响。一个掩蔽信号会对其它频带上的信号蝉声掩蔽效应。这种掩蔽效应称为掩蔽扩散。
8.每个子带的掩蔽阈值
选择出本子带最小的阈值作为子带阈值。
9.计算每个子带信号信掩比
SMR=信号能量/掩蔽阈值,并将SMR传递给编码单元。
码率分配 LayerI 在调整到固定的码率之前,先确定可用于样值编码的有效比特数,这个数值取决于比例因子,比例因子选择信息,比特分配信息以及辅助数据所需比特数。
算法:使整帧和每个子带的总噪声-掩蔽比最小
噪声-掩蔽比NMR=SMR(信掩比)-SNR(信噪比)
循环,直到没有比特可用:对最高NMR的子带分配比特,使获益最大的子带的量化级别增加一级。重新计算分配了更多比特子带的NMR。(每分配1比特,NMR减小6dB)
装帧
LayerII 与LayerI类似,但对LayerI有增强(装帧,缩放因子表示,量化)
装帧:3组/帧 × 12个样本/子带 × 32个子带/帧 = 1152个样本/帧
在用keras循环预测各个主体时,经常会内存溢出。但是单个主体是没有错误的。发现我在对对象重新赋值后内存并没有释放。随着循环次数增加最后内存溢出的
model = keras.models.load_model('F:/DB1/model/Away10reluBNCNN1D/3468910-1/DB1_s'+ str(j) + '1Seg205m.h5') Y_test = to_categorical(np.array(Y_test)) Y_predict = model.predict([Xtest1, Xtest2,Xtest3, Xtest4,Xtest5, Xtest6,Xtest7, Xtest8,Xtest9, Xtest10]) # # 返回每行中概率最大的元素的列坐标(热编码转为普通标签) y_pred = Y_predict.argmax(axis=1) y_true = Y_test.argmax(axis=1) 解决方案: 从别人博客看到的keras无法多次调用model.predict_classes-python黑洞网
1.尝试从函数外部的文件中加载模型,并将模型对象作为函数的参数def predictOne(imgPath, model)。这也将更快,因为不需要每次需要预测时就从磁盘加载权重。
def predictOne(imgPath): model = load_model("withImageMagic.h5") image = read_image(imgPath) test_sample = preprocess(image) predicted_class = model.predict_classes(([test_sample])) return predicted_class 2.
如果要继续在函数内加载模型,请导入后端:
from keras import backend as K 接着
K.clear_session() 在加载模型之前。
首先这不是技术文档,
csdn是一个非常好的记录各种问题,找到解决问题的答案的一个社区,但是我决定以后不在这里发文章了,但我永远都是csdn的忠实用户,因为里面有很多博主花大量心血记录自己的学习过程,分享自己的内容。
各位再见
将列表 组成 字典 使用打包函数zip(里面是可迭代对象 列表是可迭代对象)
zip可以将对象中对应的元素打包成一个元组,然后返回这些元组组成的列表
a=['张三', '王五', '李四','善'] b=[98,47,87] #在打包的时候会以元素少的为主 c={a:b for a,b in zip(a,b)} #将两个列表进行打包遍历 遍历出来的a作为健 b 作为值c=a:b print(c,type(c)) d={b:a for a,b in zip(a,b)} #将两个列表进行打包遍历 遍历出来的a作为健 b 作为值c=a:b print(d,type(d))
本文目录 一、来源及作用存在问题基本作用 二、 基本原理及求解步骤核心思想如何选择投影方向 三、原理分析最大投影方差最小重构代价 四、SVD与PCA的关系 一、来源及作用 存在问题 在我们训练模型的过程中,有时会出现在训练集上误差较小,但到了测试集误差又较大,我们称之为泛化误差,造成这种现象往往是以下几个原因:
训练数据不足训练集与测试集数据分布不同特征维度过高,造成过拟合 而为了解决这一问题,我们又有以下几种方法:
增加样本数量使用正则项对数据进行降维 其中对数据进行降维可以进行人工特征筛选,但往往费时又费力,效果还有可能不好,因此我们可以采用一些模型来进行数据降,其中比较常用的就是PCA(Principal Component Analysis),即主成分分析。
基本作用 PCA经常被用作以下几个方面:
数据降维(降低高维数据,简化计算)数据去噪处理共线特征,降低算法的开销,同时防止样本过拟合 二、 基本原理及求解步骤 核心思想 PCA的核心思想是经过线性变换,将数据从 n n n维线性空间映射至 k k k维( k < n k < n k<n),并且期望在投影方向上信息量最大,同时将数据进行反向重构时代价最小。
比如下面一组数据:
如果我们将其投影至X轴,则其效果如下:
X = [1 7 -4 1 5 -1 3 -2 -6 -2] Y = [ 1.86379123 6.27582279 -3.08964086 3.39810814 6.43125938 -0.57665254 3.06208316 -1.7341361 -6.09519518 -1.36688637] 如果我们将其投影至Y轴,则效果如下:
但如果我们将其投影至过原点的一条直线,其效果将变为:
很显然投影至 y = x y=x y=x直线上,更能体现出数据之间的差异性。
ifconfig命令的全称是network interface configuring, 用来配置Linux系统中的网卡信息。使用ifconfig命令配置的网卡配置信息,只是临时生效的,当网卡或者是机器重启,配置就会消失。只有通过修改配置文件才可以永久保存配置信息了。
ifconfig的常用参数
[root@centoss8 ~]#ifconfig --help
Usage:
ifconfig [-a] [-v] [-s] <interface> [[<AF>] <address>]
[add <address>[/<prefixlen>]]
[del <address>[/<prefixlen>]]
[[-]broadcast [<address>]] [[-]pointopoint [<address>]]
[netmask <address>] [dstaddr <address>] [tunnel <address>]
[outfill <NN>] [keepalive <NN>]
[hw <HW> <address>] [mtu <NN>]
[[-]trailers] [[-]arp] [[-]allmulti]
[multicast] [[-]promisc]
[mem_start <NN>] [io_addr <NN>] [irq <NN>] [media <type>]
[txqueuelen <NN>]
[[-]dynamic]
[up|down] ...
<HW>=Hardware Type.
List of possible hardware types:
loop (Local Loopback) slip (Serial Line IP) cslip (VJ Serial Line IP) slip6 (6-bit Serial Line IP) cslip6 (VJ 6-bit Serial Line IP) adaptive (Adaptive Serial Line IP) ash (Ash) ether (Ethernet) ax25 (AMPR AX.
swin-Transformer论文详解 – 潘登同学的深度学习笔记 文章目录 swin-Transformer论文详解 -- 潘登同学的深度学习笔记 前言网络架构Swin transformer Block巧妙的Mask 实验 前言 swin-Transformer作为CVPR 21的最佳论文,在几乎所有下游任务都表现地很出色;swin-Transformer的全称是Hierarchical Vision Transformer using Shifted Windows;
核心是怎么采用Hierarchical的方式来应用Transformer,从而是的CV与NLP更好的融合;
在VIT那篇论文中,研究团队只是做了VIT用于图像分类的任务,并没有把所有任务都刷过,所以大家还是对Transformer用于CV领域有所担心,而swin-Transformer就是解决这种担心的;
将transformer用于CV领域还是有两大方面的难题的
语义尺度问题(对于空间上靠前的物体与靠后的物体的尺度是不同的,但是可能表示同样的语义信息)图片大小问题(因为VIT做了patch,得到的token长度都是定死的) 目标检测与语义分割的经典架构
目标检测要框不同尺寸的物体,常用架构就是FPN语义分割不仅要找到物体,还要画出来,常用架构就是U-Net VIT的问题
在做patch的时候,始终是在整张图上做patch,学的始终是整张图的信息一个patch中的序列长度,是随着整张图的长度变化而平方级别地变大没有CNN的先验知识 为什么把NLP的模型用于CV领域会表现的很好
因为Transformer具有很强地连接上下文的能力,在一张图片里面,所有物体不是孤立的而是有关系的 网络架构 以ImageNet的图片为例,输入图片大小为224x224x3;
Patch projection层: 每个patch的大小是4x4,那么就有56x56个patch,将patch展平得到4x4x3=48长度的token,所以输入就是[56x56]x48;Linear Embedding层: 接一层Embedding,得到[56x56]x96;Swin transformer Block:因为本质是transformer,所以输入输出维度一致,先不管;Patch Merging:是一种下采样的方式,这里是下采样两倍,就是把原特征图以2x2为一块框住,标上序号,将所有序号为1的挑出来作为一个张量,以此类推,得到 W 2 ∗ H 2 ∗ C \frac{W}{2}*\frac{H}{2}*C 2W∗2H∗C的四个张量,将其拼接得到 W 2 ∗ H 2 ∗ 4 C \frac{W}{2}*\frac{H}{2}*4C 2W∗2H∗4C; 但是为了与CNN的思想一致,就是一次改变通道数只是想让其翻倍,后面接了1x1的卷积,得到[28x28]x192;以恰当的方式重复4次以上过程接global average pooling将最后[7x7]x768的输出变为[1x1]x768; 如果是做分类的话,接FC得到[1x1]x1000; Swin transformer Block Swin transformer Block是Swin transformer的主要贡献,核心是只对每个窗口做自注意力,但是一个self-attention只能做一个序列,这里一个窗口就是一个序列,要做一个图的所有窗口,就要用多头注意力(这里的多头与之前的不一样,之前主要是为了并行计算的,现在真就是多头)
FIFO表示先入先出,是一种存储结构。可满足一下需求:
1、当输入数据速率和输出速率不匹配时。可作为临时存储单元。
2、用于不同时钟域之间的同步。
3、输入数据路径和输出数据路径之间的数据宽度不匹配时,可用于数据宽度调整电路。
同步FIFO
同步FIFO主要是空满信号的产生,
一般情况下写使能并且非满的情况下,写地址加1;
always @(posedge clk or negedge rst_n) begin if(~rst_n) begin waddr <= 'b0; end else begin if(winc & ~wfull) waddr <= waddr + 1'b1; end end 读使能并且非空的情况下,读地址加1。
always @(posedge clk or negedge rst_n) begin if(~rst_n) begin raddr <= 'b0; end else begin if(rinc & ~rempty) raddr <= raddr + 1'b1; end end 因此空和满的信号就要根据读写地址的比较来产生。
当我们只写不读的时候,FIFO总会被填满,因此就产生满信号。当我们一直读的时候,FIFO的数据总会被读完,因此就产生空信号。
通常我们会把写地址和读地址的位宽设置比FIFO深度多1bit,这一bit就是用来判断产生空满的。(假设我们定义FIFO可以存8个数据,那么要设置 :
reg [3:0] waddr; reg [3:0] raddr; 当waddr[2:0]==raddr[2:0] && waddr[3]==raddr[3](也可以直接写成waddr==raddr)时,说明FIFO里没有能读出的数据,因此产生空信号:
文章目录 前言supplier接口定义具体使用 前言 最近看到公司写的rpc框架中,运用到了大量的函数式接口Supplier,下面将对supplier接口的具体使用简单介绍。
supplier接口定义 Java对其定义如下,自jdk1.8的时候新增的功能函数。
@FunctionalInterface public interface Supplier<T> { /** * Gets a result. * * @return a result */ T get(); } 如上定义所示,Supplier 接口仅包含一个无参的方法: T get() ,用来获取一个泛型参数指定类型的对象数据。简单说这个接口只有一个get方法,传入一个泛型T,将返回一个泛型T。
具体使用 示例代码如下:
public class SupplierTest1 { public static void main(String[] args) { //传一个字符串:"hello world" Supplier<String> supplier = () -> "hello world"; //将返回这个字符串 System.out.println(supplier.get()); //传一个对象 Supplier<Student> studentSupplier = () -> new Student("123",12); //将返回一个对象 System.out.println(studentSupplier.get()); System.out.println(studentSupplier.get().getAge()); } } 返回结果:
hello world Student(name=123, age=12) 12 在实际的项目开发中,主要用于数据缓存等场景。
定义:
servlet程序是由web服务器调用,web服务器实现了对servlet生命周期的管理。当你的应用加载并使用一个Servlet时,从初始化到销毁这个Servlet期间会发生一系列的事件,这些事件叫做Servlet的生命周期事件(或方法)。
生命周期:
1.创建Servlet实例
2. WEB容器调用Servlet的init()方法,对Servlet进行初始化
3.Servlet初始化之后,将一直存在于容器中,service()相应客户端请求
4.WEB容器决定销毁Servlet时,先调用Servlet的desttoy()方法,通常在关闭web应用之前销毁Servlet
请求处理流程:
1. 用户点击一个链接,指向了一个servlet而不是一个静态页面。
2. 容器“看出”这个请求是一个Servlet,所以它创建了两个对象HttpServletRequest和HttpServletResponse。
3. 容器根据请求中的URL找到正确的Servlet,为这个请求创建或分配一个线程,并把请求和响应对象传递给这个Servlet线程。
4. 容器调用Servlet的service()方法。根据请求的不同类型,service()方法会调用doGet()或doPost()方法。这里假设调用doGet()方法。
5. doGet()方法生成动态页面,并把这个页面“塞到”响应对象里,需要注意的是,容器还有响应对象的一个引用!
6. 线程结束,容器把响应对象转换为一个HTTP响应,并把它发回给客户,然后删除请求和响应对象。
目录
一、Spring Boot中的配置文件有何作用?
二、Spring Boot中关于配置文件的操作有哪些?
1.在配置文件中配置系统全局的设置,例如tomcat端口号、链接数据库的信息等等。
2.在配置文件中自定义程序猿所要用到的信息,例如密钥信息等。
3.知道了配置文件的基本配置操作,那么如何读取配置文件中的信息呢?
4.在我们配置连接数据库的信息时,可以明显的感觉到存在太多冗余信息,那么有没有更好的措施减少冗余信息呢?答案是有的,我们系统默认的配置文件为.properties,我们可以生成一个.yml的配置文件来进行连接数据库的信息配置。
5.读取配置文件方式二:@ConfigurationProperties 读取一个实体类
6.关于.yml配置文件的value值的特征说明:
6.读取配置文件方式二:@ConfigurationProperties 读取一个数据集合
三:properties VS yml
四:Spring Boot中读取配置文件的方式
@Value
@ConfigurationProperties
Environment
@PropertySource
使用原生方式读取配置文件
一、Spring Boot中的配置文件有何作用? 1.为系统框架提供数据支持。
2.为程序猿自己去调用。
二、Spring Boot中关于配置文件的操作有哪些? 首先我们要了解,在配置文件中的信息都是以Key-Value的形式存在的。
1.在配置文件中配置系统全局的设置,例如tomcat端口号、链接数据库的信息等等。 2.在配置文件中自定义程序猿所要用到的信息,例如密钥信息等。 在此我们要知道,如果是程序猿自己配置的信息,那么可以在遵循Key-Value的格式下,定义任何名称的Key。
3.知道了配置文件的基本配置操作,那么如何读取配置文件中的信息呢? 读取配置的方法一:@Value 注解读取单个配置项,此时我们可以重写afterPropertiesSet方法来查看是否读取到了配置文件中的内容,我们知道afterPropertiesSet方法是参数设置完成之后执行的方法,代码如下:
运行程序,控制台信息如下:
4.在我们配置连接数据库的信息时,可以明显的感觉到存在太多冗余信息,那么有没有更好的措施减少冗余信息呢?答案是有的,我们系统默认的配置文件为.properties,我们可以生成一个.yml的配置文件来进行连接数据库的信息配置。 yml语法格式不同于Key-Value格式但又相似于Key-Value格式,具体写法如下:
key: value
注意:冒号后面一定要加空格,否则配置项就不会生效。
5.读取配置文件方式二:@ConfigurationProperties 读取一个实体类 具体分为两步操作:
1.将配置文件中的一组对象映射到某个类上(以Student类为例)
2.使用注入的方式在其他类中注入Student即可
同样的,在afterPropertiesSet方法中打印Student类实例
结果如下:
总结:具体的步骤为:在配置文件中自定义一个实体类Student,在Model层的Student类中使用@ConfigurationProperties 注解说明需要将配置文件中的哪个实体类映射到当前类当中,注意,需要映射的目标类需要提供Getter和Setter方法,否则就会映射失败,当启动类运行时,就会自动将配置文件中的实体类和目标类完成映射,并且在目标类中添加了@Component注解,即映射完成后会将这个类对象存储到Spring框架中,此时我们在启动类中使用@Autowired注解将这个类对象注入进来,当执行到afterPropertiesSet方法进行打印。
6.关于.yml配置文件的value值的特征说明: 我们通过案例来分析其特征(代码和程序执行结果如图):
①在自定义配置文件application.yml中配置如下配置项
②在启动类中进行配置项的读取
③运行启动类,afterPropertiesSet方法执行结果如下
总结:1.如果是String类型可以不加单引号或者双引号
2.如果加了单引号,运行结果和不加引号的效果是一致的,会自动转义字符串中的特殊符号
3.如果加了双引号,那么字符串中的特殊字符是不会转义的,会按照语义正确执行,比如\n 会执行为换行。
6.读取配置文件方式二:@ConfigurationProperties 读取一个数据集合 该操作类似于读取实体类,也分为两步,过程也是类似的:
1.配置文件中的数据集合映射到具体类当中
2.进行打印
结果如图:
三:properties VS yml properties是以Key-Value的形式配置文件,yml使用的是类似于json格式的树形配置方式,yml层级之间使用换行缩进的方式配置,key和value之间使用“: ”英文冒号+空格的方式设置,并且空格不可省略。properties是系统默认自生成的配置文件,也是早期的配置文件格式,但是其配置存在一定的冗余数据,使用yml可以很好的解决数据冗余的问题。yml通用性更强,支持多语言,不仅仅支持Java、Go、Python等。yml支持更多的数据类型。yml格式的配置文件在写的时候更容易出错,而properties虽然写法比较传统和复杂,但可以很好避免出错。properties和yml可以同时存在于一个项目中,但是假设properties和yml中同时配置了相同的配置项,即对同一个key进行了配置,则只有properties中的配置项生效,而yml中的不会生效,因此,为了避免这个问题,我们最好建议一个项目中使用统一的配置文件类型。 四:Spring Boot中读取配置文件的方式 前两种为我们常用的方式,上面已经描述过了,这里不再进行描述,后三种为不常用的方式,这里仅通过例子进行描述,了解即可,第五种读取方式比较麻烦,是很不推荐的做法,这里不再展示。
print\println\printf的区别:
printf主要是继承了C语言的printf的一些特性,可以进行格式化输出。
print就是一般的标准输出,但是不换行。print将它的参数显示在命令窗口,并将输出光标定位在所显示的最后一个字符之后。
println(“test”)相当于print(“test\n”)就是一般的输出字符串。println 将它的参数显示在命令窗口,并在结尾加上换行符,将输出光标定位在下一行的开始。
System.out.printf(“the number is: %d”,t);
参照JAVA API的定义如下:
‘d’ 整数 结果被格式化为十进制整数
‘o’ 整数 结果被格式化为八进制整数
‘x’, ‘X’ 整数 结果被格式化为十六进制整数
‘e’, ‘E’ 浮点 结果被格式化为用计算机科学记数法表示的十进制数
‘f’ 浮点 结果被格式化为十进制数
‘g’, ‘G’ 浮点 根据精度和舍入运算后的值,使用计算机科学记数形式或十进制格式对结果进行格式化。
‘a’, ‘A’ 浮点 结果被格式化为带有效位数和指数的十六进制浮点数
下在举个例子:
package other;
public class TestPrint {
public static void main(String[] args) {
int i = 4;
double j = 5;
System.out.print(“用print输出i:”+ i);
System.out.println( “用println输出i:”+ i);
System.out.printf(“i的值为%d,j的值为%f”, i,j);
}
}
运行结果为
用print输出i:4用println输出i:4
i的值为4,j的值为5.000000
go-prometheus业务监控指标实战(一) prometheus简介 Prometheus 是一个使用go语言编写的开源系统监控和告警工具包,其开发者和用户社区非常活跃,在GitHub现在是一个独立的开源项目,prometheus生态非常丰富,已经衍生出很多工具包,其中大部分都是用go语言编写的。主要有 Prometheus Server 作为服务端,用来存储时间序列数据。Exporter 用来监控 HAProxy,StatsD,Graphite 等特殊的监控目标,并向 Prometheus 提供标准格式的监控样本数据。alartmanager 用来处理告警。除此之外,官方还提供了各种语言的sdk进行接入,python,java,go等
参考学习资料 官方文档
中文文档
go_client文档
代码地址 gitee
prometheus安装 安装说明 版本:prometheus-2.35.0机器:ubuntu虚拟机,通过静态ip 192.168.64.2 和本机相连
使用静态ip端口占用,默认是9090 安装 下载-地址(不同操作系统包不同) wget https://github.com/prometheus/prometheus/releases/download/v2.35.0/prometheus-2.35.0.linux-amd64.tar.gz 解压 tar -zxvf prometheus-2.35.0.linux-amd64.tar.gz 当前目录结构 配置文件 prometheus.yml 主要关注这一块,job_name即任务名,不重复就行,默认prometheus会有一个任务就是,监控当前自己这个server实例的信息,监控指标的采集方式就是通过 targets 中配置的url地址 path默认是 /metrics
启动 ./prometheus --config.file=prometheus.yml 验证 http://192.168.64.2:9090/metrics 可正常访问,该页面为prometheus采集监控指标的urlhttp://192.168.64.2:9090/ 可以访问到prometheus提供的web界面 如果出现访问不通的情况,可以检查是否是防火墙拦截的相应端口,如果你使用的是云服务器,查看一下是否是安全组没有开对应端口的策略
web界面简单介绍 此处标识当前这台 server 采集了哪几个job,就是在上面prometheus.yml 配置文件中进行配置的
此界面可以对采集到的监控指标进行图表绘制
模型-指标类型介绍 模型 Prometheus 所有采集的监控数据均以指标(metric)的形式保存在内置的时间序列数据库当中(TSDB):属于同一指标名称,同一标签集合的、有时间戳标记的数据流。除了存储的时间序列,Prometheus 还可以根据查询请求产生临时的、衍生的时间序列作为返回结果。
在时间序列中的每一个点称为一个样本(sample),样本由以下三部分组成
指标(metric):指标名称和描述当前样本特征的 labelsets;时间戳(timestamp):一个精确到毫秒的时间戳;样本值(value): 一个 folat64 的浮点型数据表示当前样本的值。 指标类型 Prometheus 的客户端库中提供了四种核心的指标类型。但这些类型只是在客户端库(客户端可以根据不同的数据类型调用不同的 API 接口)和在线协议中,实际在 Prometheus server 中并不对指标类型进行区分,而是简单地把这些指标统一视为无类型的时间序列。
数据压缩实验五--JPEG JPEG编解码原理编码原理解码原理 JPEG文件格式Segment的组织形式Segment Marker JPEG解码解码流程程序设计整体框架三个结构体struct huffman_tablestruct componentstruct jdec_private TRACE 实验步骤1.JPG文件输出YUV文件2.以txt文件输出所有的量化矩阵和所有的HUFFMAN码表输出DC,AC图像并统计其概率分布 JPEG编解码原理 编码原理 基本流程:
1.亮度信号零偏置电平下移,对于灰度级是2n的像素,通过减去2n-1,将无符号的整数值变成是有符号数。这样做的目的是使像素的绝对值出现3位10进制的概率大大减少。
2.DCT变换
对每个单独的彩色图像分量,把整个分量图像分成8×8的图像块,并进行8×8DCT变换,目的是去除图像数据的相关性,便于量化过程去除图像数据的空间冗余。
3.量化
利用人眼视觉特性设计而成的矩阵量化DCT系数,减小视觉冗余。因为人眼对亮度信号比色差信号更敏感,因此使用了两种量化表:亮度量化值和色差量化值;根据人眼对低频敏感,对高频不太敏感,对低频分量采取较细的量化,对高频分量采取较粗的量化。
4.熵编码
(1)对量化后的DC系数进行差分编码
8×8图像块经过DCT变换之后得到的DC直流系数有两个特点:系数的数值较大;相邻8×8图像块的DC系数值变化不大。根据这个特点,JPEG算法使用了差分脉冲调制编码(DPCM)技术对相邻图像块之间量化DC系数的差值进行编码。
(2)AC系数进行Z字扫描和游程编码后,再分别进行VLC编码
Z字扫描:由于DCT变换后,系数大多数集中在左上角,即低频分量区,因此采用Z字形按频率的高低顺序读出,可以出现很多连零的机会,可以使用游程编码。
游程编码:在JPEG和MPEG编码中规定为(run,level):表示连续run个0,后面跟值为level的系数。
解码原理 解码是编码的逆过程。
JPEG文件格式 Segment的组织形式 JPEG在文件中均以Segment的形式组织,它具有以下特点:
(1)均以 0xFF 开始,后跟 1 byte 的 Marker 和 2 byte 的 Segment length(包含表示Length 本身所占用的 2 byte,不含“0xFF” + “Marker” 所占用的 2 byte);
(2)采用 Motorola 序(相对于 Intel 序),即保存时高位在前,低位在后;
(3)Data 部分中,0xFF 后若为 0x00,则跳过此字节不予处理;
Segment Marker SOI
SOI(start of image),表示图像的开始,标记代码FFD8。
APP0
标记代码:FFE0
APP0:Application,应用程序保留标记0。
给出如下信息:
Java实现上传头像 在项目开发中我们会有上传头像,修改头像的操作,controller代码如下 //设置上传文件的最大值 public static final int AVATAR_MAX_SIZE = 10 * 1024 *1024; //设置上传文件类型 public static final List<String> AVATAR_TYPE = new ArrayList<>(); //使用静态块给图片类型赋值 static { AVATAR_TYPE.add("image/jpeg"); AVATAR_TYPE.add("image/png"); AVATAR_TYPE.add("image/bmp"); AVATAR_TYPE.add("image/gif"); } /** * 用户修改头像方法 * @param session * @param file * @return */ @RequestMapping("/changeAvatar") public JsonResult<String> changeAvatar(HttpSession session, @RequestParam("file") MultipartFile file){ //这里面抛出的异常是我们自定义的异常,根据项目需要修改 if (file.isEmpty()){ throw new FileEmptyException("文件为空"); } if (file.getSize() > AVATAR_MAX_SIZE){ throw new FileSizeException("文件大小超出限制"); } if (!AVATAR_TYPE.contains(file.getContentType())){ throw new FileTypeException("
后台密码忘记了怎么办?
如果你是后台管理员,你可以使用 sp_password()方法生成一下新的密码;
你只要在任何一个前台可以访问控制器里,如application/Portal/Controller/IndexController.class.php
<?php namespace Portal\Controller; use Common\Controller\HomebaseController; /** * 首页 */ class IndexController extends HomebaseController { public function index() { echo sp_password('666666');//这次一定要记清了,密码是6个6; exit; $this->display(":index"); } } 访问你的首页:得到加密后的密码,把你刚刚修改的地方还原;
打开你的数据库管理功能,找到'cmf_user'表,找到你的管理员那一列,把密码换进去!
文章目录 前言问题复现解决方案 前言 最近工作中发现同事写代码遗留了一个bug,在使用Collectors.toMap的时候会出现Exception in thread “main” java.lang.IllegalStateException: Duplicate key XXX的错误,下面对当时的问题代码进行复现,并提出解决方案进行解决。
问题复现 问题代码示例如下:
public class Test1 { public static void main(String[] args) { List<User> userList = new ArrayList<>(); userList.add(new User(1L, "aaa")); userList.add(new User(2L, "bbb")); userList.add(new User(3L, "ccc")); userList.add(new User(2L, "ddd")); userList.add(new User(3L, "eee")); Map<Long, String> map = userList.stream() .collect(Collectors.toMap(User::getId, User::getName)); System.out.println(map); } } } 实体User定义如下:
@AllArgsConstructor @Data public class User { private Long id; private String name; } 运行上述代码将会报出如下的错误:
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录 说在前面的话一、给好模板,选好后拷贝css就可以用网址:https://csslayout.io/选中想要的布局后,直接拷贝代码就可以二 、Css Grid宫格布局网址:https://cssgr.id/ 三 、Grid布局网址:https://grid.layoutit.com/ 四、非常好玩的Css选择器的练习游戏网址:https://flukeout.github.io/ 五、FlexBox布局生成器网址 https://loading.io/flexbox/ 总结 说在前面的话 大部分初学前端的同学,在做项目时还需要自己冥思苦想怎么布局,都是卡在对css布局不熟悉上面。前端发展到现在,这么成熟了,有没有方便的工具,根据自己需求,快速获取到自己想要的布局呢? 当然有,下面推荐几个网站工具,那是真香。
一、给好模板,选好后拷贝css就可以用 网址:https://csslayout.io/ 网站有最常超过100种的图案。
有展示类,反馈类、布局类、输入类,导航类
选中想要的布局后,直接拷贝代码就可以 每种图案都有都有对应的html和css代码:
二 、Css Grid宫格布局 网址:https://cssgr.id/ 拷贝代码
三 、Grid布局 网址:https://grid.layoutit.com/ Grid的布局能力很强大
左边输入需要的行数和列数, 在右边可以直接复制代码
四、非常好玩的Css选择器的练习游戏 网址:https://flukeout.github.io/ 总共32关,通过了之后,你的css 选择器能力就是专家级别了
五、FlexBox布局生成器 Flexbox Generator 这网站稳了。Flexbox 是当前非常主流而且好用的一种布局方式,网站支持实时配置和预览。
网址 https://loading.io/flexbox/ 总结 学习前端的路上,可以依靠一些工具,这样走的更快更稳。
写一篇文章不容易,大家帮忙点赞加关注,谢谢。
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); System.out.println("执行"+"开始时间"+df.format(System.currentTimeMillis()) ); 执行结果
"yyyy-MM-dd HH:mm:ss.SSS" 毫秒主要靠后面的SSS设置,前面是用点(.)连接的,不是分号(:)
get,post方式详解 根据HTTP规范,GET用于信息获取,而且应该是安全的和幂等的所谓安全的意味着该操作用于获取信息而非修改信息。换句话说,get请求一般不应该产生副作用。幂等的意味着对同一URL的多个请求应该返回同样的结果。完整的定义并不像看起来那样严格。从根本上讲,其目标是当用户打开一个连接时,它可以确信从自身的角度来看有没有改变资源。比如,新闻站点的头版不断更新。虽然第二次请求会返回不同的一批新闻,该操作仍然被认为是安全的和幂等的,因为它总是返回当前的新闻。反之亦然。POST请求就不那么轻松了。POST表示可能改变服务器上的资源请求。仍然以新闻站点为例,读者对于文章的注解应该通过POST请求实现,因为在注解提交之后站点已经不同了(比方说文章下面出现一条注解)
原理区别: 一般在浏览器中输入网址访问资源都是通过GET方式;在FORM提交中,可以通过Method指定提交方式为GET或者POST,默认为GET提交
Http定义了与服务器交互的不同方法,最基本的方法有4种,分别是GET,POST,PUT,DELETE。
URL全称是资源描述符,我们可以这样认为:一个URL地址,它用于描述一个网络上的资源,而HTTP中的GET,POST,PUT,DELETE就对应着对这个资源的查,改,增,删4个操作。到这里大家应该有个大概的了解了,GET一般用于获取/查询资源的信息,而POST一般用于更新资源的信息(这是GET和POST的本质区别,也是协议设计者的本意,其他区别都是具体表现形式的差异)
根据HTTP规范,GET用于信息获取,而且应该是安全的和幂等的。
所谓安全的意味着该操作用于获取信息而非修改信息。换句话说,GET请求一般不应产生副作用。就是说,它仅仅是获取资源信息,就像数据库查询一样,不会修改,增加数据,不会影响资源的状态。(注意:这里安全的含义仅仅是指非修改信息)幂等的意味着对同一URL的多个请求应该返回同样的结果。 幂等(idempotent,idmpotence)是一个数学或者计算机的概念,常见于抽象代数之中。 幂等有如下几种定义: 对于单目运算,如果一个运算对于范围内的所有的一个数多次进行该运算所得的结果和进行一次该运算所得的结果是一样的,那么我们就称该运算是幂等的。比如绝对值运算就是一个例子,在实数集中,有abs(a)=abs(abs(a)) 对于双目运算,则要求当参与运算的两个值是等值的情况下,如果满足运算结果与参与运算的两个值相等,则称该运算幂等,如求两个数的最大值的函数,有在实数中幂等,即max(x,x)=x 实际应用中,以上2条规定并没有这么严格。引用别人文章的例子:比如,新闻站点的头版不断更新。虽然第二次请求会返回不同的一批新闻,该操作仍然被认为是安全的和幂等的,因为它总是返回当前的新闻。从根本上说,如果目标是当用户打开一个连接时,他可以确信从自身的角度来看没有改变资源即可。
根据HTTP规范,POST表示可能修改服务器上的资源的请求。继续引用上面的例子:还是以网站为例,读者对新闻发表自己的评论应该通过POST实现,因为在评论提交后站点的资源已经不同了,或者说资源被修改了。
上面大概说了一下HTTP规范中,GET和POST的一些原理性问题。但在实际过程中,很多人并未按照HTTP规范去做。,例如:
许多人贪求方便,更新资源时用来GET,因为POST必须要到FROM(表单),这样会麻烦一点对资源的增,删,改,查操作,其实都可以通过GET/POST完成,不需要用到PUT和DELETE另外一个是:早期的Web MVC框架设计者们并没有意识到将URL当作抽象的资源来看待和设计。还有一个严重的问题是传统的Web MVC框架基本都支持GET和HTTP方法,而不支持PUT和DELETE方法。MVC:MVC本来是存在于Desktop程序中的,M是指数据模型,V是指用户界面,C则是控制器。使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式 表现形式区别
为了理解两者在传输过程中的不同,我们先看一下HTTP协议的格式:
HTTP请求:
<request line> //http请求行 <headers> //http请求消息报头 <blank line> //回车换行 [<request-body>]//http请求正文 在http请求当中,第一行必须是一个请求行(requestline),用来说明请求类型、要访问的资源以及使用的HTTP版本。紧接着是一个首部(header)小节,用来说明服务器要使用的附加信息。在首部之后是一个空行,再此之后可以添加任意的其他数据[称之为主体(body)]
GET与POST方法实例:
GET/books/?sex=man&name=Profesional HTTP/1.1 Host:www.wrox.com User-Agrent:Mozilla/5.0(Windows;U;Windows NT 5.1;en-US;rv:1.7.6) Gecko/20050225 Firefox/1.0/1 Connection:keep-Alive POST/HTTP/1.1 Host:www.wrox.com User-Agent:Mozilla/5.0(Windows;U;Windows NT 5.1;en-US;rv:1.7.6) Gecko/20050225 Firefox/1.0.1 Content-Type:application/x-www-form-urlencoded Contect-Length:40 Connection:keep-Alive (-----------) name=Professional%20Apublisher=Wiley 两种方式区别:
(1)GET提交,请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,多个参数用&连接;例如:login.action?
name=hyddd&password=idontkonw&verify=%E4%BD%A0%E5%A5%BD,如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密,得出如:%E4%BD%A0%E5%A5BD,其中%XX中的XX为该符号以16进制表示的ASCLL
POST提交:把提交的数据放置在是HTTP包的包体中。上文实例中红色字体标明的就是实际的传输数据。
因此,GET提交的数据会在地址栏中显示出来,而POST提交,地址栏不会改变
(2)传输数据大小:首先声明:HTTP协议没有对传输的数据大小进行限制,HTTP协议规范也没有对URL长度进行限制
而在实际开发中的存在的限制有:
GET:特定浏览器和服务器对URL的长度有限制,例如IE对URL的长度的限制是2083字节(2K+35)。对于其他的浏览器,如Netscape、FireFox等,理论上灭有长度限制,其限制取决与操作系统的支持。
因此对于GET提交时,传输数据就会收到URL长度的限制
POST:由于不是通过URL传值,理论上数据不受限。但实际各个WEB服务器会规定对post提交数据的大小进行限制,Apache、IIS6都有各自的配置。
(3)安全性
POST的安全性要比GET的安全性高。注意:这里所说的安全性和上面GET提到的”安全“不是同个概念,上面的“安全”的含义仅仅是不做数据修改,这里的安全的含义是真正的Security的含义:比如:通过GET提交数据,用户名和密码将会铭文出现在URL上,因为登录页面有可能被浏览器缓存,其他人查看浏览器的历史记录,那么别人就可以拿到你的账号密码了,除此之外,使用GET提交数据还有可能造成Cross-siterequest forgery 攻击
(4)Http get,post,soap协议都是在http上运行的
编码器的信号又A相、B相、Z相的定义,这个和电机的ABC相的没有关系,本文介绍编码器A相、B相、Z相的概念。
编码器A相B相Z相的概念
谓U相、V相、W相是指的电机的主电源的三相交流供电,与编码器没有任何关系。“A相、B相、Z相”与“U相、V相、W相”是完全没有什么关系的两种概念,前者是编码器的通道输出信号;后者是交流电机的三相主回路供电。
而编码器的A相、B相、Z相信号中,A、B两个通道的信号一般是正交(即互差90°)脉冲信号;而Z相是零脉冲信号。详细来说,就是一般编码器输出信号除A、B两相(A、B两通道的信号序列相位差为90度)外,每转一圈还输出一个零位脉冲Z。
当主轴以顺时针方向旋转时,输出脉冲A通道信号位于B通道之前;当主轴逆时针旋转时,A通道信号则位于B通道之后。从而由此判断主轴是正转还是反转。
另外,编码器每旋转一周发一个脉冲,称之为零位脉冲或标识脉冲(即Z相信号),零位脉冲用于决定零位置或标识位置。要准确测量零位脉冲,不论旋转方向,零位脉冲均被作为两个通道的高位组合输出。由于通道之间的相位差的存在,零位脉冲仅为脉冲长度的一半。
编码器轴每旋转一圈,A相和B相都发出相同的脉冲个数,但是A相和B相之间存在一个90°(电气角的一周期为360°)的电气角相位差,可以根据这个相位差来判断编码器旋转的方向是正转还是反转,正转时,A相超前B相90°先进行相位输出,反转时,B相超前A相90°先进行相位输出(如下图所示)。编码器每旋转一圈,Z相只在一个固定的位置发一个脉冲,所以可以作为复位相或零位相来使用。
ROS,机器人系统的不二选择 文章目录 ROS,机器人系统的不二选择ROS是什么ROS的强大之处ROS的学习方法 总结 ROS是什么 作为新世纪的孩子们,可能从出生以来,我们就伴随着机器人的飞速发展,在年少时也同样拥有着创建属于自己的机器人,完成那些拯救世界的任务,那么现在真正的机器人是什么样的呢,在我们的生活中,已经能够在处处看到各种各样的机器人,他们不知疲倦地帮助人类完成着那些重复无聊以及危险复杂的任务。
他们可能是这样的,负责协作生产的机械臂:
也可能是这样的,用于负责处理物流任务的AGV机器人
当然这些也是,更加类似于人形的机器人
机器人的定义:
机器人有着多种多样的定义,简单的讲,就是可以帮助人类完成那些相对人类难以完成或效率地下的任务,并且不会感到疲倦。机器人的类型:
机器人并不局限于那种我们所了解的人形机器人,机械臂、无人机、无人船乃至于智能小车,都是机器人。现在的主流机器人类型,有智能小车,它们能够实现无人驾驶,主要负责一些仓储物流问题;有机械臂,主要负责智能化的自动生产装配;以及一些特殊的机器人,例如迎宾机器人等。 机器人开发平台:
ROS(Robot Operating System),开源机器人操作系统,是一个机器人软件平台,能为异质计算机集群提供类似操作系统的功能。 机器人的设计制造控制是一个十分综合的研究方向,涉及到了机械、电子、软件、网络、AI等多个专业,对于某个专业的学生来讲,我们只可能掌握其中的几项技能,需要软件帮助我们设计完成机器人,而对于ROS来说:
它支持着无数的电路板,无需我们自行刻录设计;它自带无数的机械模型,无需我们进行机械设计;它拥有着强大的通讯和AI功能,无需我们深入了解基本原理;它拥有者强大的仿真系统,无需我们闭门造车、在设计时考虑诸多问题。 ROS的强大之处 完善的工具:
ROS拥有着一大批实用方便的组件,这里我们简单举例: RVIZ,常用于无人驾驶的导航,在导航领域相比于其他软件有着明显的优势;
Gazebo,机器人的物理仿真软件,相比于matlab、admas等能够更加清晰直观的看到在模拟世界下机器人的运动情况,界面更加流畅美观;博主后续也会推出关于Gazebo的入门教程,敬请期待;
QT工具箱,方便的可视化调节测试界面,能够帮助我们更加迅速准确的完成开发编译;
除了这些,ROS还拥有着相关于导航、SLAM等多种优秀组件,在今后的学习中我们将逐步了解。
成熟的社区:
对于我而言,ROS的强大除了体现在成熟的架构体系,能够帮助我们减少学习其他学科知识的时间之外,更加在于它完善的开发社区,自从ROS系统公布以来,作为世界上主流的机器人开发软件,它逐渐建设出了强大的功能包、强大的开发工具和强大的开发者社区,能够让你在遇到任何问题,找到相应的解决办法。
下列是一些基本的ROS资源网站:
ROS:提供库和工具,帮助软件开发人员创建机器人应用程序;
ROS Wiki:ROS软件包和教程;
ROSCon:ROS开发者年会;
古月居:较大的中文ROS开发社区;
ROS2 Docm:ROS2 文档;
ROS2 design:ROS2 设计文件;
正是由ROS发行版中的功能包、共享开源代码、以及ROS Wiki、ROS Answers和各种博客共同构成一个完善的ROS生态系统,能够有效的帮助我们完成机器人开发研究。
ROS的学习方法 ROS的学习很简单:
ROS的学习并不困难,主要在于需要深刻了解ROS的各个节点之间的关系,理清它们之间的联系,熟悉各种小工具以及社区资源,在逐渐熟练之后,能够大幅度减少我们开发的时间和成本。ROS的学习很困难:
同样ROS的学习也很困难,困难在于很多方面,一方面在于Linux系统,不同windows下的图形化操作,初入Linux学习的我们在开始时很难适应,一方面在于编程知识和ROS架构的要求,导致ROS的学习曲线十分陡峭,难以上手。 面对这样的难题,我们当然不能退缩,相信大家和我一样,学习ROS其实是为了学习机器人,我们始终保持着那样一个对于机器人的激情和热爱,而ROS就是我们的武器,这里也简单给出一些学习教程,希望大家共勉。
古月居ROS入门21讲
Mastering ROS for Robotics Programming, by Lentin Joseph
ROS By Example (Volume 1 and Volume 2), by Patrick Goebel
Programming Robots with ROS: A Practical Introduction to the Robot Operating System, by Morgan Quigley, Brian Gerkey & William D.
Nginx配置https及证书 1 证书2 nginx配置3 参数4 自定义证书5 nginx配置参数详解6 https工作流程7 https协议8 实现https的算法种类9 https简易工作流程10 什么是数字签名11 什么是CA12 什么是数字证书13 从CA方面签发证书的过程14 防止中间人攻击15 SSL证书类型 1 证书 之前我们使用的是自签名的SSL证书,对于浏览器来说是无效的。使用权威机构颁发的SSL证书浏览器才会认为是有效的,这里给大家推荐两种申请免费SSL证书的方法,一种是从阿里云申请,https://common-buy.aliyun.com/?spm=5176.2020520163.0.0.e8f856a74ReRXh&commodityCode=cas 链接地址
另一种是从FreeSSL申请。
使用acme.sh自动申请证书
acme.sh脚本实现了acme协议, 可以从letsencrypt生成免费的证书。一般我们申请的证书有效期都是1年,过期就要重新申请了,使用acme.sh脚本可以实现到期自动申请,再也不用担心证书过期了!
腾讯云申请
2 nginx配置 server { listen 80; server_name www.domain.com ; rewrite ^(.*)$ https://$server_name$1 permanent; #rewrite ^(.*)$ https://$host$1; # return 301 $scheme://$server_name$request_uri; #rewrite ^(.*)$ https://www.xxx.com$1; } server { listen 443 ssl http2; server_name www.domain.com; ssl_certificate /usr/local/key/1_www.domain.com_bundle.crt; ssl_certificate_key /usr/local/key/2_www.domain.com.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.