先上个图吧
关于使用
可先用文本框放入合适位置然后引用自带函数
这里需要注意的是当选择Now时显示的是当前页
当选择Report时显示的是总页数
1.module简介
module是一个专门管理环境变量的工具,全程是module environment,一般应用于软件或运行库等设备有多个版本,且需要分别配置这些环境变量。
2.module工具的官网
module官网https://modules.readthedocs.io/en/latest/index.html
3.module的安装
Moudle工具是基于TCL(8.4以上版本)工具的。Moudle工具可以使用二进制编译安装,也可以使用yum/apt快速安装,
module工具,依赖tcl工具,因此首先要安装tcl工具。
wget https://cfhcable.dl.sourceforge.net/project/tcl/Tcl/8.5.9/tcl8.5.9-src.tar.gz
tar -zxvf tcl8.5.9-src.tar.gz
cd tcl8.5.9/unix
./configure --prefix=/usr/local/tools/tcl
make
make install
安装tcl之后,就可以安装module工具了。
wget https://newcontinuum.dl.sourceforge.net/project/modules/Modules/modules-4.2.4/modules-4.2.4.tar.gz
tar -zxvf modules-4.2.4.tar.gz
cd modules-4.2.4
./configure --prefix=/usr/local/tools/modules --with-tcl-lib=/usr/local/tools/tcl/lib --with-tcl-inc=/usr/local/tools/tcl/include
make
make install
安装完成之后,在/usr/local/tools/modules目录下,就有module工具了。不过在bin目录下,是没有module这个命令的。
4.module的初始化
安装module工具后,你会发现它并不是一个可执行的二进制文件,你需要对module工具进行一次初始化。
在/usr/share/modules/init(注意此处,可能是module也可能是modules)内部你可以找到针对各个脚本的二进制初始化文件,有profile.sh和profile.csh文件,用来配置module的脚本文件。如果当前用的shell是bash,就使用profile.sh,如果当前用的shell是cshell,就使用profile.csh。可以直接source这个文件,也可以打开/etc/profile文件,加入 source /usr/llocal/tools/modules/init/profile.©sh 这一行代码。重启终端,使用module -h,就可以打印module命令的help了。也可以建立符号链接,这样当系统重启后,会自动加载。
ln -s /usr/local/tools/modules/init/profile.sh /etc/profile.d/module.sh ln -s /usr/local/tools/modules/init/profile.csh /etc/profile.d/module.csh 不过如果使用which module,会发现找不到module命令。
5.Moudle工具的使用
Module工具依托于MODULEPATH这个环境变量来查找配置信息目录,也就是说你在设置好目录结构,配置好环境变量后,只需要设置这一个module的环境变量,那么module工具就会自动去查找这个路径下的所有配置信息。export MODULEPATH=/opt/modulefiles
例如这个工具文件modulefiles放在了/opt下面,编写的modulefiles文件放在目录/opt/modulefils/gcc/4.8.4和/opt/modulefiles/gcc/4.9.7下。
6.modulefiles文件编写
以下是 modulefiles目录下的 modules文件,我们后面实现的工具配置文件,都是基于这个文件进行修改。千万不要出现软件名和版本一样的modulefile。
#%Module1.0##################################################################### ## //#%Module1.0 这个是识别这个文件为modulefile的,没有他这个文件不会被识别。 ## modules modulefile ## proc ModulesHelp { } { //proc:帮助文件,可以要,也可以不要 global version prefix puts stderr "
文章目录 一、设置窗体的背景图二、设置Button组件三、设置字体大小和颜色四、设置组件的背景色五、综合测试案例 一、设置窗体的背景图 利用JLable类的构造方法或方法加载图片
ImageIcon image = new ImageIcon("D:\\背景.jpg"); JLabel jlable = new JLabel(image); // JLabel jLabel = new JLabel(); // jLabel.setIcon(image); 当我们需要设置窗体的背景图,并将一些组件放到背景图上时,发现组件并不会显示出来。此时我们可以使用JLayeredPane类来实现。
// 创建一个JLayeredPane用于分层的。 JLayeredPane layeredPane = new JLayeredPane(); // 获取图片 ImageIcon image = new ImageIcon("D:\\背景.jpg"); // JLabel用于存放背景图片,作为背景添加到JPanel上 JLabel jlable = new JLabel(image); // 创建JPanel,并将JLabel添加 JPanel jpanel = new JPanel(); // 设置JPanel大小为背景图片大小 jpanel.setBounds(0,0,image.getIconWidth(),image.getIconHeight()); jpanel.add(jlable); JButton button=new JButton("hello"); button.setBounds(0,75,200,75); //将jpanel放到JLayeredPane的最底层 layeredPane.add(jpanel,JLayeredPane.DEFAULT_LAYER); //将button放到jpanel高一层的地方 layeredPane.add(button,JLayeredPane.MODAL_LAYER); //设置窗体 this.setLayeredPane(layeredPane); this.setSize(image.getIconWidth(),image.getIconHeight()); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); 二、设置Button组件 # 将按钮填充的背景图改为透明 button1.
互联网上存在海量的数据,各式各样的数据每天展现在我们面前,同时众多的金融、医学和计算机等学科的研究课题,都需要获取众多的数据作为样本进行科学分析,传统的人工采集操作根本上很难胜任数据采集,即便是能够收集也需要耗费众多的时间成本,自动化网站采集应用而生。一般采集数据是各种客户端所呈现的结构化数据,例如浏览器,APP等。数据存储在客户端。采集数据不会在服务器端采集,一方面比较困难,另外这也是一种违法行为。很多客户端也要求提供验证,如用户名密码等。
网站采集的原理基本一致,例如国内用的比较多的采集器某头、某鱼等,首先由客户端发出请求,服务器接受请求后再返回相应的数据,而采集器就从返回的数据中找到对应的数据。采集器根据采集要求自动发出不同的请求,例如模拟人的点击过程或者自定规则。网站的数据获取非常依赖数据的结构,必须根据不同的数据结构制定不同的采集规则。基本上每个网页的数据结构都不同,因此必须根据具体的网页来制定规则。
下面以某网站的一个页面为例,说明下网站数据采集的过程。
确定需要获取数据的网页 网页的结构如下图所示,这是个微信小程序源码的下载页面,需要获取如下内容:1 源码名称(仿天猫首页);2 获取模板截图的地址
2.获取相应的元素信息
这个比较简单,在浏览器中按F12就可以查找到相应的元素。本页面的元素信息如下:
源码名称:
元素的类名pins-title在本页是唯一的;
模板截图:
元素的类名pins-info在本页是唯一的;
(三)在程序中实现内容的获取
使用QWebEngine实现对网页的操作。
第一,为QWebEngineView设置网页的地址,并登录网站,具体实现可自行搜索下,网上很多;
第二,书写javascript代码,从而能获取指定元素的内容,代码如下,后面的ret是为了方便输出的参数:
QString jscode = "var i,title,elements,imgs='',ret='';" "elements = document.querySelectorAll('.pins-title strong');"
"title = elements[0].innerText;"
"elements = document.querySelectorAll('.pins-info .text img');"
"for(i=0;i<elements.length;i++){imgs += elements[i].getAttribute('src');imgs+=',';};"
"ret = 'title=';"
"ret += title;"
"ret += '&';"
"ret += imgs;"
"ret;";
运行javascript代码:
web_view->page()->runJavaScript(jscode,[this](const QVariant& v){qDebug()<<v.toString();});
运行结果如下:
结果可交由主程序处理,例如存入excel表、数据库等。
CentOS
1、查找僵尸进程命令:
ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]'
[root@CentOS7 ~]# ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]' Z 1033 2717115 [python] <defunct> 说明:因为状态为 z或者Z 的进程为僵尸进程,所以我们使用grep抓取stat状态为zZ进程
2、批量干掉僵尸进程命令:
ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]' | awk '{print $2}' | xargs kill -9
[root@CentOS7 ~]# ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]' | awk '{print $2}' | xargs kill -9 说明:干掉单个进程可使用 kill -9 2717115 如果有多个僵尸进程,就是用批量杀掉进程
效果:
代码:
#ifndef TIMELINECONTROLSWIDGET_H #define TIMELINECONTROLSWIDGET_H #include <QWidget> #include <QDate> class QPainter; class TimelineControlsWidget : public QWidget { Q_OBJECT public: TimelineControlsWidget(QWidget *parent = nullptr); ~TimelineControlsWidget()override; protected: void paintEvent(QPaintEvent *event)override; private: void drawYearCircle(QPainter * painter, int x, int y); void drawSmallCircle(QPainter * painter, int x, int y); QList<std::pair<QDate,QString>> infoList; }; #endif // TIMELINECONTROLSWIDGET_H #include "timelinecontrolswidget.h" #include <QPainter> #include <QPaintEvent> TimelineControlsWidget::TimelineControlsWidget(QWidget *parent) : QWidget(parent) { setPalette(Qt::white); infoList << std::make_pair<QDate,QString>(QDate(2021,10,1),"国庆节放假"); infoList << std::make_pair<QDate,QString>(QDate(2021,8,1),"
概要:对移动云云手机产品的产品概述、产品优势、适用场景、功能特性进行介绍
云手机
一、产品概述
移动云云手机基于 ARM 服务器虚拟化技术,通过 APP、H5 为用户提供安全便捷的安卓手机服务,提 供和真机一样的云端资源(包括 CPU、内存、存储空间)以及安卓 ROM。打破了传统手机存储、性能、 续航的限制,可用于移动办公、仿真测试、家庭娱乐等场景。
二、产品优势
1、安全可靠
应用在云端运行、数据在云端存储,为用户提供安全可 靠的数据迁移能力。
2、方便快捷
支持App客户端、H5等形式使用虚拟云手机,即开即 用、接入便捷、操作灵活,通过App进入后尽享与真机 一致的操作体验。
3、集中管控
统一集中管理企业全部云手机,实现设备、应用、用户 的管理,支持批量操作、统一控制。
4、一机多用
支持本地手机与云端虚拟手机信息共享、无缝切换,支 持上传本地应用、文件,支持调用真机摄像头能力,实 现一机多用、提高资源利用率。
三、适用场景
移动办公、仿真测试、家庭娱乐
四、功能特性
1、支持多种规格云手机
移动云云手机提供基础型、商务型、旗舰型、娱乐型四种规格的云手机,满足用户不同手机规格需求,支持用户按需扩缩容以及变 更手机配置。
2、支持多终端接入
可通过安卓版本App、小程序/H5、PC客户端接入,访问便捷。
3、支持手机多开
可针对办公、仿真、娱乐等不同场景开通多台云手机,且多台云手机可快捷切换。
4、支持集中管控
可通过租户管理平台企业多台云手机对进行集中控制、统一管理。
5、具备拟真机能力 具备摇一摇、扫一扫、截屏等常见真机功能。
作者:倪蓓露
链接: https://ecloud.10086.cn/api/query/developer/user/home.html?ticket=ST-7179-Jhem0Myd4NmqdlwEK4He-cas01.example.org#L2FwaS9xdWVyeS9kZXZlbG9wZXIvYmxvZy9ibG9nZGV0YWlsLmh0bWw/YmxvZ19pZD03MDIzMWE4ZTliMjI0ZWM3YjY0YzI3ZmM3NTE2YjA5Nw==
来源:移动云开发者社区
概要:VMware是当前主流的桌面虚拟化厂商之一,VMware vSphere是VMware套件的商业名称,包含了虚拟化、管理和界面等。VMware官方提供了vSphere Web Service SDK方便开发者客户端开发,调用vmware API进行开发,vSphere Web Services SDK是目前api中最全面的。本文主要根据官方的sdk、官方的guid文档和网上的分享展开sdk的编程学习。sdk源码提供c#和java两种编译方式,本文主要使用java进行相关说明。
ws超时设置 vmware vcenter sdk提供的接口都是通过ws的形式,默认设置的超时时间是60秒,实际操作底层资源的时候很容易就会返回类似read time out这样的错误,需要手动设置下ws的超时时间。
Map var1 = ((BindingProvider)basicConnection.getVimPort()).getRequestContext(); var1.put("com.sun.xml.internal.ws.connection.timeout", 3600000); var1.put("com.sun.xml.internal.ws.request.timeout", 3600000); 获取MOR信息 访问网址https://vcenterIP/mob/?moid=MOR可以获得目标引用下的相关属性和方法,如下图所示:
获取host引用下的configManger的代码示例
final GetMOREF getMOREF = new GetMOREF(connection); final HostConfigManager configManager =(HostConfigManager) getMOREF.entityProps(host, new String[]{"configManager"}).get("configManager"); 当获取的内容是数组时:
final GetMOREF getMOREF = new GetMOREF(connection); final ArrayOfHostVirtualNic hostVirtualNicArray = (ArrayOfHostVirtualNic) getMOREF.entityProps(networkSystem,new String[]{"networkInfo.vnic"}).get("networkInfo.vnic"); 获取根目录下的数据中心:
BasicConnection basicConnection=initConnection(); GetMOREF getMOREF=new GetMOREF(basicConnection); //获取数据中心MAP Map<String, ManagedObjectReference> dcResults = getMOREF.inFolderByType(basicConnection.getServiceContent().getRootFolder(), "Datacenter", new RetrieveOptions()); 简单示例 通过mob页面我们可以看到host下设置的虚拟网卡和分布式交换机,我们通过代码来删除这些虚拟网卡和交换机,方便后续主机迁移操作
概要:由于移动云桌面市场前景较好,各区域大力支持下,售卖率较高,同时带来了一些并发的问题,由于一个CS最多支持2000个并发会话,为了满足云桌面客户的并发量,我参照官方推荐,使用VAI作为CONNECTION SERVER 和 UAG的负载均衡,并对AVI进行了UAG和CS 负载均衡的POC。
一、有关Horizon View 使用AVI做负载均衡的POC试验 移动云云桌面Horizon架构:
1.前期网络规划 地址类型地址规划AVI Controller01 管理地址172.20.254.235Service Engine 管理地址172.20.254.116-172.20.254.119Horizon CS01 业务地址192.168.253.200Horizon CS02 业务地址192.168.253.199Horizon CS VIP 业务地址192.168.253.150UAG01业务地址192.168.253.249UAG02业务地址192.168.253.248UAG VIP业务地址192.168.253.250 2.Application中创建Cloud(基于VMware) Cloud 是安装或运行Avi Vantage的环境的容器 在基础架构Infrastructure页面中创建Clouds
点击创建按钮
DateCenter中选择 对应数据中心
配置相关网络
设置或者新建Service Engine Group Service Engine是在一个组中创建的,Service Engine Group包含se应该如何调整大小、如何放置以及如何使其高度可用的定义。每个Cloud将至少有一个SE组。每个Service Engine可能只存在于一个组中。每个组充当一个隔离域。一个Service Engine Group中的Service Engine资源可能会被移动以容纳虚拟服务,但是Service Engine Group之间永远不会共享SE资源 。
记得选择对于的Cloud ,Service Engine Group 是所以唯一的Cloud下的,点击创建
其中High Availability Mode 有3中高可用模式:
Active/Standby: 两台 Service Engine 其中一主一备,只能创建两个业务引擎。对于一个服务器上的每个活动的虚拟服务,另一个服务器上都有一个配置好的备用服务,备用服务可以在活动SE发生故障时接管。在这种HA模式下没有服务引擎扩展Active/Active:这种HA模式将虚拟服务分发到至少两个Service EngineN + M (buffer): 这种默认模式允许至多N个活动SE提供虚拟业务,其容量相当于组内M个Service Engine随时准备吸收Service Engine的故障 高级配置中 选择 Service Engine 虚拟机命名浅醉、所属VC文件夹、集群和主机信息
今天在系统上做了一个功能
我看着这个简陋的页面,心说,这个系统地址,能不能做成链接样式,当点击的时候,就跳转过去。
然后,我发现公司没有前端工程师。
而我又完全不懂Vue,没办法,只能硬着头皮上了。
<el-table-column label="系统地址" align="center" prop="subnetUrl" /> 前端显示的代码如上,好像是个很普通的column,反正我也不知道是怎么回事。
然后我就找找有没有链接样式的页面。
别说,嘿,还真在另外一个页面找到了,如下:
<el-table-column label="字典类型" align="center" :show-overflow-tooltip="true"> <template slot-scope="scope"> <router-link :to="'/system/dict-data/index/' + scope.row.dictId" class="link-type"> <span>{{ scope.row.dictType }}</span> </router-link> </template> </el-table-column> 话不多说,直接扒下来。
扒,就硬扒,霸王硬上弓。
咱也不敢问,反正不懂,粘贴上去就是改。
我改了半天,就改成了这个样子。
<!--<el-table-column label="系统地址" align="center" prop="subnetUrl" />--> <el-table-column label="系统地址" align="center" :show-overflow-tooltip="true"> <template slot-scope="scope"> <router-link :to= scope.row.subnetUrl class="link-type"> <span>{{ scope.row.subnetUrl }}</span> </router-link> </template> </el-table-column> 心里美滋滋。
运行走一波,试试。
哎妈呀,它行了,它真的行了。
卧槽,我太猛了!
点击一下试试。
兜头就是一盆凉水,当时我拔凉拔凉的。
咋回事啊?
我把鼠标放到链接上,发现了一个诡异的问题
为啥前面会加上 localhost 啊!
我对于Vue一窍不通,直接上官网看文档去。
官网链接:https://v3.cn.vuejs.org/
Vue源码Github地址:https://github.com/vuejs/docs-next-zh-cn
我找了半天,找到了这样一段话,
H3C交换机配置文件用FTP方法备份和恢复,使用SecureCRT,SecureFX对交换机配置文件进行备份和恢复非常方便。
设置Host_1与Host_2网卡IP,网卡选 VirtualBox Host-Only Ethernet Adapter 和 VirtualBox Host-Only Ethernet Adapter #2
Ip:192.168.10.81和192.168.10.82 与本机IP网段相同。
设置S6850_1交换机用户admin,密码 abcd123456 ,服务类型 FTP ,开通FTP服务和
设置IP:192.168.10.11
打开SecureCRT软件,按图中顺序连接交换机S6850_1,在第4步填入参数 \\.\pipe\topo1-device1
连接后
输入
<H3C>system-view System View: return to User View with Ctrl+Z. [H3C]local-user admin //添加用户 New local user added. [H3C-luser-manage-admin]password simple abcd123456 //设置密码 [H3C-luser-manage-admin]authorization-attribute user-role level-15 //设置用户级别 [H3C-luser-manage-admin]service-type ftp //设置用户可以使用FTP服务 [H3C-luser-manage-admin]quit [H3C]ftp server enable //开启交换机的FTP服务 FTP is insecure because it transmits data in plaintext form. [H3C]interface Vlan-interface 1 //进入VLAN1虚拟接口 [H3C-Vlan-interface1]IP address 192.
本人小白入门,不到之处请大侠指点!!!
先观察题目的提示,(由于是新生赛,所以提示比较明显)显然是需要我们用SQLMAP进行操作。
不妨输入 用户名 1 密码 1' or '1'='1 来进行简单的测试,果然登陆上了。但是返回的是“登陆成功”并没有返回数据库中的内容,于是也可以尝试尝试sql盲注的思路。
一、sqlmap解法 sqlmap的基本命令:Kali Linux 漏洞利用工具集 sqlmap 教程 - 付杰博客
某大神的sqlmap学习笔记:Kali Linux学习笔记—SQLMAP 自动注入_江河湖海:D的博客-CSDN博客
这里列举几个常用的操作命令:
-dbs 获取所有数据库
--current-db 当前使用的数据库
--users 所有用户
--current-user 数据库使用账户
--is-dba 当前用户权限(是否为root权限)
--passwords 数据库账户与密码
-D 数据库名 --tables 查看指定数据库的所有表
-D 数据库名 -T 表名 --columns 查看指定数据库指定表的所有字段
-D 数据库名 -T 表名 -C 字段名 -dump 查看指定字段所有的值
--random-agent 构造随机user-agent
--time-sec=TIMESEC DBMS响应的延迟时间(默认为5秒)
下面来写写这个题目,用sqlmap的解决方案(sqlmap的最最最最基础的操作)
首先看看存不存在注入点
sqlmap -u "http://xxxx" -dbs
再看看,所连接的数据库有哪些
进入users数据库,看看有哪些表
sqlmap -u "http://xxxx" -D users --tables
❝ 码哥你又送书呀,简直就是「送书童子」,String 还能优化啥?你是不是框我?
莫慌,今天给大家见识一下不一样的 String,从根上拿捏直达 G 点。
并且码哥分享一个例子:通过性能调优我们能实现百兆内存轻松存储几十 G 数据。
String对象是我们每天都「摸」的对象类型,但是她的性能问题我们却总是忽略。
爱她,不能只会简单一起玩耍,要深入了解String 的内心深处,做一个「心有猛虎,细嗅蔷薇」的暖男。
通过以下几点分析,我们一步步揭开她的衣裳,直达内心深处,提升一个 Level,让 String 直接起飞:
字符串对象的特性;
String 的不可变性;
大字符串构建技巧;
String.intern 节省内存;
字符串分割技巧;
String 身体解密 想要深入了解,就先从基本组成开始……
「String 缔造者」对 String 对象做了大量优化来节省内存,从而提升 String 的性能:
Java 6 及之前 数据存储在 char[]数组中,String通过 offset 和 count两个属性定位 char[] 数据获取字符串。
这样可以高效快速的定位并共享数组对象,并且节省内存,但是有可能导致内存泄漏。
❝ 共享 char 数组为啥可能会导致内存泄漏呢?
String(int offset, int count, char value[]) { this.value = value; this.offset = offset; this.count = count; } public String substring(int beginIndex, int endIndex) { //check boundary return new String(offset + beginIndex, endIndex - beginIndex, value); } 调用 substring() 的时候虽然创建了新的字符串,但字符串的值 value 仍然指向的是内存中的同一个数组,如下图所示:
目录
前言
一、实现思路
二、功能实现
1.下载所用到的第三方库
2.代码实现
三、实现跨网段控制
四、结语
前言 写程序的时候或遇到电脑中一些问题,有时候会去下载专门的软件去远程协助。但是我想用程序自己去实现远程控制桌面的功能。原以为网上到处都是,结果找了好几天,要么文章杂乱无序,要么都要结合微信等等。
于是我只能在众多代码中百里挑一选取自己需要的那一小部分,然后不断地拼凑,不断地理解大神的代码,最终做出这么一个远程控制桌面功能。我热泪盈眶地望着写好的代码,中间好几次拼不对或遇到bug导致程序无数次崩溃,差点就想放弃了......
以下是参考网站的名单:
1.全网最全免费内网穿透映射工具教程:https://www.bilibili.com/video/BV1Ja4y1J7Fj?
2.配套博客地址:https://www.it235.com/实用工具/内网穿透/pierce.html
一、实现思路 1. 你和对方建立一个Socket链接(协议是tcp/ip这种有状态协议)
2. 对方系统会在这个socket链接上实时给你发送目前他截屏到的图像和系统状态数据 3. 你收到数据,程序解析出相对的命令和发送来的图像
4. 通过这个命令来达到本机还原操作和控制效果(包括图象,鼠标和键盘等等)
5. 然后重复流程2,循环反复
二、功能实现 1.下载所用到的第三方库 如何下载慢或报错超时后面加上镜像地址 -i https://pypi.douban.com/simple/
例如:pip install numpy==1.21.2 -i https://pypi.douban.com/simple/
pip install numpy==1.21.2 pip install pywin32==302 pip install Pillow==8.4.0 pip install mouse==0.7.1 pip install keyboard==0.13.5 pip install opencv-python==4.5.3.56 2.代码实现 全代码在本文末尾相关资源中
控制端control.py主运行函数
def main(): lenb = soc.recv(5) imtype, le = struct.unpack(">BI", lenb) imb = b'' while le > BUF_SIZE: t = soc.
各位,如果你的职业是开挖掘机,你说要不要深入理解挖掘机?通常来说,深入理解你操纵的机器才能最终达到人机一体的境界。
当然,你可以说:不用,因为如果挖掘机不好使,我可以换一台。嗯,也有道理。不过,假如你同时又是一名前端开发者,那你要不要深入理解浏览器呢?注意,身为前端,你不太可能有机会因为浏览器不好使就强迫用户换一个你认为好使的。这时候,你好像别无选择了。
不过也不用害怕,今天我们的现代浏览器深度游会非常轻松、快乐。这首先必须感谢一位名叫Mariko Kosaka(小坂真子,https://kosamari.com/)的同行。她在Scripto工作,2018年9月在Google开发者网站上发表了“Inside look at modern web browser”系列文章。本文就是她那4篇文章的“集合版”。为什么搞这个“集合版”?因为她的4篇文章写得实在太好,更难得的是人家亲手绘制了一大堆生动的配图和动画,这让深入理解现代浏览器变得更加轻松愉快。
好了,言归正传。本文分4个部分,对应上述4篇文章(原文链接附后)。
架构:以Chrome为例,介绍现代浏览器的实现架构。导航:从输入URL到获到HTML响应称为导航。渲染:浏览器解析HTML、下载外部资源、计算样式并把网页绘制到屏幕上。交互:用户输入事件的处理与优化。 先来个小小的序言。很多人在开发网站时,只关注怎么写自己的代码,关注怎么提升自己的开发效率。这些当然重要,但是写到一定的阶段,就应该停下来想想:浏览器到底会怎么运行你写的代码。如果你能多了解一些浏览器,然后对它好一点,那么就会更容易达成你提升用户体验的目标。
架构 Web浏览器的架构,可以实现为一个进程包含多个线程,也可以实现为很多进程包含少数线程通过IPC通信。如何实现浏览器,并没有统一的标准。Chrome最新的架构:最上层是浏览器进程,负责协调承担各项工作的其他进程,比如实用程序进程、渲染器进程、GPU进程、插件进程等,如下图所示。
渲染器进程对应新开的标签页,每新开一个标签页,就会创建一个新的渲染器进程。不仅如此,Chrome还会尽量给每个站点新开一个渲染器进程,包括iframe中的站点,以实现站点隔离。
下面详细了解一下每个进程的作用,可以参考下图。
浏览器进程:控制浏览器这个应用的chrome(主框架)部分,包括地址栏、书签、前进/后退按钮等,同时也会处理浏览器不可见的高权限任务,如发送网络请求、访问文件。渲染器进程:负责在标签页中显示网站及处理事件。插件进程:控制网站用到的所有插件。GPU进程:在独立的进程中处理GPU任务。之所以放到独立的进程,是因为GPU要处理来自多个应用的请求,但要在同一个界面上绘制图形。 当然,还有其他进程,比如扩展进程、实用程序进程。要知道你的Chrome当前打开了多少个进程,点击右上角的按钮,选择“更多工具”,再选择“任务管理器”。
Chrome的多进程架构有哪些优点呢?
最简单的情况下,可以想像一个标签页就是一个渲染器进程,比如3个标签页就是3个渲染器进程。这时候,如果有一个渲染器崩溃了,只要把它关掉即可,不会影响其他标签页。如果所有标签页都运行在一个进程中,那只要有一个标签页卡住,所有标签页都会卡住。
除此之外,多进程架构还有助于安全和隔离。因为操作系统有限制进程特权的机制,浏览器可以借此限制某些进程的能力。比如,Chrome会限制处理任意用户输入的渲染器进程,不让它任意访问文件。
由于进程都有自己私有的内存空间,因此每个进程可能都会保存某个公共基础设施(比如Chrome的JavaScript引擎V8)的多个副本。这会导致内存占用增多。为节省内存,Chrome会限制自己可以打开的进程数量。限制的条件取决于设备内存和CPU配置。达到限制条件后,Chrome会用一个进程处理同一个站点的多个标签页。
Chrome架构进化的目标是将整个浏览器程序的不同部分服务化,便于分割或合并。基本思路是在高配设备中,每个服务独立开进程,保证稳定;在低配设备中,多个服务合并为一个进程,节约资源。同样的思路也应用到了Android上。
重点说一说站点隔离(http://t.cn/RgNAwLC)。站点隔离是新近引入Chrome的一个里程碑式特性,即每个跨站点iframe都运行一个独立的渲染器进程。即便像前面说的那样,每个标签页单开一个渲染器进程,但允许跨站点的iframe运行在同一个渲染器进程中并共享内存空间,那安全攻击仍然有可能绕开同源策略(http://t.cn/8s1ySzx),而且有人发现在现代CPU中,进程有可能读取任意内存(http://t.cn/R8FwHoX)。
进程隔离是隔离站点、确保上网安全最有效的方式。Chrome 67桌面版默认采用站点隔离。站点隔离是多年工程化努力的结果,它并非多开几个渲染器进程那么简单。比如,不同的iframe运行在不同进程中,开发工具在后台仍然要做到无缝切换,而且即便简单地Ctrl+F查找也会涉及在不同进程中搜索。
导航 导航涉及浏览器进程与线程间为显示网页而通信。一切从用户在浏览器中输入一个URL开始。输入URL之后,浏览器会通过互联网获取数据并显示网页。从请求网页到浏览器准备渲染网页的过程,叫做导航。
如前所述,标签页外面的一切都由浏览器进程处理。浏览器进程中有线程(UI线程)负责绘制浏览器的按钮和地址栏,有线程(网络线程)负责处理网络请求并从互联网接收数据,有线程(存储线程)负责访问文件和存储数据。
下面我们逐步看一看导航的几个步骤。
第一步:处理输入。UI线程会判断用户输入的是查询字符串还是URL。因为Chrome的地址栏同时也是搜索框。
第二步:开始导航。如果输入的是URL,UI线程会通知网络线程发起网络调用,获取网站内容。此时标签页左端显示旋转图标,网络线程进行DNS查询、建立TLS连接(对于HTTPS)。网络线程可能收到服务器的重定向头部,如HTTP 301。此时网络线程会跟UI线程沟通,告诉它服务器要求重定向。然后,再发起对另一个URL的请求。
第三步:读取响应。服务器返回的响应体到来之后,网络线程会检查接收到的前几个字节。响应的Content-Type头部应该包含数据类型,如果没有这个字段,则需要MIME类型嗅探(http://t.cn/Rt2gG2J)。看看Chrome源码(http://t.cn/Ai9cZI7D)中的注释就知道这一块有多难搞。
**如果响应是HTML文件,那下一步就是把数据交给渲染器进程。但如果是一个zip文件或其他文件,那就意味着是一个下载请求,需要把数据传给下载管理器。
此时也是“安全浏览”(https://safebrowsing.google.com/)检查的环节。如果域名和响应数据匹配已知的恶意网站,网络线程会显示警告页。此外,CORB(Cross Origin Read Blocking,https://www.chromium.org/Home/chromium-security/corb-for-developers)检查也会执行,以确保敏感的跨站点数据不会发送给渲染器进程。
第四步:联系渲染器进程。所有查检完毕,网络线程确认浏览器可以导航到用户请求的网站,于是会通知UI线程数据已经准备好了。UI线程会联系渲染器进程渲染网页。
由于网络请求可能要花几百毫秒才能拿到响应,这里还会应用一个优化策略。第二步UI线程要求网络线程发送请求后,已经知道可能要导航到哪个网站去了。因此在发送网络请求的同时,UI线程会提前联系或并行启动一个渲染器进程。这样在网络线程收到数据后,就已经有渲染器进程原地待命了。如果发生了重定向,这个待命进程可能用不上,而是换作其他进程去处理。
第五步:提交导航。数据和渲染器进程都有了,就可以通过IPC从浏览器进程向渲染器进程提交导航。渲染器进程也会同时接收到不间断的HTML数据流。当浏览器进程收到渲染器进程的确认消息后,导航完成,文档加载阶段开始。
此时,地址栏会更新,安全指示图标和网站设置UI也会反映新页面的信息。当前标签页面的会话历史会更新,后退/前进按钮起作用。为便于标签页/会话在关闭标签页或窗口后恢复,会话历史会写入磁盘。
最后一步:初始加载完成。提交导航之后,渲染器进程将负责加载资源和渲染页面(具体细节后面介绍)。而在完成渲染后(在所有iframe中的onload事件触发且执行完成后),渲染器进程会通过IPC给浏览器进程发送一个消息。此时,UI线程停止标签页上的旋转图标。
初始加载完成后,客户端JavaScript仍然可能加载额外资源并重新渲染页面。
如果此时用户在地址又输入了其他URL呢?浏览器进程还会重复上述步骤,导航到新站点。不过在此之前,需要确认已渲染的网站是否关注beforeunload事件。因为标签页中的一切,包括JavaScript代码都由渲染器进程处理,所以浏览器进程必须与当前的渲染器进程确认后再导航到新站点。
如果导航请求来自当前渲染器进程(用户点击了链接或JavaScript运行了window.location = "https://newsite.com"),渲染器进程首先会检查beforeunload处理程序。然后,它会走一遍与浏览器进程触发导航同样的过程。唯一的区别在于导航请求是由渲染器进程提交给浏览器进程的。
导航到不同的网站时,会有一个新的独立渲染器进程负责处理新导航,而老的渲染器进程要负责处理unload之类的事件。更多细节,可以参考“页面生命周期API”:http://t.cn/Rey7RIE。
另外,导航阶段还可能涉及Service Worker,即网页应用中的网络代理服务(http://t.cn/R3SH3HL),开发者可以通过它控制什么缓存在本地,何时从网络获取新数据。Service Worker说到底也是需要渲染器进程运行的JavaScript代码。如果网站注册了Server Worker,那么导航请求到来时,网络线程会根据URL将其匹配出来,此时UI线程就会联系一个渲染器进程来执行Service Worker的代码:可能只要从本地缓存读取数据,也可能需要发送网络请求。
如果Service Worker最终决定从网络请求数据,浏览器进程与渲染器进程间的这种往返通信会导致延迟。因此,这里会有一个“导航预加载”的优化(http://t.cn/Ai9qGJ66),即在Service Worker启动同时预先加载资源,加载请求通过HTTP头部与服务器沟通,服务器决定是否完全更新内容。
渲染 渲染是渲染器进程内部的工作,涉及Web性能的诸多方面(详细内容可以参考这里http://t.cn/Ai9c4nUu)。标签页中的一切都由渲染器进程负责处理,其中主线程负责运行大多数客户端JavaScript代码,少量代码可能会由工作线程处理(如果用到了Web Worker或Service Worker)。合成器(compositor)线程和栅格化(raster)线程负责高效、平滑地渲染页面。
渲染器进程的核心任务是把HTML、CSS和JavaScript转换成用户可以交互的网页接下来,我们从整体上过一遍渲染器进程处理Web内容的各个阶段。
解析HTML 构建DOM。渲染器进程收到导航的提交消息后,开始接收HTML,其主线程开始解析文本字符串(HTML),并将它转换为DOM(Document Object Model,文档对象模型)。
DOM是浏览器内部对页面的表示,也是JavaScript与之交互的数据结构和API。
如何将HTML解析为DOM由HTML标准(http://t.cn/R2NREUt)定义。HTML标准要求浏览器兼容错误的HTML写法,因此浏览器会“忍气吞声”,绝不报错。详情可以看看“解析器错误处理及怪异情形简介”(http://t.cn/Ai9c8i5D)。
安装要求 足够新的MATLAB版本(R2015b或更高版本)和一个支持C ++ 11的编译器(Visual Studio 2015,GCC 4.8,Xcode 7.3.1或更高版本)。 对于GPU计算,至少需要CUDA 7.5以及CuDNN v(可选)或更新版本。
本次安装在如下实验环境中通过:
MATLAB2019b
Visual Studio 2019
matconvnet-1.0-beta25
步骤 1、下载MatConvNet工具箱安装包 下载链接 注:在链接中下载完安装包后将安装包剪切到MATLAB的安装路径中,本人是D:\MATLAB\toolbox(如果不安到toolbox里可能后续程序会报错,本人出现了这个问题)
2、安装和编译库 (1)如果这是您第一次编译 MatConvNet,请考虑先尝试 CPU 版本。
在MATLAB命令行中键入以下内容,以确保你的电脑在windous环境下VS的版本在2015及以上。
mex -setup mex -setup C++ (2)在命令行中依次输入以下代码
其中:cd后跟的路径为你保存工具箱的路径,因人而异。
cd D:\MATLAB\toolbox\matconvnet-1.0-beta25 addpath matlab vl_compilenn 注意:此处可能会出现编译错误,如下所示
警告: CL.EXE not found in PATH. Trying to guess out of mex setup. > In vl_compilenn>check_clpath (line 650)
In vl_compilenn (line 426)
In install (line 33) 'cl.exe' 不是内部或外部命令,也不是可运行的程序 或批处理文件。 错误使用 vl_compilenn>check_clpath (line 656)
spring指令重排和多线程,原来在编写程序的时候要考虑这么多东西,要想清楚每一个代码,每一个线程在哪执行,还有要懂得jvm 的一些优化的。任重而道远啊。
单例模式,只允许一个实例的存在,构造函数是私有的,对外提供获取实例的方法。getInstance()
单例模式需要注意多线程情况下的程序正确运行,加双重校验锁,但是容易出错,一般用静态内部类,在加载的时候就创建,
普通工厂模式, 对于参数的不同,返回不同的实例类。
工厂模式实现了使用和创建的分离。
但是工厂模式也产生了 产品过多
需求:对接第三方登陆,实现绕过原有Shiro认证登陆。
文章目录 一、实现思路1. 现状分析2. 用户来源3. 所属范围 二、实现方案2.1. 自定义登录认证规则2.2. Shiro认证枚举2.3. 密码和非密码登录2.4. 规则配置2.5. 自定义Realm2.6. 案例使用 一、实现思路 1. 现状分析 系统权框架默认使用Shiro 认证授权机制
2. 用户来源 从统一认证平台登录跳转过来的用户
3. 所属范围 登录限制由统一认证平台去做,但是,跳转过来的用户仍然走您本系统的登录流程,只是走本系统的登录流程时,想跳过Shiro 对用户密码的校验,校验所属范围为Shiro 认证机制,其他功能照旧;
二、实现方案 2.1. 自定义登录认证规则 package com.gblfy.config.skipshiro; import com.gblfy.config.skipshiro.enums.ShiroApproveLoginType; import org.apache.shiro.authc.UsernamePasswordToken; /** * 自定义token 实现免密和密码登录 * <p> * 1.账号密码登陆(password) * 2.免密登陆(nopassword) * </p> * * @author gblfy * @date 2021-10-22 */ public class EasyUsernameToken extends UsernamePasswordToken { private static final long serialVersionUID = -2564928913725078138L; private ShiroApproveLoginType type; public EasyUsernameToken() { super(); } /** * 免密登录 */ public EasyUsernameToken(String username) { super(username, "
戳气球 动规划方法关键是要找出重复计算的部分还有就是找出状态转移方程。
当从左到右计算需要右边子问题的计算结果的时候,不妨考虑一下从右到左边计算看看是否是自底向上的,如果是就存储起来。
/** class Solution { int []val; int [][]rec; public int maxCoins(int[] nums) { //第一种方法,记忆化搜索。用分治递归的思路。 int n = nums.length; val = new int [n+2]; rec = new int [n+2][n+2]; for(int i = 1;i<n+1;++i){ val[i]=nums[i-1]; } val[0]=val[n+1]=1; for(int i =0 ;i<n+2;i++){ Arrays.fill(rec[i],-1); } return solve(0,n+1); } public int solve(int left,int right){ //表示没有办法插入气球了。 if(left>=right-1){ return 0; } if(rec[left][right]!=-1){ return rec[left][right]; } int sum =0; for(int i = left+1;i<right;++i){ sum=val[left]*val[i]*val[right]; sum+=solve(left,i)+solve(i,right); rec[left][right]=Math.
学习正点原子《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf》个人笔记
常用操作&相关知识 压缩解压 解压.tar.bz2
tar -vxjf linux-imx-4.1.15-2.1.0-g8a006db.tar.bz2
压缩.tar.bz2
tar -vcjf alientek_uboot.tar.bz2 alientek_uboot
编译 将前面编译出来的 led.o 文件链接到 0X87800000 这个地址,使用如下命令:
arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
上述命令中-Ttext 就是指定链接地址,“-o”选项指定链接生成的 elf 文件名,这里我们命名为 led.elf。上述命令执行完以后就会在工程目录下多一个 led.elf 文件
led.elf 文件也不是我们最终烧写到 SD 卡中的可执行文件,我们要烧写的.bin 文件,因此还需要将 led.elf 文件转换为.bin 文件,这里我们就需要用到 arm-linux-gnueabihf-objcopy 这个工具了。
arm-linux-gnueabihf-objcopy 更像一个格式转换工具,我们需要用它将 led.elf 文件转换为led.bin 文件,命令如下:
arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
上述命令中,“-O”选项指定以什么格式输出,后面的“binary”表示以二进制格式输出,选项“-S”表示不要复制源文件中的重定位信息和符号信息,“-g”表示不复制源文件中的调试信息。
大多数情况下我们都是用 C 语言写试验例程的,有时候需要查看其汇编代码来调试代码,因此就需要进行反汇编,一般可以将 elf 文件反汇编,比如如下命令:
arm-linux-gnueabihf-objdump -D led.elf > led.dis
上述代码中的“-D”选项表示反汇编所有的段,反汇编完成以后就会在当前目录下出现一个名为 led.dis 文件
可以打开 led.dis 文件看一下,看看是不是汇编代码