String str = new String("abc");问一共创造了几个对象???
字符串拼接一般使用StringBuffer或StringBulider来进行 append操作
字符串常量池
https://blog.csdn.net/Jay112011/article/details/113094239?spm=1001.2014.3001.5502
https://blog.csdn.net/Jay112011/article/details/113095434?spm=1001.2014.3001.5502
如果⼀个String类型的字符串,在编译时可以确定是⼀个字符串常量,则编译完成之后,字符串会⾃动拼接成⼀个常量,此时String的速度⽐StringBuffer和StringBuilder的性能好的多
public static void main(String[] args) {
String a = "a";
String b = "b";
String c = a + b;
String d = "a" + "b" + "c";
}
用 javap -p 类名称.class 反编译一下结果如下:
public static void main(String[] args) {
String a = "a";
String b = "b";
(new StringBuilder()).append(a).append(b).toString();
String d = "abc";
}
同时看string c的拼接过程,先⽣成⼀个StringBuilder对象,再调⽤2次append⽅法,最后再返回⼀个String对象,知道String⽐StringBuilder慢的原因了吧!
在编译期间不可以确定字符串值的话,就需要新创建一个字符串对象
ifconfig命令详解,转载自https://blog.csdn.net/boyaaboy/article/details/105795964 功能:ifconfig命令被用于配置和显示Linux内核中网络接口的网络参数。用ifconfig命令配置的网卡信息,在网卡重启后机器重启后,配置就不存在。要想将上述的配置信息永远的存的电脑里,那就要修改网卡的配置文件了。
语法 ifconfig(参数)
情况一:
来源:https://man.linuxde.net/ifconfig
add<地址>:设置网络设备IPv6的ip地址;
del<地址>:删除网络设备IPv6的IP地址;
down:关闭指定的网络设备;
<hw<网络设备类型 ><硬件地址>:设置网络设备的类型与硬件地址;
io_addr:设置网络设备的I/O地址;
irq:设置网络设备的IRQ;
media<网络媒介类型>:设置网络设备的媒介类型;
mem_start<内存地址>:设置网络设备在主内存所占用的起始地址;
metric<数目>:指定在计算数据包的转送次数时,所要加上的数目;
mtu<字节>:设置网络设备的MTU;
netmask<子网掩码>:设置网络设备的子网掩码;
tunnel<地址>:建立IPv4与IPv6之间的隧道通信地址;
up:启动指定的网络设备;
-broadcast<地址>:将要送往指定地址的数据包当成广播数据包来处理;
-pointopoint<地址>:与指定地址的网络设备建立直接连线,此模式具有保密功能;
-promisc:关闭或启动指定网络设备的promiscuous模式;
IP地址:指定网络设备的IP地址; 网络设备:指定网络设备的名称。
实例 显示网络设备信息(激活状态的):
[root@localhost ~]# ifconfig
eth0
Link encap:Ethernet HWaddr 00:16:3E:00:1E:51
inet addr:10.160.7.81 Bcast:10.160.15.255 Mask:255.255.240.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:61430830 errors:0 dropped:0 overruns:0 frame:0
TX packets:88534 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000
RX bytes:3607197869 (3.3 GiB) TX bytes:6115042 (5.8 MiB)
lo
Link encap:Local Loopback inet addr:127.
文章目录 方法一:控件的onClick属性
方法二:匿名类
方法三:内部类
方法一:控件的onClick属性 利用控件自带的onClick属性,指定事件处理函数名称即可实现控件点击事件的处理
这里有个小技巧就是当设置完控件的onClick属性后,它会报没有找到对应事件处理函数的错误,此时点击左侧的警告提示下拉,选择创建事件处理函数到对应的Activity中,如下图所示:
代码 页面布局文件:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:onClick="btn1" android:layout_width="match_parent" android:layout_height="80dp" android:text="按钮1" > </Button> </RelativeLayout> Activity文件:
package com.example.app01; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.Toast; public class MainActivity extends AppCompatActivity { //页面创建初始化时 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toast.makeText(this, "欢迎使用", Toast.LENGTH_SHORT).show(); } //按钮1的事件响应处理函数 public void btn1(View view) { //界面消息提示框 Toast.makeText(this, "
1、微服务技术栈 2、认识微服务 2.1、微服务架构演变 2.2、springcloud(Spring Cloud) SpringCloud和SpringBoot的版本兼容关系如下: 2.3、微服务拆分 2.4、微服务远程调用
从第6期开始参加CSDN编程竞赛到26期,转眼就参与了20期,第一次进入前十,很开心!
这次的题目比较简单一些,很多满分的,在此分享一下我的解答给大家~~
1、题目名称:等差数列 一个等差数列是一个能表示成a, a+b, a+2b,…, a+nb (n=0,1,2,3,…)的数列。在这个问题中a是一个非负的整数,b是 正整数。 现给出三个整数,分别表示等差数列的第一项a、最后一项、公差b,求该数列的和。
#include <stdio.h> int solution(int m, int n, int p){ int result = 0; // TODO: 请在此编写代码 if (m < 0 || n <= 0 || p <= 0 || (n - m) % p > 0) { result = -1; } else { int num = (n - m) / p + 1; result = (m + n) * num / 2; } return result; } int main() { int m; int n; int p; scanf("
mutable修饰符用来指明我们可以对const的变量进行修改,同样,在lambda函数中,也可以使用此修饰符。 按值捕获到lambda函数中的变量在函数体中默认是const类型,即不可修改,在添加了mutable修饰符后,便可以对此变量进行修改,但此时仍然修改的是位于lambda函数体中的局部变量,具体的用处类似于函数体中的static变量,只允许在该函数中改变。
这是由于lambda函数其实也是一种类,然后下面这个初始化语句:
auto f=[v1](A a) mutable -> B{...}
实际上一方面定义了一种返回值为B,接收一个A类型参数的,这样的lambda函数类型。一方面也定义了一个这样的lambda函数对象 f, 所以此处在捕获变量列表中值捕获的变量v1,它其实可以被看做对象f的一个数据成员变量,其初始值为9,因此,函数体内对其每次的变动都会被累积。 int n {}; // 使用mutable时,参数列表“()”是不可以省略的 auto fun = [n] () mutable { return ++n; }; cout<<fun() <<endl; cout<<fun() <<endl; /** Output * 1 * 2 */ 还有一种情况就是当使用匿名的lambda表达式的时候是不会有这种保留改动的现象的。 int n {}; for(int i=3; i>0; i--){ [n] () mutable { n++; cout<<n <<endl; }(); } /** Output * 1 * 1 * 1 */ 这是因为,lambda其实相当于是一个匿名类,原理还是利用其operator(),1 中匿名类被赋值给fun,[]捕获列表相当于给这个类添加了一个静态成员变量,因此每次调用都会+1;而 2 中是在for的函数体内构建lambda表达式,每次进入for都会重新构建一个匿名类,出了for的局部作用域销毁,因此每次都是 1,不会+1。
描述 不知道什么原因,拯救者Y9000P突然很卡,打开windows“任务管理器”,查看CPU性能显示速度不到1GHz。
解决办法 关机
拔掉所有外设,如鼠标、外接键盘、扩展屏幕、和其他设备(电源接头可以不用拔)
关机后,长按开机键20s,释放静电。
20s后再次开机,不再卡顿。
H5开发我们会遇到这样的需求,在页面中打开外部APP。下面我们来总结一下H5打开APP的方式。并详细介绍 URL Scheme 打开方式。
目前常见的唤醒APP方式有:
1:URL Scheme
2:Android intent
3:Safari内置APP广告条
4:Universal Links
方式一:URL Scheme
IOS和Android都支持Scheme,在APP开发时注册一下scheme就可以使用了。如果想跳转指定页面还可以借助URL Router机制。
这种打开APP的方式是现在使用比较多的方式,相对比较简单。但是不同浏览器的错误不同,处理起来比较困难。不同浏览器的支持情况也不同:IOS9以后Safari不再支持js,iframe来触发scheme跳转,并加入了确认机制,这让之前通过js超时机制处理的方式基本不可用。有的应用内置浏览器也不支持这种方式比如:微信、微博等
下面是通过scheme打开app的代码。但是不完全兼容所有浏览器但相对比较稳定,可以参考一下:
/* * brower:{brower: 浏览器, sys: 浏览器系统} * appSrc:{android: 安卓app scheme,ios: IOS scheme} * downSrc:{android: 安卓下载地址,ios: IOS下载地址} * srtt:默认null用于记录定时器 */ function openApp(brower, appSrc, downSrc, srtt) { let openUrl = function() { // 通过iframe的方式试图打开APP,如果能正常打开,会直接切换到APP,并自动阻止a标签的默认行为 // 否则打开a标签的href链接 if (brower.brower == 'Safari') { if (brower.sys === 'ios') { window.location.href = appSrc.ios if (srtt) clearTimeout(srtt) srtt = setTimeout(() => { // document.
PostgreSql 创建工作负载 填写基本信息 选择负载类型为“部署”输入工作负载名称 填写容器信息 选择添加容器输入容器名称填写镜像地址填写环境变量设置数据库端口
填写存储挂载 上方填写数据库文件存储路径下方填写第二步容器信息中的PGDATA环境变量 填写服务/应用路由 jar包项目 创建工作负载 填写基本信息 选择负载类型为“部署”输入工作负载名称
填写容器信息 选择添加容器输入容器名称填写镜像地址增加命令参数
jre不能单纯作为服务启动,需要填写启动jar包命令,工作目录为jar包所在地址,使用java -jar 启动jar包填写环境变量
工作负载重启后ip地址是会发生变化的, 所以在数据库url的环境变量中,使用数据库的容器名称可代替ip地址进行填写
存储挂载和数据库一样,不做过多描述 服务/应用路由 服务只需填写项目端口即可。
应用路由需要配合nginx一起配置,需要填写域名和通过访问的路径做映射,填写之后对应在服务器中的nginx做一下代理配置即可。
tomcat + war包项目 创建工作负载 基本信息、容器信息与jar包一致,不过端口需要填写tomcat的默认端口:8080 存储挂载 存储挂载除了一个项目文件存放的数据卷外,需要增加一个映射war包位置的数据卷
NFS Path是服务器中存放war包的路径,tomcat启动的话是默认启动tomcat路径下的webapps文件夹下的war包,所以在这里做一次挂载。
服务/应用路由 服务/应用路由和jar包项目的区别不大,唯一不同的是,jar包的前端匹配映射规则是自定义的。tomcat会有一个默认的path,也就是war包的名称。所以在路径映射那里,需要填写war包的名称。
最近也是用到了若依的多级联动,效果如下(可多级)
若依有已经封装好的一套js,难点在于后端数据封装,前端按照封装好的代码引用即可。
这里主要分享下关于后端数据如何封装多层。后端代码直接奉上。
记得要把集合转json处理:JSON.toJSON(cxList)
cxList :返回前端的数据 List<CxSelect> cxList = new ArrayList<CxSelect>(); //deptList:第一级数据集合:进行循环,把第一级的对象封装到最外层的集合 for (SysDept dept:deptList){ CxSelect firstSelect = new CxSelect(); firstSelect.setN(dept.getDeptName()); firstSelect.setV(dept.getDeptId().toString()); //第二级数据集合 List<BaseSourceChannel> pidList = baseSourceChannelService.selectBaseSourceChannelList(faParam); List<CxSelect> secondList = new ArrayList<CxSelect>(); for (BaseSourceChannel as:pidList){ CxSelect secondSelect = new CxSelect(); secondSelect.setN(as.getSourceName()); secondSelect.setV(as.getId().toString()); sonParam.setStatus("1"); sonParam.setPid(as.getId()); List<BaseSourceChannel> sonList = baseSourceChannelService.selectBaseSourceChannelList(sonParam); //第三级数据集合 List<CxSelect> thirdList = new ArrayList<CxSelect>(); for (BaseSourceChannel model:sonList){ CxSelect thirdSelect = new CxSelect(); thirdSelect.setN(model.getSourceName()); thirdSelect.setV(model.getId().toString()); thirdList.add(thirdSelect); } //在每一次第二级的对象内的第三级集合循环后,把第三级的集合赋值给第二级对象的S属性里, //并把该对象塞到第二级集合里 secondSelect.setS(thirdList); secondList.
一、IDEA简介 IDEA 全称 IntelliJ IDEA,是java编程语言的集成开发环境。IntelliJ在业界被公认为最好的Java开发工具,尤其在智能代码助手、代码自动提示、重构、JavaEE支持、各类版本工具(git、svn等)、JUnit、CVS整合、代码分析、 创新的GUI设计等方面的功能可以说是超常的。IDEA是JetBrains公司的产品,这家公司总部位于捷克共和国的首都布拉格,开发人员以严谨著称的东欧程序员为主。它的旗舰版还支持HTML,CSS,PHP,MySQL,Python等。免费版只支持Java,Kotlin等少数语言。下载地址(官网):官网下载IDEA虽然也有自带的主题,但是非常的单一,使用久了也会造成审美疲劳,影响开发人员的开发人员视力。 以下是本人正在使用的一款主题:
主题下载地址: 下载主题
提取码:1324
可以配合我的settings文件,一起使用。
如果该文章对您有用,麻烦点赞 收藏 加关注哦!!! 万分感谢。
一、创建应用 首先需要系统中有node环境 其次安装npm
安装angular-cli npm install @angular/cli -g
创建应用 ng new angular-test --minimal --inline-template false
--skipGit=true
--minimal=true 创建没有单元测试的简易脚手架
--skip-install
--style=css
--routing=false
--inlineTemplate
--inlineStyle
--prefix
运行应用 ng serve
--open=true 应用构建完成后在浏览器中运行
--hmr=true 开启热更新
hmrWarning=false 禁用热更新警告
--port 更改应用运行端口
二、组件 命令创建模板 ng g c <component-name> // ng g c user// 一个模板一般拥有以下内容import { Component } from'@angular/core'; @Component({ selector: 'app-user', template: ` <h1> user works! </h1> `, styles: ['h1 { font-weight: normal; }'] }) exportclassUserComponent { } // template 为单独文件时 改为templateUrl: ''// styles 为单个或多个文件时 styleUrls: [] 组件生命周期(按以下顺序执行) constructor 实例化组件类的构造函数,用于接收注入服务
上文创建了一堆 utils、component-info,并实现了新组件模块相关目录和文件的创建。本文继续实现后面的内容。
1 组件样式文件并导入 在 src/service 目录中创建 init-scss.ts 文件,该文件导出 initScss 函数。
由于 .vue 类型的组件的样式就直接写在了 style 中,故首先判断组件类型是否是 tsx,tsx 类型的组件才进行这一步的操作:
在 scss/components/ 目录下创建组件的 scss 文件 _xxx.module.scss;在 scss/components/index.scss 中导入 _xxx.module.scss。 1.1 init-scss.ts 代码实现如下:
import { ComponentInfo } from '../domain/component-info' import path from 'path' import { scssTemplate } from '../util/template-utils' import fs from 'fs' import { g } from '../util/log-utils' const updateComponentScssIndex = (scssRootPath: string, lineName: string) => { const indexScssPath = path.resolve(scssRootPath, 'components/index.
通常在交付MYSQL数据库前会将日志目录与数据文件分开,为其单独设立一个文件系统,这样便于掌握日志与数据的空间使用情况。如果不是业务突然增长,binlog会按照默认设置的过期时间自动被清理,但是有时候业务量增长是很突然的,比如上线了一个活动等,所以设置binlog自动清理是每个MYSQL管理员必须要做的一件事情。
两种binlog清理方法的选择 按MYSQL8.0官方手册的说法,purge binary log 和 expire_logs_senconds 都可以安全清理binlog文件,那么到底该选择哪一种呢?
1、选择参数expire_logs_senconds。对于大公司、大企业来说,交付的数据库数量较多,数据库通常有统一的部署规范,这种情形就可使用本参数来设置所有的数据库binlog自清理周期,例如本公司大基线要求是7天。
2、选择命令purge binary log。这种方式比较适合临时清理一下的场景,比如自清理脚本。例如某应用binlog文件突增,触发自清理条件就会清理,但不会修改过期参数expire_logs_senconds,当业务量下来是binlog又会保留的久一点。
值得注意的是,官方手册中有一句话 “为了手动清理binlog日志文件,请用 purge binary log 命令”
清理方法1(purge binary log) 清理时,PURGE BINARY LOGS和PURGE MASTER LOGS这两个命令任选其一即可,PURGE命令会根据mysql-bin.index的内容来确定被清理的binlog日志文件。
The PURGE BINARY LOGS statement deletes all the binary log files listed in the log index file prior to the specified log file name or date. BINARY and MASTER are synonyms. Deleted log files also are removed from the list recorded in the index file, so that the given log file becomes the first in the list.
打开修改个人信息页面 , f12 , 打开console, 输入下面的代码 ,回车 , 刷新看一下吧
注释:上传个图片看看自己的aid是不是2608,如果不是改成你的aid
var ajax = new XMLHttpRequest(); ajax.open("post", "https://juejin.cn/web/user/update/user_info/", true); ajax.setRequestHeader( "content-type", "application/x-www-form-urlencoded" ); ajax.send( "aid=2608&avatar=https://p3-passport.byteimg.com/img/user-avatar/2741f39cc0043a66c7e568a982d2647a~100x100.awebp" ); ajax.onreadystatechange = function() { if (ajax.readyState == 4 && ajax.status == 200) { var c = ajax.responseText; console.log(c); } }; 下面写了一个简单的计时器执行(闲着无聊写着玩的同样是在console里执行)
function jjPost(){ var ajax = new XMLHttpRequest(); ajax.open("post", "https://juejin.cn/web/user/update/user_info/", true); ajax.setRequestHeader( "content-type", "application/x-www-form-urlencoded" ); ajax.send( "aid=2608&avatar=https://p3-passport.byteimg.com/img/user-avatar/2741f39cc0043a66c7e568a982d2647a~100x100.awebp" ); ajax.onreadystatechange = function() { if (ajax.readyState == 4 && ajax.
首先,系统的网络安全需要考虑的因素包括:1. 加密算法:使用强大的加密算法来保护网络数据;2. 防火墙:使用防火墙来阻止未经授权的访问;3. 身份验证:使用身份验证来验证用户的身份;4. 日志记录:记录系统的安全事件和活动;5. 安全更新:及时更新系统中的安全补丁;6. 用户权限管理:严格控制用户的访问权限;7. 安全审计:定期进行安全审计,发现和解决安全漏洞。
最近接口经常被频繁访问,我估计是线上文档泄露了,所以今天看了看如何对swagger文档添加一个密码访问
pom配置 <!-- Swagger2 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> <version>1.9.2</version> </dependency> <!-- END:必要组件 --> swagger配置种开启EnableSwaggerBootstrapUI 在swagger的配置文件种添加注解@EnableSwaggerBootstrapUI
@Configuration @EnableSwagger2 @EnableSwaggerBootstrapUI public class Swagger2Config {} 在全局配置添加验证方式 不让访问文档 在application.yml或application.properties种添加:
swagger: production: true 效果:
验证密码后访问 swagger: basic: enable: true username: xxx password: xxx 效果:
登陆后即可访问文档
最近频繁听到信创这个词语,但对于信创相关知识不是很了解。不少人在问,如何如何通俗理解信创国产化是什么意思?有哪些系统?有什么意义?今天我们大家就来一起简单聊聊。
通俗理解信创国产化是什么意思?
信创国产化通俗来讲,就是在核心芯片、基础硬件、操作系统、中间件、数据服务器等领域实现信创产业的国产替代。信创产业是数据安全,网络安全的基础,因此需要大家积极配合,大力推动。
信创国产化系统有哪些?
CPU有龙芯、兆芯、飞腾 、海光、申威和华为等等;主要国产操作系统包括中标麒麟、银河麒麟、普华软件、深度等;数据库有南大通用、人大金仓等;国产中间件厂商主要包括东方通、普元信息、宝兰德、中创股份及金蝶天燕等;国产流式软件厂商包括金山办公、永中office、中标普华等;版式软件包括福昕软件、数维网科等;电子签章包括书生电子、安证通、金格科技等;OA软件包括蓝凌软件、致远互联等。
信创国产化有什么意义?
信创国产化对于加快我国企业数字化转型具有深远意义,不仅能够为企业赋能增效,还能推动经济持续发展。在多方政策的推动下,信创国产化步入快车道,我国信创发展体系已初具雏形。数据显示,预计到2025年,信创市场规模将突破8000亿元。所以,持续加快建设信创产业高质量生态体系,已经成为推动新旧动能转换和实现信息技术国产化的发展方向。
知识拓展:符合信创要求的堡垒机有哪些?支持哪些系统?
目前市面上符合信创要求的堡垒机不多,但行云管家堡垒机可以。行云管家支持各类信创产品操作系统、数据库、服务器等国产软硬件部署,如深度LINUX、银河麒麟、中标麒麟、红旗LINUX、统信UOS等等。
1、SpringCloud简介与5大常用组件
过程 ubuntu18.04 使用如下命令安装protobuf
pip3 install protobuf 安装完毕后报错
protobuf requires Python '>=3.7' but the running Python is 3.6.9 解决 更新pip
python3 -m pip install --upgrade pip 再次安装之前安装的module
pip3 install protobuf 不再报错
瀚高数据库
目录
环境
文档用途
详细信息
环境
系统平台:Linux x86-64 Red Hat Enterprise Linux 7
版本:4.5.7
文档用途
1、如何使用ArcGIS连接瀚高数据库
2、如何导入GIS数据
详细信息
一、ArcGIS与HGDB的对应关系
找到如上图所示的路径,其中的数字代表的就是当前ArcGIS与瀚高的适配版本,如瀚高版本过高可能会导致连接不上的问题
二、在HGDB安装postgis扩展
create extension postgis; 三、ArcGIS连接HGDB的步骤
打开ArcGIS,点解数据库连接,双击添加数据库连接
数据库平台选择PostgreSQL;
实例写法格式为:ip,端口号;
其余按提示填写即可(数据库那一栏不能点击下来按钮选择,需要手动输入数据库名称)
点击确定,ArcGIS就能连接上HGDB了
四、ArcGIS往HGDB导入地理信息数据
右键新建立的数据库连接,选择导入–要素类(单个)
把地理信息位置文件(附件)放到下图的路径下,输入要素类会自动选择该文件
输出要素类的值为导入瀚高数据库的表名(瀚高数据库需要创建与数据库名同名的模式名)
点击确定之后,地理数据就导入到瀚高数据库了
.plus, .minus { width: 11px;/* 大小 */ height: 11px;/* 大小 */ position: relative; display: inline-block; } .plus::before, .minus::before { content: ' '; position: absolute; left: 0; top: 0; bottom:0; margin:auto 0; width: 100%; height: 3px; /* 粗细 */ background-color: white; /* 颜色 */ } .plus::after { content: ' '; position: absolute; left: 0; right:0; margin: 0 auto; width: 3px; /* 粗细 */ height: 100%; background-color: white; /* 颜色 */ } 实现:
在使用vue开发可视化大屏的时候,通常会遇到自适应的要求。这里有两个常规尺寸的自适应解决方案
方案1:使用scale 使用transform:scale,等比例缩放来解决大屏的自适应,这一套解决方案阿里云的datav也有使用,但是vue里可以使用第三方插件,比如vue3-scale-box这一类。
1.安装
npm install vue3-scale-box --save //安装插件 2.使用
//具体页面使用 app.vue <template> <ScaleBox :width="1920" :height="1080"> <router-view/> </ScaleBox> </template> <script> import ScaleBox from "vue3-scale-box" components:{ scaleBox } </script> 这里面width和height就是设计稿的长宽
这个方法可能会遇到一些问题,慎重选择使用哦
方法2:使用flexible和csspost-pxtorem 这一个方法应该是比较常规的方法
使用插件自动的将写的px转换为rem来使用,放大缩小的展示都很正常
安装 npm install lib-flexible npm install postcss-pxtorem 2.使用
在根目录新建postcss.config.js文件
module.exports = { "plugins": { "postcss-pxtorem": { rootValue: 192, // 设计稿宽度 propList: ['*'], selectorBlackList: ['.norem'], // 过滤掉.norem-开头的class,不进行rem转换 exclude:['screen'] //文件夹screen一下的文件不需要进行px-rem适配 } } } 在本地新建一个rem.js文件 刷新rem
; (function (win, lib) { var doc = win.
数据库在编程中是一个很重要的环节,这里是记录rust如何操作数据库并以mysql为主的做简单的使用说明。rust中对mysql数据库存有支持的我所知道的crate:
mysql 单一驱动sqlx 多驱动,异步,不是ORMdiesel 多驱动,异常,ORM 因为mysql的crate有点单一,这里主要是说明sqlx及diesel的使用,分两篇记录。本都吃是以sqlx为说明
在这过程的走了不少不能言语的弯路主要有以下两点:
文档都是英文,多数都是偏向于postgres(英文不好)select出来的数据不直观。不像php那样直接一个关联数据解决所有问题 sqlx的sql是原始的,我所知道的是它不像ORM那样,能通过一系列的方法组合成相应的sql,sql都是手写的。是不是用ORM,看自己的需求进行选择
crate 依赖(Cargo.toml文件) [dependencies] tokio = { version = "1", features = ["full"] } sqlx = { version = "0.6", features = [ "runtime-tokio-native-tls", "mysql", "chrono", "json", "macros", "decimal" ] } dotenvy = "0.15.6" chrono = { version = "0.4.23", features = ["serde"] } sqlx-cli = "0.6.2" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" rust_decimal = "
启用这些设备
1.Vulhub靶场介绍 Vulhub:是一个面向大众的开源漏洞靶场,无需docker知识,仅需要执行两条简单的命令即可编译、运行一个完整的漏洞靶场镜像。让漏洞复现更加简单,让入门小白可以更加专注于漏洞本身。
官网:Vulhub - Docker-Compose file for vulnerability environment
2.资源准备 由于整个过程都是采用安装包进行安装的,原因在安装步骤的也进行解释了,这里提供一下各个资源的下载地址吧,若下载慢,也可以使用我的百度网盘中的资源进行安装。
资源包:百度网盘 请输入提取码提取码:ko3a
下载.tgz格式的docker离线安装包:Index of linux/static/stable/x86_64/
下载.rpm格式的docker离线安装包:Index of linux/centos/7/x86_64/stable/Packages/
下载Vulhub靶场压缩包:GitHub - vulhub/vulhub: Pre-Built Vulnerable Environments Based on Docker-Compose
3.靶场安装步骤 这里采用的均是使用安装包进行安装,由于在安装docker、docker-Compose和Vulhub的时候可能会存在下载很长时间的情况,而这样就无需下载,直接进行安装就快很多了。
3.1.安装Docker 3.1.1.新建Docker目录 新建/usr/docker/目录,这个目录是用于 Docker离线安装包存放和安装的。
命令:mkdir /usr/docker/ 3.1.2.上传Docker安装包 如果使用xshell连接的话,使用rz即可进行上传,若输入rz后无法进行上传,那么就是由于未安装,使用yum install lrzsz即可安装。
3.1.3.安装Docker服务 使用yum进行安装。
命令:yum install docker-ce-17.12.1.ce-1.el7.centos.x86_64.rpm -y 3.1.4.设置Docker服务 这里需要开启docker服务以及设置开机自启动。
命令:systemctl start docker && systemctl enable docker 3.1.5.查看Docker状态 这里需要查看一下刚刚设置过的docker服务的状态。
命令:systemctl | grep docker 3.2.安装Docker-compose 3.2.1.进入相关目录 这里需要进入/usr/local/bin/目录。
命令:cd /usr/local/bin/ 3.2.2.上传Docker-compose安装包 这里的上传方式和上传docker安装包一样,都使用rz。
3.2.3.添加执行权限 这里需要为docker-compose安装包添加执行权限。
目录 Cadence Allegro 17.4学习记录开始01-原理图Capture CIS 17.4一、创建工程文件夹二、建立原理图工程三、创建元件库绘制元件库符号实例简单的元件,比如AT24C02homogeneous分列元件的分部具有相同属性,比如运放,LM358heterogenous分列元件的分部具有不同属性,比如STM32单片机IC,STM32F405RGT6元件库网址总结 四、自带元件库 Cadence Allegro 17.4学习记录开始01-原理图Capture CIS 17.4 一、创建工程文件夹 在打开软件前,可以先创建一个工程文件夹,然后在这个工程文件夹里面创建3个文件夹,分别用于存放原理图文件,封装,PCB文件,这是一个好习惯便于管理文件。
二、建立原理图工程 使用软件:Capture CIS17.4,
首次打开这个软件,出现以下选择:根据①②③这三个步骤选择即可。
创建工程:
第一,点击工程,弹出对话框
打开原理图文件夹里面,就会用有原理图文件了
这个就是创建原理图工程的方法,推荐使用这个方法
第二,点击设计,直接创建原理图工程,默认名,DESIGN1
这个也可以创建原理图工程,都是一样的,我一般不使用,需要修改名字
三、创建元件库 名字和路径都默认了,保存在SCH文件夹里。
下面就可以开始绘制自己需要的原理图元件符号了
绘制元件库符号实例 简单的元件,比如AT24C02 第一,新建元件
第二,点击OK,进入元件绘制界面
绘制元件的基本步骤与Altium designer的基本一致,放置管脚、设置管脚属性、放置Body、设置元件属性
第三,放置管脚阵列(Pin Array),管脚阵列可以同时放置多个管脚,实现快捷放置
具体使用,选中PIN ARRAY,如下,注意,其中名称可以用以数字结尾的字符串,后续增加的管脚会以每次步进值增加该值。
图中设置的结果如下
第四,设置管脚属性
第五,放置Body
下面就是完成后的元件符号
homogeneous分列元件的分部具有相同属性,比如运放,LM358 第一,新建元件
第二,点击OK,进入元件绘制界面
第三,放置管脚阵列(Pin Array),管脚阵列可以同时放置多个管脚
第四,设置管脚属性
第五,放置Body,文本标志
这样就可以了
heterogenous分列元件的分部具有不同属性,比如STM32单片机IC,STM32F405RGT6 第一,新建元件
按照IO口、电源、启动,将管脚分为4个部分,分别为PAPB口、PCPD口、启动、电源部分。
封装为LQFP64,如下图
第二,点击OK,进入元件绘制界面
绘制元件的基本步骤与Altium designer的基本一致,
放置管脚、设置管脚属性、放置Body、设置元件属性
根据放置管脚、设置管脚属性、放置Body、设置元件属性这四个属性分别绘制ABCD四个部分就可以了,
这样就可以了
元件库网址 这里有两个网址,可以下载元件库,
新版的网址,链接: IC封装网-行业IPC标准化的元件库及PCB封装库资源下载平台
旧版的网址,链接: IC封装网
两个网址,都可以下载元件库
总结 简单元件制作 可用管脚阵列加快设计
针对复杂焊盘中间需要挖空的特殊焊盘,通过简单的Convert命令转换成“region”是不能实现的,因为Convert命令虽然能将复杂的封闭曲线进行转换,但封闭的曲线内部不能再嵌套曲线,这导致无法制作中间确实铜皮的图形。 本文是操作绘制如下的焊盘: 其设计思想是通过convert命令和覆铜操作绘制带挖空区域(挖出两个圆形)的铜皮。 此元器件的封装直接在PcbLib库中不能绘制,必须新建pcb文件进行绘制,因为需要覆铜操作。 1.首先绘制复杂形状的曲线,本人是直接在keepout层绘制的: 2.设置板边,选中最外侧的曲线,点击“design”,点击“board shape”,点击“define from selected objects”,成功设置板外框: 3.设置中间挖空的区域,点击左侧圆,点击菜单“tools”,点击“convert”,点击“create cutout from selected primitives”,创造不覆铜cutout区域,右侧的圆也是同样操作 4.覆铜,PCB中一定要有一个线网络名,本人是手动建立了“gnd”的网络标号,也可以通过复制其他pcb的线标号。另外,为了保证覆铜的铜皮紧挨板边,建议将“rule”里设置clearance设置为0mil。 5.将此铜皮复制到PcbLib库中,手动增加一个表贴焊盘,并将焊盘放到铜皮里面,本文为了显示效果,将焊盘放到铜皮附近。 6.接下来制作top paste层和topsolder层,可以直接复制图形即可。至此带挖空区域的焊盘制作完毕。
1、概述 DoIP是Diagnostic communication over Internet Protocol 的简称,顾名思义,就是通过网络协议进行诊断通信。
ISO 13400的所有部分都基于ISO/IEC 7498-1中规定的OSI基本参考模型,该模型将通信系统分为七层。从上到下称为应用层(第7层)、表示层、会话层、传输层、网络层、数据链路层和物理层(第1层)。ISO 13400使用了这些层的一个子集。ISO 13400为DoIP指定了传输层、网络层、数据链路层和物理层。
ISO 13400由以下部分组成,其总称为"道路车辆-互联网协议诊断通讯"(DoIP):
1、 一般信息和用例定义。
2、 传输协议和网络层服务。
3、 基于IEEE 802.3的有线车辆接口。
以下部分正在筹备中
4、 以太网诊断连接器。
5、 一致性测试规范。
ISO 13400协议与OSI基本参考模型的对应关系可参考下图:
2、DoIP的优势 1、更快的诊断响应。
2、传输大量数据的时间更短(用于软件刷新和参数下载)。
2、使得远程的直接诊断成为可能。
3、基本要求 3.1、数据链路与物理层要求 根据ISO-13400的要求,DoIP通信在物理层支持100BASE-TX (100 Mbit/s Ethernet) 和10BASE-T (10 Mbit/s Ethernet) 两种制式。DoIP设备的MAC地址也符合IEEE 802.3 的要求。
3.2、传输层与网络层要求 ISO-13400规定,DoIP通信在传输层上必须同时支持UDP和TCP,并将UDP和TCP的使用场合进行了定义,对所使用的端口号也进行了定义。后续会说明。
ISO-13400规定,DoIP通信在网络层上使用IPv6协议,但是为了后向兼容的原因,也支持IPv4。此外,对于IPv4来说,还要支持地址解析协议(ARP),对于IPv6来说,还要支持邻居发现协议(NDP),这两个协议是用于在只知道IP地址的情况下获取MAC地址的。
4、基本数据类型 DoIP数据作为SDU层层向下传递,直至构成完整的以太网帧,通过物理层的介质发送出去。DoIP的数据内容分为5个部分:
1、所使用的ISO13400版本信息,占用1个字节。
2、所使用的ISO13400版本信息依比特取反,占用1个字节。
3、数据类型,占用2个字节(标识本帧数据的用途,比如用于上报或请求车辆信息、诊断命令、诊断逻辑链接激活、alive check等)。
4、数据长度,占用4个字节(标识后面的数据长度)。
5、诊断数据,长度为0至2的32次方减1,这里的数据又分为sender address、receiver address、应用数据这三部分。
4.1、ISO13400版本取值范围 DoIP版本取值范围如下表:
Version
含义
0x00
reserved
0x01
DoIP ISO/DIS 13400-2:2010
0x02
一、webpack 按需加载momentjs 语言包
momentjs是一个很好用的日期处理插件。但是webpack打包时我们会发现这个插件体积比较大(如下图)如图可以看出locale是大的主要原因
webpack提供的ContextReplacementPlugin插件允许我们覆盖打包时的查找规则
plugins: [ new webpack.ContextReplacementPlugin( /moment[/\\]locale$/, /zh-cn/, ), ] 配置只打包zh-cn语言包后文件体积明显减少
文章目录 SpringMVC框架介绍SpringMVC原理图SpringMVC接口解释SpringMVC运行原理 SpringMVC框架介绍 Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。
spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,可以选择是使用内置的 Spring Web 框架还是 Struts 这样的 Web 框架。通过策略接口,Spring 框架是高度可配置的,而且包含多种视图技术,例如 JavaServer Pages(JSP)技术、Velocity、Tiles、iText 和 POI。Spring MVC 框架并不知道使用的视图,所以不会强迫您只使用 JSP 技术。
Spring MVC 分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行定制。
Spring的MVC框架主要由DispatcherServlet、处理器映射、处理器(控制器)、视图解析器、视图组成。
SpringMVC原理图 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PvNAJ1J3-1632905720761)(https://img-my.csdn.net/uploads/201211/16/1353059506_5137.jpg)]
SpringMVC接口解释 DispatcherServlet接口:
Spring提供的前端控制器,所有的请求都有经过它来统一分发。在DispatcherServlet将请求分发给Spring Controller之前,需要借助于Spring提供的HandlerMapping定位到具体的Controller。
HandlerMapping接口:
能够完成客户请求到Controller映射。
Controller接口:
需要为并发用户处理上述请求,因此实现Controller接口时,必须保证线程安全并且可重用。
Controller将处理用户请求,这和Struts Action扮演的角色是一致的。一旦Controller处理完用户请求,则返回ModelAndView对象给DispatcherServlet前端控制器,ModelAndView中包含了模型(Model)和视图(View)。
从宏观角度考虑,DispatcherServlet是整个Web应用的控制器;从微观考虑,Controller是单个Http请求处理过程中的控制器,而ModelAndView是Http请求过程中返回的模型(Model)和视图(View)。
ViewResolver接口:
Spring提供的视图解析器(ViewResolver)在Web应用中查找View对象,从而将相应结果渲染给客户。
SpringMVC运行原理 客户端请求提交到DispatcherServlet由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的ControllerDispatcherServlet将请求提交到ControllerController调用业务逻辑处理后,返回ModelAndViewDispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图视图负责将结果显示到客户端 DispatcherServlet是整个Spring MVC的核心。它负责接收HTTP请求组织协调Spring MVC的各个组成部分。其主要工作有以下三项: 截获符合特定格式的URL请求。初始化DispatcherServlet上下文对应的WebApplicationContext,并将其与业务层、持久化层的WebApplicationContext建立关联。初始化Spring MVC的各个组成组件,并装配到DispatcherServlet中。 具体实例可参考:http://blog.csdn.net/kkdelta/article/details/7274708
http://downpour.iteye.com/category/196182
#!/bin/sh echo ================================= echo 自动化部署脚本启动 echo ================================= echo 停止原来运行中的工程 APP_NAME=xr-admin tpid=`ps -ef|grep $APP_NAME|grep -v grep|grep -v kill|awk '{print $2}'` if [ ${tpid} ]; then echo 'Stop Process...' kill -15 $tpid fi sleep 2 tpid=`ps -ef|grep $APP_NAME|grep -v grep|grep -v kill|awk '{print $2}'` if [ ${tpid} ]; then echo 'Kill Process!' kill -9 $tpid else echo 'Stop Success!' fi # 先拉取git clone代码到下面的路径 echo 准备从Git仓库拉取最新代码 cd /home/xiangmu/qilu-finance-background-code echo 开始从Git仓库拉取最新代码 git pull echo 代码拉取完成 echo 开始打包 mvn clean package -P dev cd /home/xiangmu/qilu-finance-background-code/xr-admin/target echo 启动项目 nohup java -jar xr-admin.
文章目录 1. Spring Boot是什么2. 为什么学习Spring Boot2.1 从Spring官方来看2.2 从Spring Boot的优点来看2.3 从未来发展的趋势来看 3. 本课程能学到什么5. 本课程开发环境和插件第01课:Spring Boot开发环境搭建和项目启动1. jdk 的配置2. Spring Boot 工程的构建2.1 IDEA 快速构建2.2 官方构建2.3 maven配置2.4 编码配置3. Spring Boot 项目工程结构 4. 总结 第02课:Spring Boot返回Json数据及数据封装1. Spring Boot 默认对Json的处理1.1 创建 User 实体类1.2 创建Controller类1.3 测试不同数据类型返回的json1.4 jackson 中对null的处理 2. 使用阿里巴巴FastJson的设置2.1 jackson 和 fastJson 的对比2.2 fastJson依赖导入2.2 使用 fastJson 处理 null 3. 封装统一返回的数据结构3.1 定义统一的 json 结构3.2 修改 Controller 中的返回值类型及测试 4. 总结 第03课:Spring Boot使用slf4j进行日志记录1. slf4j 介绍2. application.yml 中对日志的配置3. logback.xml 配置文件解析3.
一 随便一个终端,进要用的虚拟环境:
conda activate 虚拟环境名 二 安装 ipykernel
conda install ipykernel 三 把当前环境配置到 ipykernel 里去
python -m ipykernel install --user --name 环境名 --display-name 显示的名字 四 手动运行exe,或代码运行 jupyter
jupyter notebook 五 new 新文件的时候可以选择环境
也可在打开已有文件后,进行切换。
六 从 jupyter 中删除虚拟环境 kernel:
打开jupyter 终端:
jupyter 终端 Terminal 中输入如下,显示当前存在的kernel的名字及其路径,其实上一张图里也能看出来 kernel 名叫啥。
jupyter kernelspec list 运行下面的语句删除 kernel:
jupyter kernelspec uninstall 名字
本文虽然命名为对比文档,但是对比意义不是特别强烈的内容仍不在少数——如三种3D技术的误差等部分——换言之,本文旨在通过对比的形式对三种3D技术的特点和特性进行总结。资料主要来自于网络,部分相关参考文献会附在文末。由于时间有限,有些图留有多重水印,如有侵权,请联系作者删除。作者学习时间为一周左右,浏览的文献及网络资料繁多,参考文献难免有缺漏。本文系作者学习总结,用于个人学习记录,读者若有见解,请不吝赐教。
目录
1、三种3D技术的概述
1.1 ToF
1.2 双目
1.3 结构光
2、三种3D技术的组成部分
2.1 ToF
2.2 双目的计算流程
2.3 结构光
3、三种3D技术的原理对比
3.1 ToF
3.1.1 dToF(脉冲调制)
3.1.2 iToF(连续波调制)
3.2 双目
3.3 结构光
3.3.1 时序编码
3.3.2 空间编码
3.3.2.1 德布鲁因序列 (De Bruijn) 序列
3.3.2.2 二维空间编码
4、三种3D技术的误差
4.1 ToF
4.1.1 系统性误差
4.1.2 非系统性误差
4.2 双目
4.3 结构光
5、三种3D技术的优缺点
5.1 ToF
5.1.1 直接测量法
5.1.2 间接测量法
5.2 双目
5.2.1 优点
5.2.2 缺点
5.3 结构光
5.3.1 优点
5.3.2 缺点
6、后处理
收到监控报警,某套Mysql5.7数据库主从延迟过高,且持续增长。经分析确认,应用负责人在手工补跑数据,提交了大事务,这种情况下不能也无法人工干预,只能静静等从库跟上来。另,主库3小时内就已经全部跑完补跑的数据,但从库却花了一整天才追上主库,mysql性能问题是值得诟病的。
一、案发情况 1、收到邮件报警
2、查看同步状态,确认同步线程还在线以及当前处理的binlog文件和位置
3、使用mysqlbinlog 翻译binlog事务,并联系应用责任人了解当下发生了啥业务。mysqlbinlog命令及结果如下
#!/bin/ksh #mysql用户执行 Master_Log_File=#Master_Log_File# Master_Log_Pos=#Master_Log_Pos# datadir=`mysql -usysdba -padmin123 -e "show variables like '%datadir%'"|grep datadir |awk '{print $2}'` tmp=${datadir%data/}"log/bin_log/" binlogfile=$tmp$Master_Log_File echo "binlog文件路径:"$binlogfile mysqlbinlog -vv --base64-output=decode-row $binlogfile --start-position=$Master_Log_Pos |head -n 100 4、电话沟通后,确认是应用责任人在补跑数据,目前等待就行了,从库会自动跟上主库。如果万一从库发生意外永远跟不上了,那就应急处理“用主库的备份文件恢复备库”
二、发生主从延迟时,常规的处理步骤 1、查看同步状态,确认同步线程还在工作;
2、查看binlog文件,确认当前同步线程正在处理的过程;
3、电话/邮件/微信尽快联系应用负责人,确认当前时段是否有批量/程序在进行数据库操作;
4、等待从库跟上主库,通常要好几个小时,大部分情况下自动跟上;
5、如果主从同步断掉,需具体问题具体分析;
js实现web页面扫描二维码(html5-qrcode)
以vue3项目使用为例
这种还是推荐IOS和安卓原生实现,做桥接文件调用
这种实现方式只支持localhost和https的浏览器网页版
而且经过测试兼容性也不是很好,具体参见官网
下面附了官网链接
1.下载依赖
npm install html5-qrcode 2.二次封装
<template> <div> <div class="readerDialog" v-show="dialogShow"> <div id="reader" width="600px"></div> </div> </div> </template> <script> // 调起摄像头扫描二维码 import { ref, reactive, toRefs, watch, getCurrentInstance } from 'vue'; import { Html5Qrcode } from 'html5-qrcode'; export default { name: 'Qrcode', props: [], emits: ['success'], setup (props, { emit }) { const params = reactive({ dialogShow: false, codeUrl: '', cameraId: '', showText: '', devices: [], getCamerasText: '', html5QrCode: null }); // 外部调用此方法打开 const open = () => { params.
前言 嗨嗨,大家好,虽然换了个名字但是我还是小圆 ~
今天再发一次这篇文章吧
还是有很多小伙伴刚开始接触python这门语言,一些软件安装或者环境解释器啥的没配置好,导致一拿到代码开始运行直接报错或者运行没结果…
在安装模块时成功了,但是在pycharm导入模块的时候报错了,或者运行没有结果,基本上都是这个问题
今天来给大家分享一下python新手必须学会的技巧 :pycharm中配置python解释器
1.打开设置 软件安装包可以点击文末名片领取
依次点击file - settings 打开设置
2. 点击到project >> Python interpreter 依次点击 project:Pythonproject → Python interpreter
3. 选择环境 依次选择,点击设置。
左边
第一个是选择Python
第二个是选择anaconda
右边
第一个是从pycharm里面下载模块
第二个是选择你安装的环境,从它里面调用已经安装的模块。
注:如果是安装的anaconda
都是类似的,就不过多介绍了
4. 确定之后等待加载就行了 点击应用,点击OK即可。
最后 今天的分享到这里就结束了 ~
对文章有问题的,或者有其他关于python的问题,可以点击文末名片进行学习交流哦
小程序跳转到H5页面 小程序跳转H5页面是通过web-view组件来实现的,web-view是一个可以用来承载网页的容器,会自动铺满整个小程序页面,也就是说h5页面的跳转是在小程序的环境下打开的。需要在小程序里建立一个空白页,放置webview用来展示H5页面。
限制条件:
H5页面所在的域名必须为https由于web-view组件是一个全屏组件,不能和其它小程序组件合用,因此需要独立占据一个页面,由A跳到B,由B跳到h5页面小程序能够跳转的h5页面的域名必须在业务域名中进行注册小程序账号必须是企业账号,个人和海外账号暂不支持,只有企业账号才能看到业务域名入口设置网页授权域名,H5页面关联的服务号中去进行设置,在公众号设置添加好需要跳转的域名 H5页面跳转到小程序 1、h5页面在小程序环境下打开的情况下 限制条件:
当前的h5页面必须是在小程序的环境下打开的页面,才能回跳小程序的指定页面。其它限制条件同小程序跳h5页面的要求 注意点:无论是小程序跳转H5页面还是跳转回来都是可以传递参数的
2、h5页面不在小程序环境下打开的情况下 微信新增小程序跳转按钮:wx-open-launch-weapp(具体用法可参考 官方文档 )。用于页面中提供一个可跳转指定小程序的按钮。使用此标签后,用户需在网页内点击标签按钮方可跳转小程序.
通过微信公众号后台配置菜单,子菜单内容选择小程序公众号推文里添加素材点击小程序,弹框如下图(在弹框中可以选择展示的方式:文字、图片、小程序卡片、小程序码当公众号和小程序已关联(在公众号的菜单中有绑定小程序的入口)
3.1小程序所在的菜单会出现在公众号的介绍页(如果是在二级菜单中,所对应的只出现相应一级的该小程序入口)
4.模板消息(直接在模板消息接口中配置)
4.1该小程序appid必须与发模板消息的公众号是绑定关联关系,点击模板消息跳转小程序,可支持跳转到小程序的具体页面,支持带参数,(示例index?foo=bar)
5.H5页面中嵌入小程序码
6.安卓手机debug调试( 打开信息里面的调试功能 ) 分类信息平台外链
判断摄像头兼容问题 <video id="video"></video>
// 定义方法访问用户媒体设备的兼容方法
function getUserMedia(constraints, success, error) {
if (navigator.mediaDevices.getUserMedia) {
console.log("最新的标准API");
navigator.mediaDevices.getUserMedia(constraints).then(success).catch(error);
} else if (navigator.webkitGetUserMedia) {
console.log("webkit核心浏览器");
navigator.webkitGetUserMedia(constraints, success, error)
} else if (navigator.mozGetUserMedia) {
console.log("firfox浏览器");
navigator.mozGetUserMedia(constraints, success, error);
} else if (navigator.getUserMedia) {
console.log("旧版API");
navigator.getUserMedia(constraints, success, error);
}
}
获取videoDOM元素,并且让video承接画面(注意:每次调用都需要重新获取权限) // 获取元素节点
let video = document.getElementById("video");
let mode = "user" // 设置使用environment后置摄像头,user为前置摄像头
// 封装开启摄像头方法
function getCamera() {
// 判断用户的兼容,并作出对应的处理
if (navigator.mediaDevices.getUserMedia || navigator.getUserMedia || navigator.
概述 这篇是php7源码系统攻略的第三篇,是对之前的知识和补充,踩了很多坑,鏖战了数天才完全通关,下面带你安装常用的 redis 、yaf 、swoole 、 扩展,以及trie_filter、xdiff和grpc 、protobuf 。
php的扩展可分为3类,原生自带、pecl官网、和老旧的疑难杂症包。
原生自带 比如sockets 、pdo-mysql 、mysqli 这种扩展属于原生自带,再编译的时候非常方便,如果你拿不定主意,可以使用./configure --help | grep sockets 命令去寻求帮助,需要主意的是,opcache已经集成在php7+的版本里了。
#--with-fpm-user=USER #--with-fpm-group=GRP ./configure --prefix=/usr/local/php7 \ --with-php-config=/usr/local/php7/bin/php-config \ --enable-fpm \ --enable-debug \ --enable-zip \ --enable-sockets \ --with-pdo-mysql \ --with-mysqli \ --with-pear \ --with-curl \ --with-openssl && make && make install 生产环境要指定管理组和用户权限,--prefix指定的是php7的安装目录,--with-php-config 这个参数指定的目录特别关键,是后期安装扩展的灵魂。
pecl官网 去pecl官网,下载指定版本的扩展,使用命令wget https://pecl.php.net/get/yaf-3.0.7.tgz,太老旧的版本可能已经下线了,最好去官网去查询一下。
下面我以swoole-4.2.11为例子,来演示一下第二类的扩展,redis、MongoDB、yaf 都是同样的道理。
1.下载安装包,解压 wget https://pecl.php.net/get/swoole-4.2.11.tgz && \ tar zxf swoole-4.2.11.tgz 这里需要主意,一定要切换到解压的目录,指定命令phpize
2.下载安装包,解压 安装时--with-php-config这个参数要指定给你安装php时的目录这个是不能错的,不然编译的时候会找不到对应的目录。
./configure --with-php-config=/usr/local/php7/bin/php-config 3.
场景:
已经提交了代码,但在此之前又拉了相同的分支,需要再提交一份
将同一份修改提交到两个分支
实现方案:
1.Version Control -> Repository 找到提交记录-> 右键create Patch,将patch文件保存在本地
2.切换另一个分支
3.导入patch文件 VCS->Apply patch,选中刚才的patch文件,导入即可,接下来你应该会了。(如果你的idea没有vcs 可以点击 Help Find Action 搜索Apply patch)
补充一下:
Local Changes中也可以将未提交的代码备份成patch文件
目录 Cadence Allegro 17.4学习记录绪论第一,先来说说Cadence Allegro 17.4的原因第二,简单介绍这个EDA软件Cadence Allegro 17.4第三,学习规划1、Cadence Allegro 17.4软件安装2、学习资料3、学习方法4、学习顺序 Cadence Allegro 17.4学习记录绪论 第一,先来说说Cadence Allegro 17.4的原因 本人一直以来都是使用AD的 ,因为大学时候第一接触的就是AD,出来工作之后才知道有,Cadence Allegro,PADS等EDA软件。经过了这么多年使用AD这个软件,发现是挺好用的。现在学习Cadence Allegro这个软件,主要是为了可以更近一步,提高工资,和本人对这个EDA软件挺感兴趣的。
所以决定一边学习,一边记录。希望一个月的时间,可以熟练使用这个EDA软件,为我下次跳槽就业提供帮助。
第二,简单介绍这个EDA软件Cadence Allegro 17.4 Cadence Allegro 有三个版本,16.6,17.2,17.4。
现在主要学习最新的版本17.4.
原理图设计:OrCAD
PCB设计:Allegro
主要用到的就下面三个图片软件:
PCB Editor 17.4 是用来画PCB和元器件封装的;
Padstack Editor 17.4 是用来画元器件焊盘的;
Capture CIS 17.4 是用来画原理图和原理图库的。
其实Cadence还有很多功能,现在计划先学习以上内容,后面熟悉了这个软件,还可以继续学习放仿真等功能。
现在对于AD软件已经很熟悉了,所以对比起来学习,有很多相似的地方,一定要坚持下去学习。
学习过程中,一定要记录,笔记。
好记性,不如烂笔头!!!!
相信自己,可以的。
第三,学习规划 1、Cadence Allegro 17.4软件安装 可以参考吴川斌大神的方法,非常的省时省力,这是他的博客链接: {吴川斌的博客}
在他的博客里面有软件和安装方法,说的很清楚!
2、学习资料 书籍,《Cadence Allegro17.4 电子设计速成实战宝典》这是书籍刚发布的第一时间我就买了,凡亿教育出品的书籍视频资料,链接: Cadence Allegro17.4 电子设计速成实战宝典 配套素材下载网上看看博客,论坛,特别是B站上有很多好的学习视频(我经常在上面学习)等。 3、学习方法 坚持练习坚持练习坚持练习一遍不会,就练习100遍 4、学习顺序 熟悉软件的操作,不停的多次练习,可以看书和视频一起学习软件熟悉以后,找一块简单的2层板上手,有时间的可以多练习几次两层板简单的2层板上手后,就可以看书学习4层板往后可以学习6-8层
注意,一定要把基础打好,把笔记做好,总结 最后,希望自己可以坚持学习下去,把每一天的笔记做起来。就不会忘了
Matlab基础绘图整理 一张图绘制多个子图在图片文本中添加希腊字母和特殊字符其他常用函数限制坐标轴范围添加坐标轴说明添加图例修改线条类型、标记修改线条粗细 一张图绘制多个子图 主要命令:
figure(); %第几张图
subplot(x,y,n); % subplot(x,y,n)x表示显示的行数,y表示列数,n表示第几幅图片
示例:
figure(1); %第一张图 subplot(3,1,1); %子图在图1中排列是三行一列,现在画第一张子图 plot(x1,y1); subplot(3,1,2); %子图在图1中排列是三行一列,现在画第二张子图 plot(x2,y2); subplot(3,1,3); %子图在图1中排列是三行一列,现在画第三张子图 plot(x3,y3); 在图片文本中添加希腊字母和特殊字符 Matlab支持TeX 标记和LaTex标记。使用LaTex标记时,需要将Interpreter 属性设置为 ‘latex’
参考matlab官方网页:图文本中的希腊字母和特殊字符
其他常用函数 限制坐标轴范围 xlim([-1 1]); ylim([-1 1]); 添加坐标轴说明 xlabel('T(s)'); ylabel('\phi(rad)'); 添加图例 legend('\phi_d', '\phi_{1}', '\phi_{2}'); 修改线条类型、标记 修改线条粗细 plot画图默认粗细为0.5
plot(time, x, 'LineWidth', 1) //修改线条粗细为1
开发时总是会报错提示某端口已被占用,我们要手动关闭占用该端口的进程:
1.打开终端
2.输入netstat -nao | findstr XXXX (xxxx是被占用的端口号),查看占用该端口的pid
3.输入tasklist | findstr xxxx (xxxx是查寻到的pid),用于通过pid查询进程名
4.taskkill /f /t /im java.exe(用你查到的进程名替代java.exe)
或者taskkill /pid xxxx/F(xxxx为第二步查到的pid)
python3.6安装opencv遇到报错。如下所示:
pip install opencv-python报错。
Please check the install target is valid and see CMake's output for more information. ---------------------------------------- ERROR: Failed building wheel for opencv-python Failed to build opencv-python ERROR: Could not build wheels for opencv-python, which is required to install pyproject.toml-based projects 原因是使用pip install opencv-python命令安装的是最新版本,python3.6不支持。所以找一个python3.6支持的版本。如opencv-python==4.3.0.38。
pip install -i https://pypi.douban.com/simple/ pip install opencv-python==4.3.0.38
安卓7以上的安卓模拟器(包括雷电9等安卓9的模拟器),win11安卓子系统的请去用对应的专门的工具,本文使用的是逍遥模拟器
工具准备: 逍遥模拟器:自行官网下载工作室版本
apk:链接:https://pan.baidu.com/s/1OLKFFz50VltEm6ZiiB8ZAQ 提取码:5z8w
首先要开启逍遥模拟器的root权限,在重启模拟器
这里我已经安装成功,初始这是没有东西的,这里点击安装 点击下一步,进去到方式
选择系统分区,然后点击开始
安装成功,然后重启模拟器,不能点击下面的重启,直接重启模拟器
点击确定就可以,之后就可以使用了
之后再打开就可以看到自己安装后的版本了
之前项目上出现过这样一个bug,就是明明两个数都是一样的但是就是莫名其妙的报出两个数不相等,导致流程无法继续下去
然后我把所有数据导出来,进行一对一比对,只是一个很耗时的过程,最终让我找到
因为js计算过后会出现计算精度丢失的问题 找到问题所在就好说了,然后就开始解决这个让我为难了好长时间的问题
废话不多说直接上代码
/** * 解决两个数相加精度丢失问题 * @param a * @param b * @returns {Number} */ function floatAdd(a, b) { var c, d, e; if(undefined==a||null==a||""==a||isNaN(a)){a=0;} if(undefined==b||null==b||""==b||isNaN(b)){b=0;} try { c = a.toString().split(".")[1].length; } catch (f) { c = 0; } try { d = b.toString().split(".")[1].length; } catch (f) { d = 0; } e = Math.pow(10, Math.max(c, d)); return (floatMul(a, e) + floatMul(b, e)) / e; } /** * 解决两个数相减精度丢失问题 * @param a * @param b * @returns {Number} */ function floatSub(a, b) { var c, d, e; if(undefined==a||null==a||"
声明式事物管理虽然十分方便,但是也有失效的情形: 1.@Transactional作用在非public方法上 Spring的事物管理只支持使用public声明的方法,即使是在同一个包或者同一个类中的方法事务管理也会失效
package com.ffyc.springdemo.service; import com.ffyc.springdemo.dao.AdminDao; import com.ffyc.springdemo.model.Admin; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class AdminService { @Autowired AdminDao adminDao; @Transactional(rollbackFor = Exception.class) void zhuanZhang(){ //@Transactional作用在非public方法上 adminDao.sub(); System.out.println(10/0); adminDao.add(); }adminDao.update(); } } 2.所处方法中的异常被try catch捕获处理 若是作用方法中含有try catch语句并且捕获处理了方法中的异常,这样Spring就会无法找到异常从而导致事务管理失效
package com.ffyc.springdemo.service; import com.ffyc.springdemo.dao.AdminDao; import com.ffyc.springdemo.model.Admin; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.io.UnsupportedEncodingException; @Service @Transactional(rollbackFor = Exception.class) public class AdminService { @Autowired AdminDao adminDao; public void zhuanZhang(){ adminDao.
无返回值:void
有返回值:(基本数据类型)byte、short、int、long、float、double、boolean、char
(引用数据类型)String、类、接口、数组
YOLOv5算法原理与网络结构
1.1 YOLOv5算法
YOLOv5算法共有4种网络结构,分别是YOLOv5s、YOLOv5m、YOLOv5l和YOLOv5x,这四种网络结构在宽度和深度上不同,原理上基本一样,接下来以 YOLOv5s 为例介绍 YOLOv5网络结构。
图1 YOLOv5网络结构图
YOLOv5s的网络结构如图1所示,该结构分为四个部分输入端、Backbone(主干网络)、Neck网络和Prediction(输出端)。
各部分具有的主要功能结构如下:
输入端:Mosaic数据增强、自适应锚框计算,以及自适应图片缩放。
主干网络:Focus结构、CSP结构。
Neck网络:FPN+PAN结构。
输出端:GIOU_Loss。
1.1.1 输入端
(1) Mosaic数据增强
输入端使用的数据增强方式是Mosaic方式,对数据集合采取随机缩放、随机剪裁、随机排布。
主要有两个优点:
第一,提高了数据集的复杂度:对多张图片,进行随机的缩放以及剪裁,之后再随机分布,进行拼接,使数据集得到极大地丰富,特别是进行随机缩放操作,可以增加许多小目标,训练得到的模型,鲁棒性会更好;
第二,减少 GPU 内存使用:使得 Mini-batch 也就是一个批次从数据集读取进行训练的图片张数,不需要设置的很大,因此,训练时使用一个GPU也能达到比较好的训练效果。
(2) 自适应锚框计算
YOLO系列检测算法中,针对不同目标,都会初始设定好默认长宽的锚框,进行训练时,在初始设定好的锚框基础上,输出一个预测框,将标注的真实框和预测框做对比,并且计算它们的差距,之后再反向更新,迭代网络结构中的参数。在 YOLOv3、YOLOv4中,训练不同的数据集时,计算初始锚框的值是通过单独的程序运行的,但在YOLOv5中将此功能嵌入到算法结构中,每次训练时,自适应的计算不同训练集中的最佳锚框值。
(3) 自适应图片缩放
在目标检测算法中,针对数据集中图片长宽一般不相同的问题,经常是将原始图片先缩放成一个统一的标准尺寸,全部处理后,再送入检测网络中,将长宽800*600的图像进行缩放,使用黑色背景来填充,填充后会出现大区域的黑边。在项目实际使用时,图片的长宽比几乎都不相同,因此缩放填充后,黑边大小都不同,如果填充的比较多,则存在信息冗余,影响网络推理速度。
因此,在最新的 YOLOv5 算法中进行了改进,这也是 YOLOv5算法推理速度能够变快的一个方面。该算法对原始图像进行缩放操作时,可以根据图片尺寸,自适应的添加最少黑边,图像的黑边明显变少了,这样处理后,在推理时,计算量也会得到减少,从而使得网络的目标检测速度会得到提高。
通过这种自适应缩放的优化改进,YOLOv5的推理速度得到了提升,把长宽 800*600 的图像缩放填充为 416*416 尺寸的图像为例,介绍自适应图片缩放的三步:
第一步,计算长宽的缩放比例,将原始图像尺寸 800*600,分别除以缩放后的尺寸 416*416,可以计算出长边的缩放系数为0.52,宽边的缩放系数为0.69。
第二步,选择较小的缩放系数 0.52,将原始图像的长宽都乘以0.52,计算出此时的长边是416,宽边是312。
第三步,计算需要填充的黑色区域,宽边312和需要缩放到的 416相差104,差值除以 2,就得到了两端需要填充的黑色区域的高度。
1.1.2 主干网络
(1) Focus结构
Focus结构中关键的是切片操作,切片操作演示过程,将4×4×3的特征图经过切片处理,变成2×2×12的特征图。将608×608×3 的三通道图像输进 Focus 结构,经过切片操作,先变成304×304×12 的特征图,之后,经过使用 32 个卷积核的卷积操作,最终变成 304×304×32 的特征图。需要注意的是,YOLOv5s网络结构中的 Focus 结构使用32个卷积核,进行卷积操作,而其他三种网络结构,使用的卷积核数量有所增加。
(2) CSP结构
YOLOv5中有两种结构的CSP,CSP1_X结构在Backbone主干网络中,另一种CSP2_X结构在Neck中。对于Backbone的主
Docker容器重量级监控 CIG 一、概述二、安装三、测试四、grafana 配置1、配置数据源2、配置面板panel3、进行数据的输入展示 一、概述 原有的查看Docker实例的状态命令
docker stats 可以查看实力的 CPU占用,内存,网络IO以及阻塞IO的情况
但是这个信息是实时的,我们查看不了一段时间的信息,以及无对其进行预警,所以就有了 CIG 监控
CAdvisor监控收集+InfluxDB存储数据+Granfana展示图表
二、安装 新建目录cig
mkdir -p cig 编写 docker-compose.yml
version: '3.1' volumes: grafana_data: {} services: influxdb: image: tutum/influxdb:0.9 restart: always environment: - PRE_CREATE_DB=cadvisor ports: - "8083:8083" - "8086:8086" volumes: - ./data/influxdb:/data cadvisor: image: google/cadvisor links: - influxdb:influxsrv command: - storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxsrv:8086 restart: always ports: - "8080:8080" volumes: - /:/rootfs:ro - /var/run:/var/run:rw - /sys:/sys:ro - /var/lib/docker/:/var/lib/docker:ro grafana: user: "
1、为什么要用Multi-Scale的ViT?
patch大小会影响ViT的准确性和复杂性;具有细粒度的patch大小,ViT性能更好,但会导致更高的FLOPs和显存消耗。例如,patch大小为16的ViT比patch大小为32的ViT好6%,但前者需要更多4×的FLOPs。
受此启发,作者提出的方法是利用来自更细粒度的patch大小的优点,同时平衡复杂性。更具体地说,作者首先引入了一个双分支ViT,其中每个分支处理不同patch大小的特征,然后采用一个简单而有效的模块来融合分支之间的信息。
此图为Cross-Attention Multi-Scale Vision Transformer,即CrossViT的网络结构。模型主要由K个多尺度Transformer编码器组成,其中每个编码器由两个分支组成:
L-Branch :
大分支利用粗粒度的patch大小(Pl),更多的Transformer编码器和更大的embedding维度。
S-Branch :
小分支对细粒度的patch大小(Ps))进行操作,具有更少的编码器和更小的embedding维度。
两个分支的输出特征在Cross-Attention中融合L次,利用末端的两个分支对CLS token进行预测。对于两个分支的每个token,作者还在多尺度Transformer编码器之前添加了一个可学习的位置embedding,以学习位置信息。
2、多尺度特征融合:
有效的特征融合是学习多尺度特征表示的关键。在本文中作者探索了四种策略:
(a)All-Attention Fusion是简单地concat来自两个分支的所有token,而不考虑每个token的属性。因为所有的token都是通过自注意模块计算的,其时间复杂度也是跟输入特征大小呈二次关系。
(b)Class Token Fusion只将 CLS Token 融合,因为它可以被视为一个分支的全局表示。
(c)Pairwise Fusion成对融合,根据它们的空间位置将它们合并。其中相对应空间位置的 Token 融合在一起,CLS Token 则分别融合。但是,这两个分支处理不同大小的patch,因此具有不同数量的patch token。因此作者首先执行插值操作来对齐空间大小,然后以成对的方式融合两个分支的patch token。
(d)Cross-attentions Fusion交叉注意力,将来自一个分支的 CLS Token 和来自另一个分支的 Patch Token 融合在一起。为了更有效地融合多尺度特征,作者首先利用每个分支的CLS token作为代理,在另一个分支的patch token之间交换信息,然后将其投影到自己的分支。
由于CLS token已经学习了自己分支中所有patch token之间的抽象信息,因此与另一个分支中的patch token的交互有助于融合不同尺度的信息。与其他分支token融合后,CLS token在下一层Transformer编码器上再次与自己的patch token交互,在这一步中,它又能够将来自另一个分支的学习信息传递给自己的patch token,以丰富每个patch token的表示。
文章目录 浅谈设计模式1.设计模式是什么2.为什么要学设计模式3.SOLID设计原则4.设计模式的核心思想—封装变化5.23种常见设计模式 创建型一、工厂模式(Factory Pattern)简单工厂1.解决的问题:2.构造器3.使用步骤4.举例 抽象工厂 (Abstract Factory Pattern)举例 二、单例模式(Singleton Pattern)举例Vuex:单例模式的典型应用1. 概念2. 确保Store的唯一性 举例2 三、原型模式(Prototype Pattern)原型范式原型深拷贝 结构型一、装饰器模式(Decorator Pattern)举例 二、适配器模式(Adapter Pattern)三、代理模式(Proxy Pattern)应用1. 事件代理2. 图片预加载3. 缓存代理 举例 行为型一、策略模式(Strategy Pattern)举例 二、状态模式(State Pattern)举例 三、观察者模式(Observer Pattern)举例 四、迭代器模式(Iterator Pattern) 浅谈设计模式 1.设计模式是什么 先看看必应搜索出来的词条:
我个人认为设计模式就是前人在编程中经过不断的试错和踩坑所总结出来的方法和套路
2.为什么要学设计模式 先看看必应搜索出来的词条:
我的理由:
为了写出健壮性代码面试会考,而且常考 一个软件工程师驾驭技术的能力总共分为三个层次:
能用健壮的代码去解决具体的问题能用抽象的思维去应对复杂的系统能用工程化的思想去规划更大规模的业务 第一点是面对所有程序员,后两点更多的是面向团队中的负责架构的人员
3.SOLID设计原则 单一功能原则(Single Responsibility Principle)开放封闭原则(Opened Closed Principle)里式替换原则(Liskov Substitution Principle)接口隔离原则(Interface Segregation Principle)依赖反转原则(Dependency Inversion Principle) 4.设计模式的核心思想—封装变化 如果一个软件不需要进行迭代和版本更替,那我们再开发过程中只需要完成其功能就行,完全不用去考虑其可维护性和可拓展性。
但在通常开发中我们开发了一个软件,随着时间线的拉长,它会变得越来越复杂,体量也会越来越大。而我们所需要做的就是将他的变化造成的影响最小化——将变和不变分离,确保在维持软件原有功能情况下,完成新的功能增加和产品迭代,这个过程就叫封装变化
5.23种常见设计模式 这里我们并不需要把所有的设计模式都学透,从强语言迁移过来的设计模式并不是全部都是用于现在的前端,暂时只需要把几个重点的弄明白就行
创建型 一、工厂模式(Factory Pattern) 工厂模式其实就是将创建对象的过程单独封装
简单工厂 有构造函数的地方,我们就应该想到简单工厂
1.解决的问题: 将实例化的操作和使用对象的操作分开,让使用者不用知道具体的参数就可以实例化出所需要的产品类,避免了在客户端代码中显式指定,实现了解耦(使用者可以直接消费产品而不需要知道其生产细节)
2.构造器 通常创建对象:
# seq seq:单词sequence序列的缩写,功能是输出序列化的一串整数。 # 输出 1-5,分隔符是换行符 seq 5 # 输出 2-8,分隔符是空格 seq -s ' ' 2 8 # 输出 1-10 的奇数 seq -s ' ' 1 2 10 # 使用-f来指定输出格式,%后面表示的是数字的位数,默认为%g,示例中的%2g表示两位输出,不足两位默认补空格 seq -f "%2g" -s ' ' 8 12 seq -f "%04g" -s ' ' 8 12 # 前面加自定义字符串 seq -f "sss%04g" -s ' ' 8 12 # 保留小数点后3位 seq -f "%.3f" 9 11 # -w 输出数字等宽 seq -w 1 2 100 # paste 从在命令行上指定的文件中读取输入。用于合并文件的列。 # paste 指令会把每个文件以列对列的方式,一列列地加以合并。 # 将两个文件按照行合并,同时指定间隔符 paste -d , test.
目录 前言实现代码 前言 代码分享 经典贪吃蛇小游戏,使用C语言实现。
实现代码 #include <stdio.h> #include <stdlib.h> #include <time.h> #include <Windows.h> #include <conio.h> #include <math.h> #define MAP_SIZE 40 /* 定义上下左右四个方向的命令 1上 2下 3左 4右 */ #define UP 1 #define LEFT 2 #define DOWN 3 #define RIGHT 4 /* 定义地图一张 g_map 10*10 蛇的长度 g_snake_legnth 定义命令 g_cmd:移动的命令 定义食物的位置 g_food_x 和 g_food_y 定义贪吃蛇头部位置 */ int g_map[MAP_SIZE][MAP_SIZE] = {0}; int g_snake_legnth; int g_cmd; int g_food_x,g_food_y; int g_head_x,g_head_y; int g_end_x,g_end_y; /* 生成随机数 食物的位置 食物被吃掉之后重新生成 设置随机数种子 生成0-MAP_SIZE-1的随机数 */ void Rand_food_addr() { do{ srand((unsigned)time(NULL)); g_food_x = rand()%(MAP_SIZE-2)+1; g_food_y = rand()%(MAP_SIZE-2)+1; }while(g_map[g_food_x][g_food_y]!
SPDK从功能角度将各个独立的部分划分为“子系统“。例如对各种后端存储的访问属于bdev子系统,又例如对虚拟机呈现各种设备属于vhost子系统。不同场景下,各种工具可以通过组合不同的子系统来实现各种不同的功能。例如虚拟化场景下,vhost主要集成了bdev、vhost、scsi等子系统。这些子系统存在一定依赖关系,例如vhost子系统依赖bdev,这就需要将被依赖的子系统先初始化完成,才能执行其它子系统的初始化。
本篇博文我们先整体介绍一下SPDK子系统的初始化流程,然后再深入分析一下bdev子系统。vhost子系统我们将在独立的博文中展开分析。
SPDK子系统 通过前文的分析,我们知道主线程在执行_spdk_reactor_run时,首先处理的事件便是verify事件,该事件处理函数为spdk_subsystem_verify:
spdk/lib/event/subsystem.c:
static void
spdk_subsystem_verify(void *arg1, void *arg2)
{
struct spdk_subsystem_depend *dep;
/* 检查当前应用中所有需要的子系统及其依赖系统是否均已成功注册 */
/* Verify that all dependency name and depends_on subsystems are registered */
TAILQ_FOREACH(dep, &g_subsystems_deps, tailq) {
if (!spdk_subsystem_find(&g_subsystems, dep->name)) {
SPDK_ERRLOG("subsystem %s is missing\n", dep->name);
spdk_app_stop(-1);
return;
}
if (!spdk_subsystem_find(&g_subsystems, dep->depends_on)) {
SPDK_ERRLOG("subsystem %s dependency %s is missing\n",
dep->name, dep->depends_on);
spdk_app_stop(-1);
return;
}
}
/* 按依赖关系对所有子系统进行排序 */
subsystem_sort();
A2B总线是高级可编程的,可以处理许多用例。A2B系统很容易配置,基于系统、节点和外设的知识。准确的系统配置可以通过从每个从属服务器单独收集信息来获得。例如,相同的A2B模块可以由不同的供应商提供,每个模块都有独特的寄存器编程要求。一个模块可以使用TDM4作为音频接口,而另一个模块使用TDM8。一个模块可以提供两个上游通道,而另一个模块可以提供三个上游通道,所有这些通道的主机事先都不知道连接了多少节点。
注意:确保寄存器编程的结果是有效的系统配置。
Analog Devices提供免费的SigmaStudioTM (http://www.analog.com/SigmaStudio)工具,具有直观的图形用户界面来构建、配置和设置A2B总线。这些工具还为嵌入式软件生成驱动程序代码。
Linux和QNX软件驱动程序也可根据要求提供。
1、I2C端口编程概念 上位机收发寄存器由A2B主机通过I2C端口使用I2C寄存器直接访问编程实现。从节点上的I2C连接控制器也可以以这种方式对从节点启用的收发器寄存器进行编程;然而,A2B从收发器寄存器通常是由A2B主机通过主收发器在A2B总线上使用远程从收发器I2C寄存器访问来远程编程的。此外,如果从端收发器与从节点上的I2C从端设备进行了本地连接,那么A2B主机也可以通过A2B总线使用远程外设I2C远程访问已连接的I2C从端设备。I2C访问编程顺序图是对收发机寄存器编程和访问I2C外围设备从节点所需要的编程顺序的图形表示。
I2C接口编程顺序
在I2C接入编程顺序图中:
1、I2C ADDR为主收发器I2C设备地址:
1)、直接I2C寄存器使用BASE_ADDR (I2C ADDR: BASE)访问主收发器。
2)、远程从I2C寄存器访问从收发器,远程外围I2C访问I2C从节点上连接的外围设
备使用BUS_ADDR(I2C ADDR:BUS)。
注意:有关BASE_ADDR和BUS_ADDR的更多详细信息,请参阅收发器I2C访问章
节。
2、NODEADR是主收发器A2B_NODEADR寄存器:
1)、NODE是A2B_NODEADR.NODE字段。
2)、 PERI 是A2B_NODEADR.PERI位。
3、CHIP是A2B_CHIP寄存器:
1)、黑色文本表示A2B_CHIP寄存器本身。
2)、蓝色文本表示A2B_CHIP寄存器的值。
1.1、直接I2C寄存器访问 无论收发器配置为master还是slave, I2C端口都可以直接访问收发器寄存器空间:
1、在主节点上,A2B主机使用该方法直接访问主收发器寄存器空间。
2、在从节点上,本地连接的I2C主机使用该方法直接访问从收发器寄存器空间。
如图《I2C访问编程顺序图》中的I2C主收发器寄存器访问部分所示,主收发器寄存器访问要求从主机传输的I2C数据包括主收发器I2C设备地址(I2C ADDR: BASE = BASE_ADDR),然后是寄存器地址(ADDR),最后是与主收发器寄存器相关联的数据(R/W data)。详细信息请参见收发器I2C访问章节。
注意:主I2C访问序列对于从节点上直接访问从收发器寄存器空间的I2C连接主机是相同的。
1.2、远程从I2C寄存器访问 虽然从节点上本地连接的I2C主机可以直接通过I2C端口对从收发器寄存器进行编程,但A2B系统通常由主节点上的A2B主机完全配置。如图《I2C接入编程顺序图》中的Slave 0 I2C接入部分所示,A2B主机首先直接配置主收发器,然后通过A2B总线远程I2C接入对特定的Slave收发器进行编程。A2B主机必须使用以下编程顺序从主节点通过A2B总线远程访问A2B从收发器寄存器空间。
1、使用直接I2C寄存器访问来设置主收发器A2B_NODEADR。NODE字段表示要访问的从节点ID。确保a2b_noder。在这个写操作中,PERI位设置为0,以便后续总线访问的目标是指定的从属收发器寄存器空间,而不是连接到指定从属器的I2C外围设备。
附加信息:设置 A2B_NODEADR.NODE字段为0意味着后续总线访问将以从节点0为目标。如果该字段设置为1,则后续总线访问将以从节点1为目标。如果意图将写操作广播到所有发现的节点(主节点和从节点),请确保还设置了广播位(A2B_NODEADR.BRCST)。
2、要访问从收发器寄存器,主机的I2C传输包括主收发器的总线地址(I2C ADDR: BUS = BUS_ADDR),然后是从收发器寄存器地址(ADDR),最后是与从收发器寄存器相关联的数据(data)。详细信息请参见收发器I2C访问章节。
1.3、远程外围I2C访问 《I2C接入编程顺序》中的“从机1 I2C外设接入”部分,以A2B总线为例,说明A2B主机通过远程外设I2C接入方式,访问与从机I2C端口相连的外设的顺序。A2B主机必须按照以下编程顺序通过A2B总线访问A2B从节点上的I2C外设(例如,麦克风或DAC)。
1、使用直接I2C寄存器访问写访问来设置主收发器A2B_NODEADR.NODE字段表示连接到要访问的外围设备的从节点ID。确保A2B_NODEADR.PERI位在写入过程中被清除,以便随后的总线访问是到目标接收器的寄存器空间,而不是到从外设本身。
附加信息:在这个写操作中将A2B_NODEADR.NODE.NODE字段设置为1,以便后续总线访问目标从节点1。如果意图将外围设备写入广播到所有发现的节点(主节点和从节点),请确保还设置A2B_NODEADR.BRCST位。如果目标从收发器中的A2B_CHIP寄存器已经设置为预期外围访问的I2C地址,那么使用A2B_NODEADR执行这个写操作。PERI位设置(而不是清除),并直接进入最后一步。
2、使用远程从I2C寄存器访问用与从机相连的外围设备的I2C设备地址对所需的从机收发器的A2B_CHIP寄存器进行写访问。
3、使用直接I2C寄存器访问写访问来设置主收发器A2B_NODEADR.PERI位(同时维护A2B_NODEADR.NODE字段的内容。),以便后续的BUS_ADDR访问到所需的从节点I2C外围设备。
4、要访问从节点外围设备,来自主机的I2C传输必须包含主收发器的BUS_ADDR (I2C ADDR: BUS),然后是从收发器用来访问从节点I2C外围设备的地址(ADDR),最后是与地址相关的数据(Data)。
2、系统启动和发现 A2B系统由A2B主机组成。正确地建立电源之后,必须发现系统中的每个节点并按顺序进行配置,从主节点开始。
2.1、复位和操作状态 PLL锁的丢失将重置除A2B_BMMCFG和A2B_CONTROL.MSTR之外的所有寄存器信息。收发器状态图显示了收发器状态信息,在启动和运行一个完整的A2B系统时,了解这些信息非常重要。
收发器状态机
计算机网络概述(入门篇) 目录 计算机网络概述(入门篇)一、网络基础1.什么是网络?2.什么是通信?3.什么是网络通信?4.网络的划分 二、分层思想层次划分的方法 三、OSI七层参考模型四、TCP/IP模型TCP和UDP 五、数据封装过程六、数据解封装过程补充知识 一、网络基础 1.什么是网络? 网络的定义︰网络指用一个巨大的虚拟画面,把所有东西连接起来,也可以作为动词使用。在计算机领域中,网络就是用物理链路将各个孤立的工作站或主机相连在一起,组成数据链路,从而达到资源共享和通信的目的。凡将地理位置不同,并具有独立功能的多个计算机系统通过通信设备和线路而连接起来,且以功能完善的网络软件(网络协议、信息交换方式及网络操作系统等)实现网络资源共享的系统,可称为计算机网络。
2.什么是通信? 通信,是指人与人、人与物、物与物之间通过某种媒介和行为进行的信息传递与交流。
3.什么是网络通信? 网络通信,是指终端设备之间通过计算机网络进行的通信。
4.网络的划分 按照网络的作用范围:广域网(WAN)、城域网(MAN)、局域网(LAN)。
二、分层思想 在计算机科学中,抽象和分层是我们的强力武器,我们可以利用它们让我们的计算机系统更加强大,完成各种”不可能“。
从操作系统,软件设计,网络协议栈等等,都体现了分层思想。
分层中,每个层次负责不同的功能。一般来讲,下层为上层提供服务,上层不要知道下层的具体实现细节,只需使用下层提供的服务。而层与层之间联系的桥梁就是“接口”(Interface)。OS调用硬件提供的api,软件调用OS提供的api,而用户调用软件提供的api。
举个例子,在计算机网络中,处于应用层的协议,如http,ftp等,可以”享受"传输层提供给他们的服务,他们无需考虑底层链路细节,无需考虑报文是如何到达接收方,这就是分层带来的好处!
我们有了分层之后,所带来的可复用性,亦是独立性等,都有助于我们更好的管理计算机这一庞大的系统。
层次划分的方法 网络的每层应当具有相对独立的功能(便于排错,这个功能用不了必然是你这层出了问题。梳理功能之间的关系,使上一个功能可以实现为另一个功能提供必要的服务,从而形成系统的层次结构,环环相扣(紧密联系)。为提高系统的工作效率,相同或相近的功能仅在一个层次中实现,而且尽可能在较高的层次中实现。每一层只为相邻的上一层提供服务。 三、OSI七层参考模型 ISO于1984年颁布了OSI参考模型。OSi参考模型是一个开放式体系结构,它规定将网络分为七层,从下往上依次是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。
四、TCP/IP模型 TCP/IP是传输控制协议/网际协议(TransmissionControlProtocol/InternetProtocol)的简称。早期的TCP/IP模型是一个四层结构,从下往上依次是网络接口层、互联网层、传输层和应用层。在后来的使用过程中,借鉴OSI的七层参考模型,将网络接口层划分为物理层和数据链路层,形成了一个新的五层结构。TCP/IP 是一系列协议的集合,所以严格的称呼应该是TCP/IP协议簇。
网络层及以下的通信为点到点通信(主机与主机)
传输层的通信为端到端(端口到端口)
1、物理层和数据链路层,TCP/IP 并没有定义任何特定的协议。它支持所有标准的、专用的协议,网络可以是局域网(如广泛使用的以太网)、城域网或广域网。所以,TCP/IP实际上只有三个层次。
2、网络层,TCP/IP定义了IP(InternetProtocol,网际协议),而IP又由四个支撑协议组成:ARP(地址解析协议)、RARP(逆地址解析协议)、ICMP(网际控制报文协议)和 IGMP(网际组管理协议)。
地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议。主机发送信息时将包含目标IP地址的ARP请求广播到局域网络上的所有主机,并接收返回消息,以此确定目标的物理地址;收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源.
ICMP(网际控制报文协议): 用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息
3、传输层, 传统上,TCP/IP 有两个传输层协议:TCP(传输控制协议)和 UDP(用户数据报协议)。TCP协议传输更加稳定可靠,UDP协议传输效率更高。
4、应用层,TCP/IP定义了许多协议,如HTTP(超文本传输协议)、FTP(文件传输 协议)、SMTP(简单邮件传输协议)、DNS(域名系统)等。
TCP和UDP 在传输层中,TCP是传输控制协议 ,是一种面向连接的、可靠的、基于字节流的传输层通信协议,效率低,数据传输比较安全。而UDP是数据报协议,是一种面向无连接的传输层通信协议,效率高,但数据传输不安全,容易丢包。
五、数据封装过程 数据封装的过程:
数据在各层之间是如何传输的:
1、应用层,数据被“翻译”为网络世界使用的语言——二进制编码数据。大家可以试想一下,人们需要通过计算机传输数据的形式千变万化、各式各样,有字母、数字、汉字、图片、声音等。这些信息对于单一通过弱电流传输的计算机来说太过于“复杂”,因此这些人类方便识别的信息被应用层通过各种特殊的编码过程转换成二进制数据。这就是上面所描述的“翻 译”过程,也是应用层在网络数据传输过程中最为核心的贡献。
2、传输层,上层数据被分割成小的数据段,并为每个分段后的数据封装TCP报文头部。它不可能看懂应用层传输具体数据的内容的,因此只能借助一种标识来确定接收到的数据对应的应用程序,这种标识就是端口。
3、网络层,上层数据被封装上新的报文头部——IP头部。值得注意的是,这里所说上层数据包括TCP头部,也就是说,这里的上层是指传输层。对于网络层而言,它是看不懂TCP报文头部中内容的,在IP头部中有一个关键的字段信息——IP地址,一组32位的二进制数组成的,用于标识网络的逻辑地址。网络层的传输过程与其很类似,在IP头部中包含目标IP地址和源IP地址,在网络传输过程中的一些中间设备,如路由器,会根据目标IP地址来逻辑寻址,找到正确的路径将数据转发到目的端。如果中间的路由设备发现目标的IP地址根本是不可能到达的,它将会把该消息传回发送端主机,因此在网络层需要 同时封装目标IP和源IP。
4、数据链路层,在数据链路层,上层数据被封装一个MAC头部,其内部有一个关键的字段信息——MAC地址,它由一组48位的二进制数组成。在目前阶段,我们先把它理解为固化在硬件设备中的物理地址,具有全球唯一性。网卡就有属于自己的唯一的MAC地址。和IP头部一样,在MAC头部也同时封装着目标MAC地址和源MAC地址。
5、物理层,传输过程无论在之前哪一层封装的报文头部还是上层数据信息都是由二进制数组成的,在物理层,将这些二进制数字组成的比特流转换成电信号在网络中传输。
六、数据解封装过程 数据解封装过程:
1、物理层,首先将电信号转换成二进制数据,并将数据送至数据链路层。
2、数据链路层,将查看目标 MAC 地址,判断其是否与自己的 MAC 地址吻合,并据此完成后续处理。如果数据报文的目标MAC 地址就是自己的MAC地址,数据的MAC头部将被“拆掉”,并将剩余的数据送至上一层;如果目标MAC地址不是自己的MAC地址,对于终端设备来说,它将会丢弃数据。
3、网络层与数据链路层类似,目标IP地址将被核实是否与自己的IP地址相同,从而确定是否送至上一层。
4、传输层,首先要根据TCP头部判断数据段送往哪个应用层协议或应用程序,然后将之前被分组的数据段重组,再送往应用层。
当联想拯救者Y9000开机莫名其妙的卡顿,加载任何东西都很慢时,可以试着拔掉笔记本电源,很快就会恢复正常 (亲测有效)
约瑟夫问题 约瑟夫问题:n个人围成一圈,初始编号从1~n排列,从约定编号为x的人开始报数,数到第m个人出圈,接着又从1开始报数,报到第m个数的人又退出圈,以此类推,最后圈内只剩下一个人,这个人就是赢家,求出赢家的编号。
本题采用无头环形链表的方式解决问题
根据循环依次删除第m个位置的数据,最后剩下的就是我们要找的结果。
这里我们共定义6个人,从第一个人开始计数,到第5个人开始出圈。 最终剩下的人获胜
上代码:
#include<stdio.h> #include<stdlib.h> #include<string.h> typedef int datatype; //定义链表的结构体 typedef struct node_t { datatype data;//数据域 struct node_t *next;//指针域,指向自身结构体的指针 }link_node_t,*link_list_t; int snum=6;//定义总人数 int main(int argc, char const *argv[]) { //为链表申请空间 link_list_t h = (link_list_t)malloc(sizeof(link_node_t)); //赋初值 h->data=1; h->next=h; link_list_t r=h;//尾指向头,实现循环 for (int i = 0; i < snum-1; i++) { //插入链表 link_list_t pnew = (link_list_t)malloc(sizeof(link_node_t)); pnew->data=i+2; //使用尾插法,每次将节点插入到末尾 pnew->next=r->next; r->next=pnew; r=pnew; } link_list_t a=h; for (int i = 0; i < snum; i++) { printf("
【题目链接】 ybt 1389:亲戚
【题目考点】 1. 并查集 【解题思路】 并查集中,每个集合由一个树来表示,树的根结点代表一个集合。find函数可以返回一个结点所在集合的根结点。
设peoNum数组,peoNum[i]表示以i为根结点的集合的元素数量,也就是这个家族的人数。
每组互相是亲戚的人构成一个集合(家族)。如果两人是亲戚,那么调用merge函数让两人所在的集合合并,同时更新集合中的元素数量(如果合并i,j所在集合时,j所在树作为i所在树根结点的子树,那么以i为根结点的集合的元素数量peoNum[i]要增加以j为根结点的集合的元素数量peoNum[j])。
对于多组询问,每次输入a,先通过find(a)找到a所在集合的根结点,而后输出该集合的元素数量,也就是该家族的人数。
【注意】由于输入输出数据量很大,需要解除输入同步,换行用’\n’,或都使用scanf/printf。
【题解代码】 解法1:并查集 #include<bits/stdc++.h> using namespace std; #define N 1000005 int fa[N], peoNum[N];//peoNum[i]:以i为根结点的集合的元素个数 void initFa(int n) { for(int i = 1; i <= n; ++i) { fa[i] = i; peoNum[i] = 1; } } int find(int x) { if(x == fa[x]) return x; else return fa[x] = find(fa[x]); } void merge(int i, int j) { int x = find(i), y = find(j); if(x == y)//如果x, y已经在一个集合内,直接返回 return; fa[x] = y;//x的双亲设为y peoNum[y] += peoNum[x];//以y为根结点的集合元素数量增加以x为根结点的集合的元素数量 } int main() { ios::sync_with_stdio(false); cin.
数据库的分类 数据库可以简单的分为 MySQL 和 NOSQL 两类。这里的 NOSQL 不是 NO SQL 的意思,他的意思是 Not Only MySQL
MySQL与NoSQL之间的区别:
1、MySQL是一个基于表格设计的关系数据库,而NoSQL本质上是非关系型的基于文档的设计。
2、MySQL数据库,覆盖了巨大的IT市场;具有固定市场的MySQL数据库包含一个庞大的社区。而NoSQL数据库是最新的到来,与MySQL相比,社区正在慢慢发展。
3、MySQL的严格模式限制并不容易扩展,而NoSQL可以通过动态模式特性轻松扩展。
4、MySQL中创建数据库之前需要详细的数据库模型,而在NoSQL数据库类型的情况下不需要详细的建模。
5、MySQL提供了大量的报告工具,可以帮助应用程序有效,而NoSQL数据库缺少用于分析和性能测试的报告工具。
6、MySQL是一个关系数据库,其设计约束灵活性较低;而NoSQL本质上是非关系型的,与MySQL相比,它提供了更灵活的设计。
7、MySQL中使用的标准语言是SQL;而NoSQL中缺乏标准的查询语言。
mongodb是什么 mongodb是一种数据库,它可以储存键值对类型的数据(json,字典)。目前流行的数据库是 MySQL ,但它并不利于初学者入门。我之前发过 Tinydb,Sqlite3 等数据库的讲解,都比较简单,那我这次来发一下mongodb数据库。
mongodb 的数据库、集合 一个数据库下可以有多个集合,集合里存储数据。集合可以理解为 SQL 数据库中的表。
使用 Python 操作 mongodb 安装 mongodb 终端运行
pip install pymongo 连接数据库 client = pymongo.MongoClient(host, port) host是地址,port 是端口。
切换数据库 第一种方法 db_name = client['db_name'] 其中 db_name 是你的数据库名。
第二种方法 db_name = client.get_database('db_name') 其中 db_name 是你的数据库名。
第三种方法 db_name = client.db_name 切换集合 db_name.
如和优雅地实现键盘展开/收起监听 Android 键盘的展开与收起一直是个很遭人诟病的东西
方法各式各样都有,但是基本都不是很好用,有各种限制
这里编写了一个优雅地实现方式,利用屏幕实际高度与显示区域的高度对比可以优雅地判断出是否弹出键盘.
众所周知键盘是会侵占实际应用的显示区域,导致实际显示区域要远小于屏幕高度
上代码 拉走直接用 /** * CreateTime 2023/2/616:08 * 键盘 打开/收起 监听 实时回调 */ class KeyBoardUtil( activity: Activity, var keyboardVisibilityListener: ((isVisibility: Boolean) -> Unit)? ) { private val contentView: View var height: Int = 0 var isVisibility = false init { contentView = activity.window.decorView //初始化时先判断当前键盘状态 isVisibility = getScreenHeight(activity) > getWindowContentHeight(activity) //这个监听的主要作用是在键盘弹出布局发生改变时 动态的通知用户键盘是否弹出 contentView.viewTreeObserver.addOnGlobalLayoutListener { isVisibility = if (getScreenHeight(activity) > getWindowContentHeight(activity)) { keyboardVisibilityListener?.invoke(true) true } else { keyboardVisibilityListener?
什么是IP地址?
在网络中用来标识设备的具体地址,数据需要通过此进行寻址传输。
MAC地址比较复杂,为了简化流程,加入了IP地址方便操作
IP地址在网络中用于标识一个节点(或者网络设备的接口)
IP地址用于IP报文在网络中的寻址时使用
(IP地址就像现实中的家庭地址,可以表示网络中的一个节点,数据就是通过它来找到目的地)
1.地址协议
计算机二进制中:1字节byte=8位=8bit(比特)
1.1 ipv4:目前主流的协议 IP地址(ipv4)由32位二进制数组成,分为4段(4个字节),每一段8位二进制数(1个字节)中间使用英文标点符号"."隔开.
ipv4地址范围 0.0.0.0~255.255.255.255
由于二进制数太长,为了便于记忆和识别,把每一段8位二进制数转成十进制,大小为0~255,IP地址的这种表示法叫做"点分十进制表示法" 例如:210.21.196.6 就是一个IP地址的表示
1.2 ipv6:由128位组成,一般用冒号分隔,十六进制表示
ipv6地址格式:2001:0db8:3c4d:0015:0000:0000:1a2f:1a2b
2.IP地址的构成
网络部分:用来表示一个网络。代表IP地址所属网络,处于高位
主机部分:用来区分一个网络内的不同主机,能唯一标识网段上的某台设备,处于低位
例如:192.168.91.100 网络部分是192.168.91.类似固定电话的区号025,主机部分是100 类似于固定电话的具体号码8552762
3.网络掩码:区分一个IP地址中的网络部分和主机部分
IP地址段分类:A,B,C,D,E五类 ABC三类用于商业用途,D类用于组播,E类用于科研
127:本地网卡环回测试地址 127.0.0.1--本机环回测试地址 0.0.0.0--所有网段 255.255.255.255--全网广播 X.X.X.255/24--本网段广播
A类地址=网络部分+主机部分+主机部分+主机部分 默认子网掩码为/8
B类地址=网络部分+网络部分+主机部分+主机部分 默认子网掩码为/16
C类地址=网络部分+网络部分+网络部分+主机部分 默认子网掩码为/24
网络号用于三层寻址的地址,它代表整个网络本身;另一个是广播地址,它代表网络中全部的主机。
在局域网内部,有两个IP地址比较特殊,一个是网络号(网段中的第一个地址),一个是广播地址(网段中的最后一个地址)。这两个地址不能配置在计算机主机上
若主机号全0,IP地址仅代表网络号指向的那个网段,该IP代表一个网段(192.168.1.0)
若主机号全1,IP地址代表网络号指向的全部主机,IP地址代表广播地址(198.162.1.255)
其它IP地址就是普通的IP地址,指向网域中的某一台主机
例如:192.168.1.0/26
网络号:192.168.1.0
广播地址:192.168.1.63
可用IP:192.168.1.1~192.168.1.62
CIDR:无类域间路由,目前的网络已经不再按A.B.C类划分网段,可以任意指定网段的范围
它是基于可变长子网掩码来进行任意长度的前缀的分配的。
作用:节省资源
网络号的计算
1:把IP地址转换成二进制数
2:把子掩码转换成二进制数,并与IP地址对齐
3:把IP地址和子掩码做“与”运算
4:用“有0出0,全1出1”口诀,计算出结果即为网络号/网络位
5:第二个IP的网络号/网络位的计算方法同上
6:比较两个IP的网络位/网络号是否相同,如果相同即为在同一个网段,两两之间的数据通信即用交换机;如果不同,即不在同一个网段,两两之间的数据通信即用路由器
广播地址计算:把主机部分位置全部置1得到广播地址 例:172.16.0.100/16
IP地址二进制:10101100.00010000.00000000.01100100
子网掩码为: 11111111.11111111.00000000.00000000
上下相与的网络号:10101100.00010000.00000000.00000000 即网络号为172.16.0.0
广播地址:主机部分00000000.00000000全部置1为11111111.11111111即广播地址为172.16.255.255
第一个可用IP为172.16.0.1 最后一个可用IP为172.16.255.254
可用IP数量为2^16-2
引言 CMake是开源、跨平台的构建工具,可以让我们通过编写简单的配置文件去生成本地的Makefile,这个配置文件是独立于运行平台和编译器的,这样就不用亲自去编写Makefile了,而且配置文件可以直接拿到其它平台上使用,无需修改,非常方便。
本文主要讲述在Linux下如何使用CMake来编译我们的程序。
一 环境搭建 我使用的是ubuntu18.04,安装cmake使用如下命令:
sudo apt install cmake
安装完成后,在终端下输入:
cmake -version
查看cmake版本
这样cmake就安装好了。
二 简单入门 首先让我们从最简单的代码入手,先来体验下cmake是如何操作的。
2.1 项目结构 2.2 示例源码 打开终端,输入:
touch main.c CMakeLists.txt
编写main.c,如下:
main.c #include <stdio.h> int main(void) { printf("Hello World\n"); return 0; } 然后在main.c同级目录下编写CMakeLists.txt,内容如下:
CMakeLists.txt cmake_minimum_required (VERSION 2.8) project (demo) add_executable(main main.c) 2.3 运行查看 在终端下切到main.c所在的目录下,然后输入以下命令运行cmake:
cmake .
输出结果如下:
PS:此时,建议留意一下这个文件夹下多生成的文件都有哪些。
可以看到成功生成了Makefile,还有一些cmake运行时自动生成的文件。
然后在终端下输入make:
可以看到执行cmake生成的Makefile可以显示进度,并带颜色。再看下目录下的文件:
可以看到我们需要的可执行文件main也成功生成了!
然后运行main:
运行成功!
PS:如果想重新生成main,输入make clean就可以删除main这个文件。然后重新make就行。
需要注意的是:我希望你着重看一下这时候这个文件夹下都有哪些文件。
三 编译多个源文件 3.1 在同一个目录下有多个源文件 3.1.1 简单版本 接下来进入稍微复杂的例子:在同一个目录下有多个源文件。
目录
一、添加设备节点和GPIO编号结构体
二、函数入口
1、获取设备节点
2、获取led所对应的gpio编辑
of_get_named_gpio 函数
3、申请GPIO
gpio_request 函数
4、使用IO,设置为输出
gpio_direction_output 函数
5、输出低电平,点亮LED 编辑
gpio_set_value 函数
函数入口代码如下
三、函数出口
1、要添加关灯和释放GPIO
gpio_free 函数
出口代码如下
四、修改dts
1、检查复用 2、gpio使用
五、编译验证
六、使用ledAPP测试
一、添加设备节点和GPIO编号结构体 二、函数入口 1、获取设备节点 2、获取led所对应的gpio of_get_named_gpio 函数 此函数获取 GPIO 编号,因为 Linux 内核中关于 GPIO 的 API 函数都要使用 GPIO 编号,此函数会将设备树中<&gpio1 3 GPIO_ACTIVE_LOW>的属性信息转换为对应的 GPIO 编号,此函数在驱动中使用很频繁!函数原型如下
int of_get_named_gpio(struct device_node *np,
const char *propname,
int index)
np:设备节点,propname:包含要获取 GPIO 信息的属性名
index: GPIO 索引,因为一个属性里面可能包含多个 GPIO,此参数指定要获取哪个 GPIO的编号,如果只有一个 GPIO 信息的话此参数为 0
PyQt5入门教程 假定已有环境如下:
Windows
Python VSCode (我们接下来会准备pyqt5和其desinger,没必要手搓qt5界面代码,手搓它,还不如用Tkinter)
1.安装PyQt5
下面使用pip来安装PyQt5,(pip3也行)
豆瓣镜像安装
pip install PyQt5 -i http://pypi.douban.com/simple/ 2.因为Qt Designer在Python3.5版本从PyQt5转移到了tools,故还需要安装pyqt5-tools
pip install pyqt5-tools 到这一步,PyQt5就安装完成了,检查下是否已经安装成功:
Win+S召唤出 搜索框,输入designer,如果看到跟下图类似的结果说明PyQt Designer已经被安装
(可能由于各式各样的原因,可能qt desinger无法命令行安装,直接百度qt desinger 下载一个也行,其大小大致在30-40mb)
初识Qt Designer Qt Designer的界面是全英文的,有汉化方法,有需要自行搜索。
1.总之,先打开它,怎么打开都行
(不知道安装到哪了就,Win+S搜索框,输入designer并敲回车,就能够启动Qt Designer了。)
初次启动会弹出这个“New Form”窗口,一般来说选择“Main Window”然后点击“Create”就可以了。
下方有个“Show this Dialogue on Startup”的checkbox,如果不想每次启动都看到这个“New Form”窗口,可以取消勾选。
创建“Main Window”之后,我们会看到如下画面
下面就来简单介绍下整个画面的构成: 左侧的“Widget Box”就是各种可以自由拖动的组件 中间的“MainWindow - untitled”窗体就是画布 右上方的"Object Inspector"可以查看当前ui的结构 右侧中部的"Property Editor"可以设置当前选中组件的属性 右下方的"Resource Browser"可以添加各种素材,比如图片,背景等等,目前可以不管 大致了解了每个板块之后,就可以正式开始编写第一个UI了 HelloWorld! 通常来说,编写GUI有两种方法:第一种就是直接使用方便快捷的Qt Designer,第二种就是写代码。在有Qt Designer的情况下,是完全不推荐费时费力去手写GUI代码的。Qt Designer可以所见即所得,并且可以方便的修改并做出各种调整。
按照惯例,我们先来实现一个能够显示HelloWorld的窗口。
1)添加文本 ,编辑
在左侧的“Widget Box”栏目中找到“Display Widgets”分类,将“Label”拖拽到屏幕中间的“MainWindow”画布上,你就获得了一个仅用于显示文字的文本框,如下图所示。
Go 双链表 接收者是值类型好,还是指针类型好公共代码double_node.go 双链表结构空和非空链表双链表插入指定一个节点的插入按照数据的位置插入,从后往前数第三个位置插入7 双链表删除按照节点删除按照索引编号删除从txt里面查找内容 接收者是值类型好,还是指针类型好 首先要知道指针类型的接收者,有如下两个优点:
接收者是指针类型,可以修改原接收者的值。接收者是指针类型,避免了每次调用方法时复制该值,减少了内存的消耗。对于大型结构体,这样更加高效。 方法的接收者使用值类型还是指针类型,并不是由是否修改接收者的值决定的,应该是由接收者的类型决定。方法的接收者如果是原始类型,推荐使用值类型。方法的接收者如果是非原始类型,推荐使用指针类型。
//指针接收者 package main import "fmt" type Usber interface { start() stop() } type Phone struct{ name string } func (p *Phone) start() { //指针接收者 fmt.Println(p.name,"启动") } func (p *Phone) stop() { fmt.Println(p.name,"关机") } func main() { p := &Phone{ name : "华为", } var c Usber = p //表示让Phton实现Usb接口 c.start() c.stop() } &取出地址,*根据地址取出地址指向的值。
package main import ( "fmt" ) func main() { // 准备一个字符串类型 var house = "
引入雪花算法当作生成主键,遇到问题如下:
前端请求获取的response的值,ID和后端返回的值不一致,排查了很久发现是前端在获取时将Long类型值转换超范围导致丢失精度
Java后端Long类型的范围 -263~263,即:-9223372036854775808~9223372036854775807,它是19位的。 这个数字可以通过方法获得:Long.MAX_VALUE、Long_MIN_VALUE。 前端JS的数字类型的范围 -253~253,即:-9007199254740991~9007199254740991,它是16位的。 这个数字可以通过方法获得:Number.MAX_SAFE_INTEGER、Number.MIN_SAFE_INTEGER。 解决办法 全局处理自定义ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; @Configuration public class JacksonConfig { @Bean public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { ObjectMapper objectMapper = builder.createXmlMapper(false).build(); // 全局配置序列化返回 JSON 处理 SimpleModule simpleModule = new SimpleModule(); // 将使用String来序列化Long类型 simpleModule.addSerializer(Long.class, ToStringSerializer.instance); simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance); objectMapper.registerModule(simpleModule); return objectMapper; } } 局部处理:
在字段上加:@JsonSerialize(using= ToStringSerializer.class) @Id @GeneratedValue(generator = "myIDGenerator") @JsonSerialize(using= ToStringSerializer.class) private Long id; 注意:全局处理会将分页参数页码、总条数值也转成string类型
Python时间字符串输出为某年某月某日 时间格式转换:将时间字符串xx-x-x格式转成xx年x月x日 # 数据中的时间字符串格式为‘2012-12-30’ data = pd.DataFrame(['2022-12-30','2022-12-20','2022-11-30'],columns=['时间']) data 时间格式转换:将时间字符串xx-x-x格式转成xx年x月x日 错误情况 # data['时间'].apply(lambda x:time.strftime("%Y年%m月%d日",time.strptime(x,'%Y-%m-%d'))) # 会出现以下报错 # 'locale' codec can't encode character '\u5e74' in position 2: encoding error # strptime或者strftime格式化参数里有一些是跟locale相关的,默认的格式化编码为单字节编码,导致不能对多字节进行编码 成功转换 import locale import time locale.setlocale(locale.LC_CTYPE, 'chinese') # 添加编码格式 data['时间'] = data['时间'].apply(lambda x:time.strftime("%Y年%m月%d日",time.strptime(x,'%Y-%m-%d'))) # 先使用【strptime】将时间字符串解析成时间元组struct_time,再使用【strftime】将时间格式化成指定格式的字符串 data 还可以使用strftime的format方法 data['时间'].apply(lambda x:time.strftime("%Y{y}%m{m}%d{d}",time.strptime(x,'%Y-%m-%d')).format(y='年',m='月',d='日'))
activiti6 查看流程图 根据processInstanceId查询
大家大概看一眼吧 我就记录一下 勿喷!
Controller @GetMapping("/getFlow") @ApiOperation(value = "流程图", httpMethod = "GET", notes = "流程图") public void getFlow(String processInstanceId, HttpServletResponse response) { ProcessinstanceService.getActiviti(processInstanceId, response); } Service public void getActiviti(String processInstanceId, HttpServletResponse response) { response.setHeader("Pragma", "No-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); JbpmProcessinstanceService.log.info("[开始]-获取流程图像"); InputStream imageStream = null; try { //获取历史流程实例 HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery() .processInstanceId(processInstanceId).singleResult(); if (historicProcessInstance == null) { imageStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("noimage.png"); response.setContentType("image/png"); OutputStream os = response.getOutputStream(); int bytesRead = 0; byte[] buffer = new byte[8192]; while ((bytesRead = imageStream.
MySQL
MySQL
前言
数据库概念
为什么要使用数据库?
MySql简介
数据库操作
关系模型
查看数据库
创建数据库
选择数据库
删除数据库
数据库命名规范
数据表的操作
创建一个班级表
表的创建
列名
列的类型定义
整型类型
(1)类型名后面的小括号
(2)UNSIGNED(无符号)
(3)AUTO_INCREMENT
浮点类型和定点数类型
日期和时间类型
字符串类型
CHAR类型和VARCHAR类型
TEXT类型
字符串类型选择练习
ENUM和SET类型
二进制类型
BINARY和VARBINARY
BIT类型
BLOB类型
其他数据类型
列的完整性约束
设置表字段的主键约束(PRIMARY KEY,PK)
单字段主键
多字节主键
设置表字段的外键约束(FORENIGN KEY,FK)
设置列的非空约束(NOT NULL,NK)
设置表字段唯一约束(UNIQUE,UK)
设置表字段值自动增加(AUTO_INCREMENT)
设置表字段的默认值(DEFAULT)
调整列的完整性约束
修改主键PK、外键FK和 唯一键UK
修改默认值DEFAULT、自增长和非空NK
表索引
索引概述
索引类型
索引存储
索引优点
索引缺点
注意
创建和查看索引
普通索引
查询索引执行情况
唯一索引
全文索引
MySQL8中文分词支持
多列索引
隐藏索引
删除索引
索引的设计原则
表的插入
插入完整数据记录
获得诸如Plane、Cube的size。 可以为它们添加Collider,然后使用XXX.collider.bounds.size;该方法获得的size和缩放比例有关,是一一对应的,缩放比例一旦改变,size也改变。
获得terrain的尺寸,在terrain的scale为1的情况下: terrainWidth = terrain.collider.bounds.size.x; terrainLength = terrain.collider.bounds.size.z; terrainHeight = terrain.collider.bounds.size.y; 每个物体都有组件MeshFilter(网格过滤器),该属组件的size属性可以获得对应的x,y,z方向的长度。
经测试size和缩放比例无关,缩放比例改变size不改变,size记录的是物体的原始尺寸。
物体的各个方向缩放比例可以通过其transform的localScale来获得,即:XX.transform.localScale.x。
物体的实际尺寸=原始尺寸*缩放比例。 float xSize = XX.GetComponent<MeshFilter>().mesh.bounds.size.x * XX.transform.localScale.x; 说明:一般用方法2。
Camera的口径Size 当投影类型为Perspective时,fieldOfView属性表示口径的度数,范围为[1,179];
当投影类型为Orthgraphic,orthographicSize属性为正交模式下的口径尺寸。
原文链接:https://www.cnblogs.com/fm168/archive/2013/04/26/3043947.html
Powered by:NEFU AB-IN
B站直播录像!
Link
文章目录 Codeforces Round 849 (Div. 4) A Codeforces Checking题意思路代码 B. Following Directions题意思路代码 C. Prepend and Append题意思路代码 D. Distinct Split题意思路代码 E. Negatives and Positives题意思路代码 F. Range Update Point Query题意思路代码 G1. Teleporters (Easy Version)题意思路代码 Codeforces Round 849 (Div. 4) A Codeforces Checking 题意 Given a lowercase Latin character (letter), check if it appears in the string codeforces codeforces .
思路 模拟
代码 #include <bits/stdc++.h> using namespace std; #define int long long #undef int #define SZ(X) ((int)(X).
SQL优化 1、SQL执行顺序2、前置条件2.1、使用explain分析SQL执行计划2.2、开启慢sql日志2.3、慢查询时间设置。默认情况下long_query_time的值为10秒,可以使用命令修改,也可以在my.cnf参数里面修改。 3、基础Sql优化3.1、小表驱动大表3.2、高效的分页3.3、分段查询3.4、注意范围查询语句3.5、查询SQL尽量不要使用select *,而是具体字段3.6、当只需要一条数据的时候,使用limit 13.7、如果排序字段没有用到索引,就尽量少排序3.8、如果限制条件中其他字段没有索引,尽量少用or3.9、避免在where子句中使用or来连接条件3.10、使用varchar代替char3.11、选择合理的字段类型3.12、尽量使用数值替代字符串类型3.13、查询尽量避免返回大量数据3.14、正确的建立索引3.15、指定查询的索引[建议]3.15.1、use index(索引): 推荐使用指定的索引 (最终用不用该索引,还需要mysql自己判断)3.15.2、ignore index(索引) : 忽略掉这个索引3.15.3、force index(索引): 强制使用该索引 3.16、是否使用了索引及其扫描类型3.17、优化like语句3.18、避免隐式类型转换3.19、索引不宜太多,一般5个以内3.20、索引不适合建在有大量重复数据的字段上3.21、where限定查询的数据3.22、避免在索引列上使用内置函数3.23、避免在where中对字段进行表达式操作3.24、避免在where子句中使用!=或<>操作符3.25、去重distinct过滤字段要少3.26、where中使用默认值代替null 4、高级SQL优化4.1、创建表时使用同一的编码4.2、insert插入优化4.3、批量插入性能提升4.4、update优化 (避免出现表锁)4.5、批量删除优化4.6、伪删除设计4.7、order by 排序优化 (排序时,使用有索引的字段进行排序)4.8、不使用ORDER BY RAND()4.9、count 优化 速度:count(*)>count(1)>count(字段)4.10、提高group by语句的效率4.11、复合索引最左特性4.12、排序字段创建索引4.13、删除冗余和重复的索引4.14、不要有超过5个以上的表连接4.15、用连接查询代替子查询[建议]4.16、inner join 、left join、right join,优先使用inner join4.17、join优化4.17.1、MySQL中没有full join,可以用以下方式来解决4.17.2、尽量使用inner join,避免left join4.17.3、合理利用索引4.17.4、利用小表去驱动大表4.17.5、巧用STRAIGHT_JOIN 4.18、in子查询的优化4.19、SQL语句中IN包含的值不应过多4.20、尽量使用union all替代union4.21、区分in和exists、not in和not exists 1、SQL执行顺序 SELECT DISTINCT column,… (选择字段 、去重)AGG_FUNC(column or expression),… (聚合函数)FROM [left_table] (选择表)<join_type> JOIN <right_table> (连接)ON <join_condition> (连接条件)WHERE <where_condition> (条件过滤)GROUP BY <group_by_list> (分组)HAVING <having_condition> (分组过滤)ORDER BY <order_by_list> (排序)LIMIT count OFFSET count; (分页) 2、前置条件 2.1、使用explain分析SQL执行计划 SQL很灵活,一个需求可以很多实现,那哪个最优呢?SQL提供了explain关键字,它可以分析你的SQL执行计划,看它是否最佳。Explain主要看SQL是否使用了索引。
官方说明文档
yum install -y yum-utils yum-config-manager --add-repo https://packages.clickhouse.com/rpm/clickhouse.repo yum install -y clickhouse-server clickhouse-client clickhouse-server start 至此安装成功。
# 查看启动状态 clickhouse-server status # 启动 clickhouse-server start # 停止 clickhouse-server stop # 重启 clickhouse-server restart 相关配置修改如下:
1、由于默认只能本地访问,所有需要修改配置,将config.xml中的 **<listen_host>::</listen_host>**注释去掉
vim /etc/clickhouse-server/config.xml # 如果支持IPV6 <listen_host>::</listen_host> # 如果支持IPV4 <listen_host>0.0.0.0</listen_host> # 默认数据文件路径:<path>/var/lib/clickhouse/</path> # 默认日志文件路径:<log>/usr/logs/clickhouse-server/clickhouse-server.log</log> 2、设置密码,这里使用sha256加密密文进行配置,以下命令可以获得明文密码的密文。
echo -n 明文密码 | openssl dgst -sha256 修改users.xml中的配置。
vim /etc/clickhouse-server/users.xml # 添加如下配置,注意替换自己的密文 <password_sha256_hex>4092f076859881b4939b61b968e234f8474c0f09347770829de2ba6b98a140ba</password_sha256_hex> 注:关于密码配置users.xml文件中给了详细的说明
<users> <!-- If user name was not specified, 'default' user is used.
【车载开发系列】UDS诊断—DTC故障码基础回顾 UDS诊断---DTC故障码基础回顾 【车载开发系列】UDS诊断---DTC故障码基础回顾一.什么是DTC故障码二.DTC故障码的作用三.什么是自诊断需求四.故障自诊断范围是什么五.DTC故障码的格式及组成六.DTC之故障所属系统七.DTC之故障类型八.DTC之所属子系统九.DTC之故障失效类型十.DTC故障码的表示十一.故障指示的概念十二.什么是故障快照信息十三.什么是故障扩展信息十四.故障扩展信息和快照信息的作用十五.DTC故障码的状态位十六.状态码的作用是什么十七.DTC故障信息存储机制十八.什么是故障自恢复策略十九.与操作DTC故障码相关的SID有哪些二十.与DTC相关的标准主要有哪些二十一.OBD与UDS的故障代码区别二十二.自诊断故障与脱机诊断故障的区别 一.什么是DTC故障码 DTC(Diagnostic Trouble Code)表示诊断故障码,是故障类型的身份ID号码;用于汽车故障时对故障部位及原因的排查。
当ECU检测到一个故障时,其将在存储器中存储对应的一个代码,此代码被称为故障代码。 除故障代码外,ECU还可能存储与此故障相关的故障状态、快照信息及扩展信息。
二.DTC故障码的作用 DTC故障码主要用来就行线下的检测和故障的维修。
1)下线检测
对于一辆车的零部件的开发、系统集成、整车组装,其中涉及的流程之长、零件数量之多,可以说是相当的复杂;为了保证最终车辆下线,并且能够安全的上路,这就要在上路之前保证每个零件本身和零件之间必须保证没有任何问题,因此故障码检测就应运而生;不仅保证电子元器件本身不存在问题,而且保证电子元器件间也是通信正常,并保证最终车辆的安全上路。
2)故障维修
车辆在整个使用的生命周期中,所处的环境也是相当的复杂且恶略;对于当前车辆复杂的线路来说是一项极大的挑战,同时在出现问题后问题的排查也是相当的困难,这时候我们就可以通过故障码来进行查询故障位置,进行快速定位和解决。
三.什么是自诊断需求 Self Fault Detection就是自诊断需求的意思。所有ECU都应持续地进行故障自诊断,以监控运行状态下的异常事件(错误)。 故障自诊断包括两种:初始化阶段自诊断及持续运行时的自诊断。
四.故障自诊断范围是什么 故障自诊断范围Self Fault Detection Scope
故障自诊断的范围,应包含但不限于如下列内容:
1)ECU 内部异常情况;
2)网络通信异常情况;
3)输入/输出线路的开路或短路情况;
4)超出线路正常运行范围的错误信号;
5)迫使系统以失效安全模式运行的情况;
五.DTC故障码的格式及组成 故障代码由 3 个字节组成:故障代码高字节、 故障代码中字节及故障代码低字节(故障代码失效类型)。前两个字节代表发生故障的对象,也就是故障内码;对应5位标准故障码(第一位是字母,后面四位是数字)。
而故障代码的低字节代表故障失效类型信息。
六.DTC之故障所属系统 故障代码高字节的第一位是字母,表示故障所属系统;有如下的四种情况:
故障内码bit14bit15标准故障码表示字符所属系统0x00PPowertrain动力系统故障0x01CChassis底盘故障0x10BBody车身故障0x11UNetwork网络故障 故障码的P、C、B、U码简单来说,这四个字母的来源即是对应车辆的四个组成部分,分别是Power(动力),Chassis(底盘)、Body(车身)、Network and vehicle Integration(U:网络和车辆集成)。
PCBU码在byte0的分布主要为P(00-3F)、C(40-7F)、B(80-BF)、U(C0-FF)。
七.DTC之故障类型 故障代码高字节的第二位是数字,表示故障类型;有如下的四种情况:
故障内码bit13bit12标准故障码表示字符故障类型0x000ISOSAE标准定义故障码0x011制造商自定义故障码0x102ISOSAE保留码0x113ISOSAE保留码 八.DTC之所属子系统 故障代码高字节的第三位是数字,表示故障所属的子系统;以对动力系统为例(P开头的故障码),有以下的情况:
0:表示燃油和空气计量辅助排放控制整个系统;
1:表示燃油和空气计量系统;
2:表示燃油和空气计量系统(喷油器)
3:表示点火系统;
4:表示废气控制系统;
5:表示巡航、怠速控制系统;
6:车载电脑和输出信号;
7:传动系统控制;
8:传动系统控制;
九.DTC之故障失效类型 故障代码中的低字节DTCLowByte则是描述故障种类和子类型,该部分内容遵循ISO 15031-6;对于不需要该字节信息的DTC,可填充为0x00。
十.DTC故障码的表示 故障码一般使用16进制数字来表示。
将标准故障码的第一、第二位(如下例中的“U0”、“B1”)换算为对应的内码格式,再以16进制表示出来;
至于后面的其他内容,其格式本来就是16进制进行表示的,直接照着写下来即可
就是说只要将标准故障码的第一、二位进行转换即可。
例如:
闭包的原理 一、什么是闭包 MDN中对闭包有以下定义:
一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在 JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。
从上述定义中我们可以总结出4点(重点):
1、闭包是在函数创建时创建的,即有函数创建就会生成闭包;
2、闭包和其函数在同一上下文中;
3、闭包包含该作用域下的所有变量/引用地址;
4、定义函数不会创建闭包,只有创建/执行函数同时才创建闭包;
注意:使用闭包时一定要注意其作用域!
如下图:第1行到第9行,只涉及到变量的声明赋值和函数的定义,所以不会有闭包产生;当代码执行到第10行,执行函数fn创建函数实例,因此会伴随着创建该作用域的一个闭包,闭包中包含变量a和b;当第10行执行完,函数实例销毁(函数内部没有引用外部变量),闭包也就随之销毁。
二、函数引用外部变量后的闭包 “一”中代码实例主要介绍了闭包和函数的创建,如果仅仅是这些描述,我们也没有必要去了解和使用闭包;但是,当函数中“引用”(借用)了外部的变量后,一切都变得精彩了:
代码分析:
function makeAdder() { var sum = 0 return function(y) { sum += y; return sum }; } var add1 = makeAdder(); var add2 = makeAdder(); console.log(add1(1)); // 1 console.log(add1(1)); // 2 console.log(add2(2)); // 2 console.log(add2(2)); // 4 分析下图:
1、1-7行定义了makeAdder函数,并将函数定义存储在内存中(蓝色圈圈);
2、第9行,调用makerAdder定义执行1-7行代码,声明并赋值sum;将3-6行函数定义返回并赋值给变量add1,同时创建对应闭包,存放sum变量,且值为0;第9行执行完毕,销毁本地执行上下文和sum变量,控制权交给调用上下文;
3、第10行,调用makerAdder定义执行1-7行代码,声明并赋值sum;将3-6行函数定义返回并赋值给变量add2,同时创建对应闭包,存放sum变量,且值为0;第10行执行完毕,销毁本地执行上下文和sum变量,控制权交给调用上下文;
4、由于add1和add2创建两个新的函数实例,所以其相对应闭包是相互不影响的;
5、执行到12行,调用add1实例并执行函数(3-6行),传入参数y为1,执行sum += y ,在查找本地或全局执行上下文之前,让我们检查一下闭包,结果闭包包含一个名为sum的变量,sum变量从0变为1,同时返回sum,最终打印出1。执行完毕,销毁本地执行上下文;
6、执行到13行,调用add1实例并执行函数(3-6行),传入参数y为1,执行sum += y ,在查找本地或全局执行上下文之前,让我们检查一下闭包,结果闭包包含一个名为sum的变量,sum变量从1变为2,同时返回sum,最终打印出2。执行完毕,销毁本地执行上下文;
7、执行到15行,调用add2实例并执行函数(3-6行),传入参数y为1,执行sum += y ,在查找本地或全局执行上下文之前,让我们检查一下闭包(此时的闭包和add1的闭包处于不同函数实例,故相互不不影响),结果闭包包含一个名为sum的变量,sum变量从0变为2,同时返回sum,最终打印出2。执行完毕,销毁本地执行上下文;
服务器线上问题开发系列 文章目录 服务器线上问题开发系列前言一、定位问题流程二、使用实例流程1.代码2.定位问题实践过程 总结 前言 一、定位问题流程 项目上线,CPU飙高不下,触发报警,如何定位排查问题。有两种办法1、通过堆栈 2、通过火焰图(本文略)
1、top查看进程占用率最高的进程
2、ps -mp pid定位到进程中cpu占用最高的线程
ps -mp 1153 -o THREAD,tid,pid
3、pstack 打印堆栈调用
二、使用实例流程 1.代码 #include <iostread> #include <thread> void test1() { while(1){ sleep(0.1); } } void test2() { while(1){ sleep(10); } } void dbdemo() { std::thread(test1).detach(); std::thread(test2).detach(); } int main() { dbdemo(); return 0; } 2.定位问题实践过程 1、top查出占用率高的进程DBclient的Pid 5896
2、ps -mp 5869 -o THREAD,tid,pid 查出DBclient进程中占用率过高的Tid,5900,转为16进制0x170C
3、pstack 5896,找到对应5900的线程,即可发现调用栈
发现线程4调用关系,test1中sleep函数导致cpu占用过高,
#0 0x00007fa889545626 in sleep () from /lib64/libc.
目录
函数栈帧是什么?
内存分区
寄存器
汇编指令 栈帧创建与销毁过程
函数执行之前的准备工作
函数执行
函数执行结束,进行函数返回
ebp回到上一个栈底
销毁形参
回到上一栈帧 查看汇编指令
编辑
前言
在C语言编写时,我们总会把一些功能单独写成一个函数,在主函数中调用,只需要在调用时通过函数名将实参传给形参就实现了整个函数调用过程,但实际的调用过程底层很复杂,这其中关系到函数栈帧。
函数栈帧是什么? 栈帧也叫过程活动记录,是编译器用来实现函数调用过程的一种数据结构。C语言中,每个栈帧对应着一个未运行完的函数。从逻辑上讲,栈帧就是一个函数执行的环境:函数调用框架、函数参数、函数的局部变量、函数执行完后返回到哪里等等。栈是从高地址向低地址延伸的。每个函数的每次调用,都有它自己独立的一个栈帧,这个栈帧中维持着所需要的各种信息,比如该函数的返回地址和局部变量。寄存器ebp指向当前的栈帧的底部(高地址),寄存器esp指向当前的栈帧的顶部(低地址)。
内存分区 栈区:从高地址向低地址延伸的,主要用来存放局部变量,函数调用开辟的空间,与堆共享一段空间。
堆区:由低地址向高地址增长,动态开辟的空间就在这里(malloc,realloc,calloc,free),与栈共享一段空间。
静态区:主要存放全局变量和静态变量。 寄存器 ebpebp是基址指针,保存调用者函数的地址,总是指向当前栈帧栈底espesp是被调函数指针,总指向函数栈栈顶esx累加器,用来乘除法,与函数返回值(本篇主要关注第二个功能)eax通用寄存器,保存临时数据,常用于返回值eip指令寄存器,保存当前指令的下一条指令的地址 汇编指令 mov:数据转移指令
push:数据入栈,同时esp栈顶寄存器也要发生改变
pop:数据弹出至指定位置,同时esp栈顶寄存器也要发生改变
sub:减法命令
add:加法命令
call:函数调用,1. 压入返回地址 2. 转入目标函数
jump:通过修改eip,转入目标函数,进行调用
ret:恢复返回地址,压入eip,类似pop eip命令
简单来讲,esp和ebp是两个指针ebp指向当前栈帧栈底,esp指向函数栈栈顶。
栈帧创建与销毁过程 #define _CRT_SECURE_NO_WARNING #include<stdio.h> #include<stdlib.h> int Add(int a, int b) { int c = 0; c = a + b; return c; } int main() { int a = 10; int b = 20; int ret = Add(a, b); printf("
注:知识点参考【武沛齐】
一、创建Django项目 pip 安装完毕 Django 后,命令行进入某个目录,输入命令:
进入到目录后,输入创建 Django 项目命令(注意,Django 创建项目后还需要通过命令在当前 Django 下创建对应的 app):
django-admin startproject DjangoAutoServer 以上代码中,django-admin startproject 是创建 Django 项目的命令,之后所跟上的 DjangoAutoServer 是对应的项目名:
若提示 “django-admin startproject ” 无法识别,请将对应的 Django 目录下的 Script 加入到环境变量之中。
创建好项目后可以在所选择的目录下看到一个以项目名作为名称的文件夹:
目录文件介绍 二、创建 app 应用 在 Django 中,创建好一个项目后,我们还需要对项目得创建一个 app,创建 app 在需要在对应的项目目录下,首先进入对应的项目目录:
随后输入对应的创建 app 命令(需要注意:这个目录需要是有 manage.py 的目录):
命令如下:
python manage.py startapp server 创建完毕后会有一个文件夹是 app 文件夹:
app 文件夹内容如下:
作用如下:
三、注册 app 到项目中 在 Django 中,我们需要对创建的 APP 进行注册,需要在 Django 下的 setting.
上传文件的输入框演示往往非常难看,但又不想使用bootstrop或者elementui框架的样式
所以可以通过自定义样式来修改input的样式
可以通过父子定位来实现修改
代码如下
html代码 <div class="group"> <label for="img" class="labelImg"> <input type="button" id="btn" value="请上传识别图像" /> <input type="file" name="img" id="img" /><br /><br /> </label> </div> css代码 .labelImg { position: relative; #img { position: absolute; left: 0; top: 0; opacity: 0; } #btn { padding: 5px 10px; background-color: #00b0f0; color: #fff; border: none; border-radius: 5px; } } 修改后的样式
游戏作为
一个行业真正发展起来是从上世纪70年代之后,电子技术的飞速发展带动了游戏行业的发展。特别是计算机技术的飞速发展和个人电脑、移动设备的广泛普及,为游戏提供了广阔的平台和众多的用户。巨大的市场需求为游戏行业的发展和建设提供了新的契机。游戏行业对人才的需求也极大地推进了游戏教育的发
展。全球首家游戏设计教育机构-DigiPen理工学院从1994年开始与任天堂联手创建游戏教育基地,培训电
脑游戏技术和设计专业人才。随后各院校相继开展游戏教育,浒戏逐渐独立成为一门学科,并进一步细分为游戏美术和游戏编程技术两大专业,提供从本科到博士的人才教育。浒戏开发不具是需要熟练的计算机游戏编程技术,还需要游戏开发者具有相当的艺术修养,比如说游戏背景、剧情 游戏美术.模型.游戏动画、游戏特效等众多的内容。这也对游戏开发行业人才的培养提出了更高的要求。星然我国很早就在大学开设了计算机专业但将计算机技术应用到游戏开发方向,专门成立以游戏开发为目的的相关专业却是在本世纪初的事情。2004年浙江大学成立数字媒体与网络技术专业,以游戏编程技术为主要培养方向。各高校根据自己的技术力量特点,分别以技术和艺术为主要方向培养游戏开发人才,纷纷成立数宁媒体技术或数字媒体艺术专业。从事游戏开发的企业也纷纷面向应届本科毕业生招收学员为自己或者社会培养游戏开发专业人才。随着电脑、手机、平板等各游戏运行平台的飞速发展,行业对游戏开发人才的需求在质量上对学校和培训机构提出了更高的要求,在数量上更是需要大量的人才。如何改革游戏教育教学体系,为行业培养出满足企业需求的合格人才,是摆在高校面前的重要问题。
项目使用的代码:
https://gitee.com/olhong/learn-project/tree/master/part3/fed-e-task-03-04
blog_strapi和blob-with-gridesome
部署strapi 服务器配置mysql环境
下载mysql的yum源
wget http://repo.mysql.com/mysql-community-release-el6-5.noarch.rpm yum install -y mysql-community-release-el6-5.noarch.rpm 安装mysql
yum -y install mysql-server
启动mysql服务
systemctl start mysqld.service
登录mysql
//初次登录,默认无密码 mysql -uroot -p //使用mysql数据库 mysql> use mysql //更新root用户密码 mysql> update user set password=password("123") where user = "root"; //刷新权限,修改密码才能生效,或者直接重启系统也可以生效 mysql> flush privileges; //逐行显示查询数据 select * from mysql.user \G; 配置mysql
# 编写my.cnf文件 vim /etc/my.cnf 在[mysqld]下添加如下内容: #设置字符集 character-set-server=utf8 #跳过验证 #skip-grant-tables 重启一下mysql服务,配置生效 #重启mysql systemctl restart mysqld.service 创建数据库
进入mysql
mysql -uroot -p
死锁 死锁的理解:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁。
说明:
1.出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于 阻塞状态,无法继续。
2.我们使用同步时,要避免出现死锁
解决方法 专门的算法、原则
尽量减少同步资源的定义
尽量避免嵌套同步
=========================================================================
首先我们看两张图理解一下JDK中用Thread.State类定义了线程的几种状态:
要想实现多线程,必须在主线程中创建新的线程对象。Java语言使用Thread类及其子类的对象来表示线程,在它的一个完整的生命周期中通常要经历如下的五种状态:
新建: 当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态
就绪:处于新建状态的线程被start()后,将进入线程队列等待CPU时间片,此时它已具备了运行的条件,只是没分配到CPU资源
运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态, run()方法定义了线 程的操作和功能
阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出 CPU 并临时中止自己的执行,进入阻塞状态
死亡:线程完成了它的全部工作或线程被提前强制性地中止或出现异常导致结束
1:线程的生命周期
2:线程的转换:
=========================================================================
下面关于死锁问题演示说明
代码如下:
public class ThreadTest { public static void main(String[] args) { StringBuffer s1 = new StringBuffer(); StringBuffer s2 = new StringBuffer(); new Thread(){ @Override public void run() { synchronized (s1){ s1.append("a"); s2.append("1"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (s2){ s1.
进制转换 可以直接进行算术运算的数据
二进制(逢2进1):0~1
十进制(逢10进1):0~9
八进制(逢8进1):0~7
十六进制(逢16进1):0-9、a(A)-f(F)
其他进制转十进制 方法:对应的数字乘以其他进制的位数次幂
二进制转十进制
八进制转十进制
需注意:通常为了区分八进制和十进制,会在八进制数前加上0
十六进制转十进制
需注意:通常为了与其他进制区分开,会在十六进制前加上0x或0X,当十六进制的字母用小写时,x也要小写,后面使用大写,则X也要大写,如:0x4caf、0X5FBC
十进制转其他进制 方法:除以其他进制倒取余
十进制转二进制
十进制转八进制
十进制转十六进制
二进制和八进制相互转换 每一个八进制数都可以用三位二进制数进行表示
0 — 7
二进制八进制00000011010201131004101511061117 在进行转换时,可考虑(421)
如:1、将10 101 011 转换为八进制
答:
从右往左开始看,三个为一组,不够的前面补0,即010 101 011,011为3、101为5、010为2,又因为为了区分八进制和十进制,故在最前面加上0,即0253
2、将052转换为二进制
答:5转换为二进制位101,2转换为二进制为010,即052转换为二进制为101 010
二进制和十六进制相互转换 每一个十六进制数可以用四位二进制数进行表示
二进制十六进制000000001100102001130100401015011060111710008100191010A1011B1100C1101D1110E1111F 在转换时,可考虑(8421)
如:
1、101 1101 0111转换为十六进制
答: 从右往左开始,4个为一组,不够的补0,即0101 1101 0101,0111为5、1101为D、0111为7,为了与其他进制区别,在前面加上0X,即0X5D7
2、将0X2BF6转换为二进制
答:2为0010、B为1011、F为1111、6为0110,即0X2BF6为0010 1011 1111 0110
示例:
1、将二进制1110 1101进制转换为十进制
答:按照常规的方法来算:
算起来很麻烦,不如转换一下思路,先将这个二进制数利用8421码转换成十六进制,再将十六进制转为十进制,即1110为E,1101为D,转换成十六进制为0XED,即:
二进制1110 1101转换为十进制为237
2、将八进制0623和十六进制0xa6f2转换为二进制
答:直接利用8421码
6为110、2为101、3为011,即八进制0623转换为二进制为110 101 011
a为1010、6为0110,f为1111,2为0010,即十六进制0xa6f2转换为二进制为1010 0110 1111 0010
Redis在3.0版本前只支持单实例模式,虽然Redis的开发者Antirez早在博客上就提出在Redis 3.0版本中加入集群的功能,但3.0版本等到2015年才发布正式版。
各大企业等不急了,在3.0版本还没发布前为了解决Redis的存储瓶颈,纷纷推出了各自的Redis集群方案。这些方案的核心思想是把数据分片(sharding)存储在多个Redis实例中,每一片就是一个Redis实例。
包括:客户端分片、代理分片、Redis Cluster
客户端分片 客户端分片是把分片的逻辑放在Redis客户端实现,(比如:jedis已支持Redis Sharding功能,即ShardedJedis),通过Redis客户端预先定义好的路由规则(使用一致性哈希),把对Key的访问转发到不同的Redis实例中,查询数据时把返回结果汇集。这种方案的模式如图所示。
一致性哈希算法(consistent hashing) 一致性哈希算法分布式系统中常用的算法。
什么是一致性 hash 算法:
一致性哈希算法也是使用取模的方法,普通哈希算法取模算法是对服务器的数量进行取模,而一致性哈希算法是对 2^32 取模,具体步骤如下:
1.一致性哈希算法将整个哈希值空间按照顺时针方向组织成一个虚拟的圆环,称为 Hash 环;
2.接着将各个服务器使用 Hash 函数进行哈希,具体可以选择服务器的IP或主机名作为关键字进行哈希,从而确定每台机器在哈希环上的位置
3.最后使用算法定位数据访问到相应服务器:将数据key使用相同的函数Hash计算出哈希值,并确定此数据在环上的位置,从此位置沿环顺时针寻找,第一台遇到的服务器就是其应该定位到的服务器
一致性哈希算法问题:hash 环的倾斜
一致性哈希算法在服务节点太少的情况下,容易因为节点分部不均匀而造成数据倾斜问题,也就是被缓存的对象大部分集中缓存在某一台服务器上,从而出现数据分布不均匀的情况,这种情况就称为 hash 环的倾斜。
hash 环的倾斜在极端情况下,仍然有可能引起系统的崩溃,为了解决这种数据倾斜问题,一致性哈希算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点,一个实际物理节点可以对应多个虚拟节点,虚拟节点越多,hash环上的节点就越多,缓存被均匀分布的概率就越大,hash环倾斜所带来的影响就越小,同时数据定位算法不变,只是多了一步虚拟节点到实际节点的映射。
比如,一个分布式的存储系统,要将数据存储到具体的节点上,如果采用普通的hash方法,将数据映射到具体的节点上,如mod(key,d),key是数据的key,d是机器节点数,如果有一个机器加入或退出这个集群,则所有的数据映射都无效了。
一致性哈希算法解决了普通余数Hash算法伸缩性差的问题,可以保证在上线、下线服务器的情况下尽量有多的请求命中原来路由到的服务器。
如Jedis的Redis Sharding实现,采用一致性哈希算法(consistent hashing),将key和节点name同时hashing,然后进行映射匹配,采用的算法是MURMUR_HASH。
采用一致性哈希而不是采用简单类似哈希求模映射的主要原因是当增加或减少节点时,不会产生由于重新匹配造成的rehashing。一致性哈希只影响相邻节点key分配,影响量小。
客户端分片的优缺点 优点:
客户端sharding技术使用hash一致性算法分片的好处是所有的逻辑都是可控的,不依赖于第三方分布式中间件。服务端的Redis实例彼此独立,相互无关联,每个Redis实例像单服务器一样运行,非常容易线性扩展,系统的灵活性很强。开发人员清楚怎么实现分片、路由的规则,不用担心踩坑。 不足:
这是一种静态的分片方案,需要增加或者减少Redis实例的数量,需要手工调整分片的程序。运维成本比较高,集群的数据出了任何问题都需要运维人员和开发人员一起合作,减缓了解决问题的速度,增加了跨部门沟通的成本。在不同的客户端程序中,维护相同的路由分片逻辑成本巨大。比如:java项目、PHP项目里共用一套Redis集群,路由分片逻辑分别需要写两套一样的逻辑,以后维护也是两套。 客户端分片有一个最大的问题就是,服务端Redis实例群拓扑结构有变化时,每个客户端都需要更新调整。如果能把客户端分片模块单独拎出来,形成一个单独的模块(中间件),作为客户端 和 服务端连接的桥梁就能解决这个问题了,此时代理分片就出现了。
代理分片 代理基本原理是:通过中间件的形式,Redis客户端把请求发送到代理,代理根据路由规则发送到正确的Redis实例,最后代理把结果汇集返回给客户端。
代理分片有:Twemproxy、predixy、codis 。
Twemproxy Twemproxy由Twitter开源的Redis代理,其基本原理是:通过中间件的形式,Redis客户端把请求发送到Twemproxy,Twemproxy根据路由规则发送到正确的Redis实例,最后Twemproxy把结果汇集返回给客户端。
Twemproxy github地址:https://github.com/twitter/twemproxy
Twemproxy通过引入一个代理层,将多个Redis实例进行统一管理,使Redis客户端只需要在Twemproxy上进行操作,而不需要关心后面有多少个Redis实例,从而实现了Redis集群。
predixy Predixy 是一款高性能全特征redis代理,支持redis-sentinel和redis-cluster。
Predixy github地址:https://github.com/joyieldInc/predixy
predixy完美的实现了对redis单例模式及集群模式的支持,几乎完整的实现了redis原生的所有用于客户端的命令。多key命令、列表阻塞操作、发布订阅、脚本、扫描等高级功能全支持,在使用redis单例模式下也支持事务。
codis Codis 是 Wandoujia Infrastructure Team 开发的一个分布式 Redis 服务, 用户可以看成是一个无限内存的 Redis 服务, 有动态扩/缩容的能力.
tar -zxvf FileName.tar.gz
zip -r a.zip a.sql
Linux下的压缩解压缩命令详解及实例
实例:压缩服务器上当前目录的内容为xxx.zip文件
zip -r xxx.zip ./*
解压zip文件到当前目录
unzip filename.zip
============================
另:有些服务器没有安装zip包执行不了zip命令,但基本上都可以用tar命令的,实例如下:
tar -zcvf /home/zdzlibs.tar.gz /home/zdz/java/zdzlibs/ linux zip命令
zip -r myfile.zip ./*
将当前目录下的所有文件和文件夹全部压缩成myfile.zip文件,-r表示递归压缩子目录下所有文件.
https://www.cnblogs.com/mafeng/p/10986586.html
tar.xz文件如何解压
eg.
推荐使用7z压缩,压缩体积比zip小一半
CentOS 8安装7z压缩/解压工具
[2]
Linux下解压命令、压缩命令大全,详细教程
springMVC文件上传 1、利用Maven自动导入jar包2、前端 html 编写3、编写 java 实现4、配置文件 springMVC.xml5、演示(1)进入首页(2)选择文件(3)上传文件成功(4)文件已经在指定文件目录下(5)查看图片(6)再上传一个相同的图片 1、利用Maven自动导入jar包 <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.5</version> </dependency> 没有使用Maven的小伙伴只能自己手动导入了。
2、前端 html 编写 index.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <form th:action="@{/upload}" method="post" enctype="multipart/form-data"> <input name="file" type="file"><br> <input type="submit" value="提交"> </form> </body> </html> 注意:form表单的enctype一定要设为 multipart/form-data
multipart/form-data表示提交的数据以多段(每一个表单项一个数据段)的形式进行拼接,然后以二进制流的形式发送给服务器。可以在网页的请求体查看(审查元素)这些数据。
success.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>success</h1> </body> </html> 3、编写 java 实现 @Controller public class FileController { @RequestMapping("
springMVC文件下载 1、编写 java 实现2、html3、演示 1、编写 java 实现 @Controller public class FileController { @RequestMapping("/download") public ResponseEntity<byte[]> download(HttpSession session) throws IOException { // 获取ServletContext对象 ServletContext context = session.getServletContext(); // 获取服务器中文件的真实路径 String path = context.getRealPath("static/img/computer.png"); // 获取该文件的输入流 FileInputStream inputStream = new FileInputStream(path); // 创建字节数组 byte[] bytes = new byte[inputStream.available()]; // 将输入流读到字节数组中 inputStream.read(bytes); // 创建HttpHeaders对象设置响应头信息 MultiValueMap<String, String> headers = new HttpHeaders(); // 设置文件下载方式以及下载文件的名字 headers.add("Content-Disposition","attachment;filename="+ URLEncoder.encode("图片.png","UTF-8")); // 设置响应报文的状态码 HttpStatus status = HttpStatus.OK; // 创建ResponseEntity对象设置响应报文 ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, status); // 关闭输入流 inputStream.
目录
二进制移频键控(2FSK)
频移键控(FSK):
FSK时域波形:
相位不连续的2FSK信号:
相位连续的2FSK信号:
2FSK调制解调系统:
编辑编辑编辑 2FSK信号波形示例:
BFSK系统信号空间图:
2FSK信号的功率密度谱:
2FSK信号的功率密度谱示意图:
FSK信号的非相干检测:
2FSK信号的产生:
BFSK的特点:
相干检测:
2FSK信号的解调:
相干解调法:
正交2FSK相干检测的误比特率:
相关(匹配滤波)解调法:
包络检波解调法:
正交2FSK非相干检测的误比特率:
二进制调制解调系统的误码性能比较:
误比特率PE性能比较:
二进制移频键控(2FSK) 用二进制数字基带信号去控制正弦载波的载频称为二进制移频键控(2FSK)。此时对应于传号与空号的载波频率分别为f1及f2。
频移键控(FSK): FSK时域波形: 相位不连续的2FSK信号: 相位连续的2FSK信号: 2FSK调制解调系统: 2FSK信号波形示例: BFSK系统信号空间图: 2FSK信号的功率密度谱: 2FSK信号的功率密度谱示意图: FSK信号的非相干检测: 2FSK信号的产生: BFSK的特点: 比ASK抗错性好
同样用于语音级别的传输, 速率不超过1200bps
用于高频 (3 to 30 MHz) 无线电传输
可用于采用同轴电缆的LAN中的高频传输
相干检测: 2FSK信号的解调: 相干解调法: 正交2FSK相干检测的误比特率: 相关(匹配滤波)解调法: 包络检波解调法: 正交2FSK非相干检测的误比特率: 二进制调制解调系统的误码性能比较: 误比特率PE性能比较:
可以使用elk+FileBeat实现分布式日志收集,分布式日志收集是干嘛的 ,比如说以我们的项目为例, 每个项目都会写属于自己的一个日志文件 在springboot项目中,当我们通过java-jar指令执行, 执行完毕之后指定日志文件.每一个服务,项目都会指定日志文件 这个时候就会有一个问题 我的日志是分散的,再加上我们使用微服务项目,每个服务会有一个很多实例 也就是说当一个client来一个请求,最后你就没有办法确定你这个请求具体打在哪一个pod上了,因为会有负载均衡,很多时候如果出现问题了,我们查询日志就会很难~ 比如说我此时nginx---->用户服务,我用户服务部署了3台服务,客户端发来请求之后如果出现错误了 怎么排查,我三台机器上都去查询log日志,看那个地方出错了,我才能去进行问题的排查,这样的效率很低 分布式日志采集就是去做这个事情的,我可以通过一个组件,将这些分布式日志收集到一个地方去进行统一管理 就像日志中心一样 这样我不管我请求发送到哪一个服务上,我都可以在统一的地方对问题进行排查 我们可以通过FileBeat+elk实现分布式日志收集,将nginx或者微服务的日志全部通过filebeat这个组件进行采集 采集之后统一发给logstash,通过logstash在再将日志发送到es中借助于kibana 进行展示 es主要做日志收集的,kibana 可以做es的图形化管理, logstash和filebeat都是可以用来做日志收集的 他们可以收集很多渠道的日志 但是logstash服务比较重,它启动的比较慢,占用的资源比较多 fileBeat比较轻量级 占的资源比较少,通常来说我们单独部署logstash,用filebeat和我们的应用程序 部署在一起收集日志,将收集的日志发送到logstash上进行统一的处理,比如说做一些格式的整理,再发送到es中 日志采集 是对你的落地文件进行采集, nginx会产生日志access.log 这个nginx日志就比较适合用filebeat采集 fileBeat软件中会有一个filebeat.yml文件,我们只需要配置好 filebeat从哪里采集数据,filebeat采集的日志 发送到哪里去 filebeat采集的东西可以直接发送es上去 ,就是我不经过任何处理 可以直接发送到es 也就是input和output ---------------------------------------------------------------------->>>>>>> logstash中也有一个文件需要配置 也同样是input和output就是我需要收集filebeat的日志,然后经过filter的一些处理 过滤 输出到es @@@发送给索引为nginxlog的索引上 我们这里做一个配置 通过filebeat采集数据输入到logstash 这里做一个filter 对日志进行规整 经过这么一个过滤器 对文件进行过滤 过滤完毕之后输出到es 这里的filter的目的就是将我们的日志进行拆分,拆分成一个个字段 比如说这个就是我们的nginx 日志 这里的filter拆分的默认逻辑是这样的 filebeat进行收集nginx的.log文件,写完之后我们就会经过logstash将这一行日志 ,就是filebeat读取到的是这一行日志access.log,这一行日志经过logstash的filter拆分之后 ,(此时日志就会有对应的格式了)之后发送到es 前端访问页面--->nginx(access.log) --->经过filebeat采集 采集成一行行的文本发送给logstash logstash 进行拆分拆分完成之后形成字段。 日志采集有什么用,基本上这个日志所有项目都需要采集的,我们可以通过用es命令就可以进行排查生产问题 我们最常用的pv,uv 就可以从这个nginx的日志数据来 我的前端页面有多少次访问 uv 有多少个不同的人来访问我们的系统 这是我们去考虑我们网站的一个 受欢迎的很重要的指标 对于pv 我每一次点击就会产生这么一个日志 每一个记录就相当于一个pv,现在如果我要统计当天的pv有多少, 就是要统计 当前的nginxLog索引上在今天有多少条日志,我基于es的查询语句就可以进行统计 这就是我们今天的pv,有多少人访问我的前端页面,我们今天的pv 这就是nginx日志 每次访问nginx就会加一条日志 接下来就是要统计我们的uv,同一个人你不管点击多少次页面,都只能算一次uv, 我可以基于ip进行进行分组 我要统计当前有多少不同的ip地址 我们现在从nginx落地日志开始 基于文本收集方式统计pv 和uv 我们吧这些日志收集起来 还有没有其他用处 出了nginx访问pv和uv 这个基本上是所有项目通用的 我也可以把我们springboot项目日志进行收集, 这样以后排查问题好排查 filebeat是一个轻量级日志采集器,logstash是负责日志传输和聚合的 导入到es非关系型数据之后 用kabana做查询和展示的 在这一套技术中logstash扮演了日志传输的角色 filebeat相比较而言 filebeat比logstash更小巧简洁 可以使用filebeat代替logstash 相对而言更加简单 ,对资源消耗更加低点 filebeat主要功能就是用来采集日志的 filebeat是常用的一种 所以我们的的filebeat最核心的做法也是将日志导入到es中 ,同时用kibana做展示 logstash主要有各种过滤功能,比如说多个节点部署logstash,对资源的损耗就会多一些,替换成filebeat 对资源的损耗就会下降下来,然后再将filebeat采集的日志统一发送到logstash中去 filebeat 默认是关闭的 就是不监控任何地方的,对应监控的路径 写一个文件路径,就是监控这个路径下的 文件,将日志进行收集 然后发送到output中去 比如说我们下面就是 开启filebeat的日志收集 然后路径就是 /opt/module/log/*.
众所周知,Redis和RabbtiMQ是高并发利器,但是如何用Redis处理高并发问题呢?我们一步步来看。
先看一个秒杀Demo,设置一个库存的字段,每次执行减少1个库存。
如果是单线程访问,我们可以把热点数据设置一个key字段,保存到Redis中,如果value(库存)>0,value-1,然后再把库存数量重新设置到Redis当中。如果多线程并发访问,就会出现脏数据,也就是超卖问题。这个时候我们可以采用加同步锁解决,线程每次访问都获取锁,执行完代码别的线程才能重新获取锁
这时候基本解决单机部署的并发问题。
所以如果是单机部署项目,可以考虑直接用Redis缓存+锁机制处理!
那如果是分布式集群部署呢? 我们继续看。
synchronized在分布式集群中失效,这时我们应该想到用Redis自带的setnx key value解决同步锁失效问题。
还是设置一个锁字段名,利用setnx命令设置到Redis 中,并设置if判断,如果已存在返回flase,不存在返回true,每访问一次,value-1,再把数量重新设置回去,最后释放锁。
但是,如果如果碰见异常问题,可能执行不到释放锁,这会造成其他线程一直无法拿到锁,这时我们可以用try catch finally解决问题(finally保证重点代码块一定能执行)。但是还有问题,如果业务代码执行比较长,或者网络延迟抖动,其他线程只能等待锁释放,这时我们可以给key设置过期时间,为了保证原子性操作我们这样写。
看上去很完美,但是还有一些极端情况,比如设置过期时间10s,第一个线程执行逻辑用了10s,来不及释放锁,锁就过期了,第二个线程一看没有锁,直接对加锁,10s又没执行完,这时就会出现锁失效情况。这时我们可以考虑验证一下客户端的id,设置一个唯一的id,保证加锁和释放锁是同一个客户端。
到这,基本解决了分布式场景下并发问题。
但是如果碰见更极端的情况(finally代码块中出现问题),可能还会导致锁失效,这时我们可以考虑锁续命来解决问题。
同样,用Redis的儿子Redisson来解决分布式锁的问题,更简单。
这里就不详细解释Redisson了,给大家看下Redisson的原理图。
购买服务器 阿里云服务器
镜像 CentOS 7.9 64位
分配公网IPV4
密钥对(创建密钥对)
部署nuxt项目 手动部署 代码:https://gitee.com/olhong/learn-project/tree/master/part3/fed-e-task-03-03/realworld
打包项目 npm run build
启动打包结果 npm run start
本地查看启动的项目
配置Host+Port
在项目的nuxt.config.js中配置
server: {
host: '0.0.0.0',
port: 3000
}
压缩发布包
.nuxt static nuxt.config.js package.json package-lock.json -> nuxt-realwork.zip
把发布包传到服务端
连接服务器(可使用xshell 或 阿里云自带的连接工具)
命令行连接 ssh root@ip地址 输入密码即可
创建目录 mkdir realword-nuxtjs
退出连接 exit
上传文件 scp scp .\nuxt-realwork.zip root@47.96.24.44:/root/realwork-nuxtjs
解压
连接到服务器,安装unzip命令
yum install -y unzip zip
解压文件夹
unzip nuxt-realwork.zip
安装依赖
安装nvm
// 执行任意一行命令 curl -o- https://raw.
三斜杠指令是包含单个XML标记的单行注释。注释的内容被用作编译器指令。
三斜杠指令只在包含它们的文件的顶部有效,即在任何注释、语句或声明之前,不然它们会被当作普通的单行注释,无任何特殊含义。
/// <reference path="..." /> 该指令用于声明文件之间的依赖关系,指示编译器在编译过程中包含其他额外文件。path指定的路径如果是相对路径,则是以当前文件为根。
编译器会从根文件开始解析该指令,以深度优先的方式,递归地找到所有编译文件。值得注意的是,根文件必须是由tsconfig.json文件中的files或include指定。根文件可以是多个文件,在/// <reference path="..." />中引入不包含在tsconfig.json配置中的文件。
// other/other.ts console.log('log:other.ts'); /// <reference path="../other/other.ts" /> // print/print.ts console.log('log:print.ts'); export function hello() { console.log('log:Function::hello'); } /// <reference path="print/print.ts" /> // index.ts console.log('log:index.ts'); hello(); 是否编译后的文件一定会执行呢? 这取决于你的运行环境,和组织代码的方式。
当在浏览器环境中运行代码时,如果你编译后的js文件,都通过script标签加载到了网页中去,理所当然这些文件都会被运行。在上面的示例代码中,要在index.ts文件运行hello方法,则网页中通过script标签加载的print/print.js文件必须放在index.js文件之前。
在node环境中,即在本地环境通过node运行编译后的index.js文件,你会发现找不到hello方法的保存。在此环境中,你必须使用require(import)来导入需要的引用。在使用typescript的情况使用import语句后,不需要/// <reference path="..." />也能让编译器识别到被import的文件。
事实上,reference指令的目的是告诉程序可用的function、type或interface的类型,它与声明更加相关。
其他reference指令 /// <reference types="..." /> 声明对包的依赖,如/// <reference types="node" />
/// <reference lib="..." /> 显式地包含一个现有的内置lib文件,如lib="es2015"
/// <reference no-default-lib="true"/> 这个指令将一个文件标记为默认库。在lib.d.ts的顶部可以看到此注释。
/// <amd-module /> 默认情况下,AMD模块是默认生成的。在使用其他工具处理生成的模块时,可能会出现问题。所以该指令允许将可选模块名传递给编译器。
参考资料 stackoverflow:Typescript ///: why doesn’t it work for me?
我们都知道最新的HTML5中支持了画布操作,可以在上面绘制各种二三维图形图像,相应的H5标签就是<canvas>
二维图形绘制:Canvas API和WebGL API,三维图形绘制:WebGL API。
一.WebGL定义:webgl是一种3D绘图库及框架协议,衍生自OpenGL ES2.0,可结合H5和js实现在web端进行二三维图形的渲染和交互,未来支持可穿戴设备的沉浸式渲染交互。
二.WebGL用途:主要应用于数据可视化,图形可视化引擎或在线游戏引擎。
三.WebGL优势:
1.内置在任意浏览器中,几乎每台电子产品都都相应的浏览器支持,无需安装任何插件。
2.几乎不需要任何编程环境,可以用vim或者记事本即可快速编写三维图形程序。
3.快速上手入门,快速呈现效果。
四.WebGL呈现形式:webgl的GLSL ES是以字符串形式存在于javascript,所以整体需用一个单引号括起来的。也可以用后缀名为glsl文件将webgl代码单独存放,然后在js中引入进来,具体引入代码如下:
import waterVertexShader from './shaders/vertex.glsl';//顶点着色器 import waterFragmentShader from './shaders/fragment.glsl';//片元着色器 五.WebGL坐标系和绘图区域(0点在整个画布的正中心)
六.WebGL绘制流程和不同类型变量的设置流程
七.WebGL缓冲区对象的获取配置流程
可以将同一个缓冲器对象不同部分数据设置到着色器变量中。
八.着色器之间传递数据的方式
利用varying类型的变量绘制图形,在顶点着色器和片元着色器中都要声明varying变量,并且一致,在顶点着色器向片元着色器传递数据,并在片元着色器中使用。详见示例2。
varying vec4 vColor;
执行流程
九.3D图形绘制基础
三维图形在屏幕上绘制需要了解以下几个知识点,分别为视点、目标点、上方向,三者的相对关系如下:
任何一个立体图形要被观察到,其实是被人为的投影到观察平面后形成的,观察平面与物理图形之间的关系如下。
具体实现详见下方示例2。
十.WebGL典型示例
0.公共引用的index.js文件
function initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE) { const vertexShader = gl.createShader(gl.VERTEX_SHADER); const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(vertexShader, VERTEX_SHADER_SOURCE) // 指定顶点着色器的源码 gl.shaderSource(fragmentShader, FRAGMENT_SHADER_SOURCE) // 指定片元着色器的源码 // 编译着色器 gl.compileShader(vertexShader) gl.compileShader(fragmentShader) // 创建一个程序对象 const program = gl.createProgram(); gl.
一、拼接窗口(Snap windows) 拼接在一起的窗口可以让同时重新设置两个窗口的大小,这样比较方便。
方法一:选择你想要的窗口,往左边或右边拖动,直达你的鼠标到达屏幕(整个)的边界。会出现图下的虚拟便捷显示,释放鼠标左键。此界面会占据一半的屏幕,再选择另一个窗口,两个界面就拼接在一起了,可以在中间的界线同时改变两个窗口的大小。
方法二:win+<–(左方向键)或者win±->(右方向键),第一次会调整大小,第二次可以选择另一个窗口拼接
注:目前只能实现两个窗口拼接。当你把窗口往 左上角、左下角、右上下角四个方向拖动(操作类似),窗口会占1/4的大小,但是没有拼接在一起,不能同时改变大小。
二、快速切换窗口(Flip windows) 可以在方便在多个窗口之间切换切换的快捷键。按住Alt键,然后在按Tab键就可以进行选择你想要的窗口了。
在需要频繁切换两个窗口的时候很实用。
三、任务视图(Task View) 按下任务栏的一个名为任务视图的图标,
或是按快捷键Win+Tab,就会把所有的窗口显示出来。
四、虚拟桌面(Virtual desktops) 在任务视图(Task view)里可以建立虚拟桌面。
注意:这里打开的桌面上的内容是会同步的,只是任务栏上的窗口会保持其独立性。
五、显示桌面(Showing The Desktop) 在打开了很多的窗口时候想要切换到桌面有几个快捷的方法。
1.右键点击任务栏,再点击显示桌面即可。
2.快捷键:Win+D
3.点击整个桌面右下角的最角落即可。如图所示:
六、WIndows与桌面功能相关的实用小工具 4、Clover clover:像浏览器一样使用桌面标签(可以收藏、打开多个tab)很方便。并且 Ctl-w(关闭当前)等快捷键与浏览器一样。。。 1.DeskPins 功能:软件大小几百KB,可以把自己需要置顶的窗口一直置顶在所有窗口最上层。
2.多窗口文件整理工具(Q-Dir) 功能:一次开十几个文件窗口,分成4个小界面,对于需要频繁打开不同文件夹的工作。是十分便捷的。
3.RightMenuMgr 鼠标右键管理工具 1.使用前 2.使用后 不用搞复杂的注册表,直接软件无脑修改。
tips:可以轻松给右键添加上“用记事本打开”,方便查看文本类的各种文件。
遇到问题:遇到了右键桌面图标卡死的情况,
大概原因:右键菜单被某个程序添加了右键菜单,而它又加载缓慢,导致资源管理器一直在等待。
解决办法:用RightMenuMgr软件,把右键的一些软件绑定给清楚了,然后就不卡了。。。
四、待补充 。。。。。。。
。。。。。。。
七、参考文档 https://edu.gcfglobal.org/en/windows10/tips-for-managing-multiple-windows/1/
一、IIS
①、x86部署问题
1、错误信息(附截图):Failed to start application '/LM/W3SVC/15/ROOT', ErrorCode '0x800700c1'.
2、错误信息(附截图):Could not find 'aspnetcorev2_inprocess.dll'. Exception message:
3、错误信息(附截图):Unable to load 'D:\apricot\.\hostfxr.dll'. This might be caused by a bitness mismatch between IIS application pool and published application.
4、问题处理及解决:IIS应用程序池【项目对应程序池】->高级设置->启用32位应用程序=>true
②、
二、
①、
Docker轻量级可视化工具Portainer 一、安装 Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。
一、安装 官网: https://www.portainer.io/
官网安装:https://docs.portainer.io/start/install/server/docker/linux
Docker命令安装(官方)
这里用的是社区版,企业版要通信证
# 创建Portainer Server将用于存储其数据库的卷: docker volume create portainer_data # 如果需要https就开放9443,不开9000 # --restart=always 这个命令的意思就是 docker重启这个容器实例也重启,保持开机自启动 docker run -d -p 8000:8000 -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest 第一次登录需创建admin,访问地址:你的IP:9000 (如果是https就访问9443)
这里服务器记得放行安全组以及防火墙的端口
这里密码是8位的,随便设
可以图像化的操作
问题
docker容器实例重新启动后容器状态为 Restarting(1),没有端口的信息
问题来源,由于Portainer数据的数据卷挂载,已经存在了,导致实例还是原有的配置数据卷,也就是重启的感觉,然后端口就可能会有占用不显示,可以重新运行可以不需要在进行命令配置或者删除原有的数据卷,重新设置
解决:删除实例,查看数据卷进行删除重新运行实例
docker stop 实例ID #删除所有容器实例 docker rm 实例ID #查看数据卷 docker volume ls #删除数据卷 docker volume rm 数据卷名字