本页内容包含所有站内用户最新发表的博客.
最新发布
javascript,加密算法
0
258
js示例代码
functiongeneratePrivateKey(length=64){
constbytes=newUint8Array(length);
window.crypto.getRandomValues(bytes);
returnBigInt(`0x${bytes.reduce((data,byte)=data+('00'+byte.toString(16)).slice(-
框架,springboot
0
1005
一、需求:二、logback-spring.xml配置文件详情三、application.yml中添加多环境配置四、测试配置是否成功五、配置不同级别的日志输出到不同文件一、需求:
使用springboot用自带的logback打印日志多环境打印生产环境输出到控制台和文件,一天一个文件,保留30天开发环境输出到控制台
二、logback-spring.xml配置文件详情?xmlversion="1.
blog
js实现图片拖拽与缩放,源码
前端,javascript
0
964
下方的代码包括html,css,javascript。可直接复制到本地文件测试。如果引用的图片无法访问,请替换图片连接。
!DOCTYPEhtml
htmllang="en"
head
metacharset="UTF-8"
metahttp-equiv="X-UA-Compatible"content="IE=edge"
metaname="viewport"content="width=device-width,initial-scale=1.0"
title图片拖拽与缩放/title
style
#content{
}
/style
/head
body
divid="content"
China'slatestemphasisonnurturingnewqualityproductiveforcesaswellasthebrefficientpoliciesintroducedduringtheannualsessionsbrofthecountry'stoplegislativeandpoliticaladvisorybodiesareboostingconfidenceamongmultinationalcompanies.brbr
China'slatestemphasisonnurturingnewqualityproductiveforcesaswellasthebrefficientpoliciesintroducedduringtheannualsessionsbrofthecountry'stoplegislativeandpoliticaladvisorybodiesareboostingconfidenceamongmultinationalcompanies.brbr
China'slatestemphasisonnurturingnewqualityproductiveforcesaswellasthebrefficientpoliciesintroducedduringtheannualsessionsbrofthecountry'stoplegislativeandpoliticaladvisorybodiesareboostingconfidenceamongmultinationalcompanies.brbr
China'slatestemphasisonnurturingnewqualityproductiveforcesaswellasthebrefficientpoliciesintroducedduringtheannualsessionsbrofthecountry'stoplegislativeandpoliticaladvisorybodiesareboostingconfidenceamongmultinationalcompanies.brbr
imgclass="imgs"src="https://img0.baidu.com/it/u=580921286,1214064928&fm=253&fmt=auto&app=138&f=JPEG?w=667&h=500"brbr
China'slatestemphasisonnurturingnewqualityproductiveforcesaswellasthebrefficientpoliciesintroducedduringtheannualsessionsbrofthecountry'stoplegislativeandpoliticaladvisorybodiesareboostingconfidenceamongmultinationalcompanies.brbr
China'slatestemphasisonnurturingnewqualityproductiveforcesaswellasthebrefficientpoliciesintroducedduringtheannualsessionsbrofthecountry'stoplegislativeandpoliticaladvisorybodiesareboostingconfidenceamongmultinationalcompanies.brbr
China'slatestemphasisonnurturingnewqualityproductiveforcesaswellasthebrefficientpoliciesintroducedduringtheannualsessionsbrofthecountry'stoplegislativeandpoliticaladvisorybodiesareboostingconfidenceamongmultinationalcompanies.brbr
China'slatestemphasisonnurturingnewqualityproductiveforcesaswellasthebrefficientpoliciesintroducedduringtheannualsessionsbrofthecountry'stoplegislativeandpoliticaladvisorybodiesareboostingconfidenceamongmultinationalcompanies.brbr
imgclass="imgs"src="https://img1.baidu.com/it/u=403163518,2135282784&fm=253&fmt=auto&app=138&f=JPEG?w=913&h=393"brbr
China'slatestemphasisonnurturingnewqualityproductiveforcesaswellasbrtheefficientpoliciesintroducedduringtheannualsessibronsofthecountry'stoplegislativeandpoliticaladvisorybodiesareboostingconfidenceamongmultinationalcompanies.brbr
China'slatestemphasisonnurturingnewqualityproductiveforcesaswellasthebrefficientpoliciesintroducedduringtheannualsessionsbrofthecountry'stoplegislativeandpoliticaladvisorybodiesareboostingconfidenceamongmultinationalcompanies.brbr
China'slatestemphasisonnurturingnewqualityproductiveforcesaswellasthebrefficientpoliciesintroducedduringtheannualsessionsbrofthecountry'stoplegislativeandpoliticaladvisorybodiesareboostingconfidenceamongmultinationalcompanies.brbr
China'slatestemphasisonnurturingnewqualityproductiveforcesaswellasthebrefficientpoliciesintroducedduringtheannualsessionsbrofthecountry'stoplegislativeandpoliticaladvisorybodiesareboostingconfidenceamongmultinationalcompanies.br
/div
/body
!--scriptsrc="./daz.js"/script--
script
functioncreateCurtain(){
constcurtain=document.createElement('div');
curtain.style.top="0px";
curtain.style.left="0px";
curtain.style.position="fixed";
curtain.style.backgroundColor="rgba(255,255,255,0)";
curtain.style.width="100%";
curtain.style.height="100%";
curtain.style.display="none";
curtain.style.transition="background-color0.4sease";
//获取body元素
constbody=document.body;
//获取第一个子元素
constfirstChild=body.firstChild;
//在第一个子元素之前插入新的div元素
body.insertBefore(curtain,firstChild);
returncurtain;
}
functiondragAndZoom(content){
vartopOld=0;
varleftOld=0;
varwidth=0;
varheight=0;
letcurtain=createCurtain();
letimgs=content.getElementsByTagName("img");
for(vari=0;iimgs.length;i++){
imgs[i].onclick=function(){
curtain.style.display="block";
curtain.style.transition="background-color0.4sease";
curtain.style.backgroundColor="rgba(0,0,0,0.9)";
width=this.offsetWidth;
height=this.offsetHeight;
constmyimage=document.createElement('img');
myimage.height=this.offsetHeight;
myimage.style.position="fixed";
myimage.style.zIndex="2147483648";
myimage.style.cursor="grab";
myimage.style.transitionProperty="top,left,transform";
myimage.style.transitionDuration="0.4s";
myimage.style.transform="translate(0%,0%)";
myimage.style.transitionTimingFunction="ease-in-out;"
myimage.setAttribute('draggable','true');
myimage.id="image";
myimage.setAttribute("src",this.getAttribute("src"));
document.body.style.overflow='hidden';
curtain.appendChild(myimage);
constrect=this.getBoundingClientRect();
consttopOffset=rect.top;
constleftOffset=rect.left;
topOld=topOffset;
leftOld=leftOffset;
myimage.style.top=topOffset+"px";
myimage.style.left=leftOffset+"px";
zoom(myimage)
imgMove(myimage);
myimage.style.top="50%";
myimage.style.left="50%";
myimage.style.transform="translate(-50%,-50%)";
}
}
curtain.onclick=function(){
letimage=document.getElementById("image");
image.style.transitionProperty="top,left,transform,height";
image.style.transitionDuration="0.4s";
image.style.transitionTimingFunction="ease-in-out;"
image.height=height;
image.style.transform="translate(0%,0%)";
image.style.top=topOld+"px";
image.style.left=leftOld+"px";
curtain.style.backgroundColor="rgba(255,255,255,0)";
image.addEventListener('transitionend',()={
this.style.display="none";
document.body.style.overflow=''
curtain.innerHTML='';
})
}
}
functionimgMove(img){
consti=window.getComputedStyle(img);
i.getPropertyValue('top');
lettv=0;
letlv=0;
//图片坐标信息
letimgTop=0;
letimgLeft=0;
//鼠标坐标信息
letmx=0;
letmy=0;
//图片拖动开始前
img.ondragstart=e={
img.style.transitionProperty="";
img.style.transitionDuration="";
img.style.transitionTimingFunction=""
//初始化鼠标坐标信息
mx=e.screenX;
my=e.screenY;
if(img.style.top==="50%"){
//初始化图片坐标信息
constimageStyles=window.getComputedStyle(img);
tv=parseFloat(imageStyles.getPropertyValue('top'));
lv=parseFloat(imageStyles.getPropertyValue('left'));
}
}
//图片拖动中
img.ondrag=e={
if(e.screenY==0&&e.screenX==0){
return
}
imgTop=imgTop+e.screenY-my;
imgLeft=imgLeft+e.screenX-mx;
mx=e.screenX;
my=e.screenY;
img.style.top=imgTop+tv+"px";
img.style.left=imgLeft+lv+"px";
}
}
functionzoom(myimage){
varscrollFunc=function(e){
e=e||window.event;
letheight=myimage.height;
if(e.wheelDelta){//IEChromeOperaSafari
if(e.wheelDelta0){
myimage.height=height+20;
e.stopPropagation();//终止事件的进一步传播
}
if(e.wheelDelta0){
if(height100){
return;
}
myimage.height=height-20;
e.stopPropagation();
}
}elseif(e.detail){//Firefox
if(e.detail0){
myimage.height=height+20;
e.stopPropagation();//终止事件的进一步传播
}
if(e.detail0){
if(height100){
return;
}
myimage.height=height-20;
e.stopPropagation();
}
}
}
if(myimage.addEventListener){
//addEventListener适用于版本较新的IE浏览器,如IE9以及火狐浏览器,
myimage.addEventListener("mousewheel",scrollFunc,false);
//Firefox浏览器使用的滚轮事件是DOMMouseScroll
myimage.addEventListener("DOMMouseScroll",scrollFunc,false);
}else{
myimage.attachEvent("onmousewheel",scrollFunc);
}
}
/script
script
window.onload=function(){
letcontent=document.getElementById("content");
dragAndZoom(content);
}
/script
/html
maven
0
1111
build
plugins
plugin
groupIdorg.apache.maven.plugins/groupId
artifactIdmaven-shade-plugin/artifactId
version3.2.4/version!--使用最新版本--
executions
execution
phasepackage/phase
goals
goalshade/goal
/goals
blog
全国车辆归属地检索表
其他
0
2014
一、表格
省
简称
省市
河北
冀A
河北石家庄
河北
冀B
河北唐山
河北
冀C
河北秦皇岛
河北
冀D
河北邯郸
河北
冀E
河北邢台
河北
冀F
河北保定
河北
冀G
河北张家口
河北
冀H
河北承德
河北
冀J
河北沧州
河北
冀R
河北廊坊
河北
冀T
河北衡水
山西
晋A
山西太原
山西
晋B
山西大同
山西
晋C
山西
nginx
0
3263
情景websocket服务端经nginx代理,刷新页面连接正常,大约经过60秒没有发送消息,websocket自动断开连接,控制台打印错误码为1006。
原因在经过nginx代理时,nginx会检测超过60秒(默认)没有活动的套接字,并将其断开连接。
解决方法
一、修改nginx代理超时时间
时间根据实际需求配置,单位秒
proxy_read_timeout86400s;
proxy_send_
java基础
0
2077
一、什么是countDownlatchCountDownLatch是一个同步工具类,它通过一个计数器来实现的,初始值为线程的数量。每当一个线程完成了自己的任务,计数器的值就相应得减1。当计数器到达0时,表示所有的线程都已执行完毕,然后在等待的线程就可以恢复执行任务。
二、方法详解
CountDownLatch(intcount):count为计数器的初始值(一般需要多少个线程执行,count就设为
rabbitmq,springboot
0
2276
客户端connection、channels、queues、consumers和系统其它部分自动生成的事件。例如,当一个connection被接受,虚拟主机通过了验证授权,将会发送一个connection_created事件,当一个connection关闭或者由于其它原因失败,将会发送一个connection_closed事件。RabbitMQ提供了一个最小的事件通知机制向RabbitMQ客户端公开。
一、rabbitmq-event-exchange插件rabbitmq-event-exchange是一个消费内部事件并且重新发送到一个topicexchange的插件,因此可以展示事件给客户端应用程序。
为了消费事件,应用程序需要声明一个队列,并绑定到一个系统指定的交换器去消费消息。
插件在默认的虚拟主机上声明了一个topic类型的exchange(交换器)amq.rabbitmq.event。所有的事件都会发送到这个exchange上并绑定一个路由键,比如,exchange.created、binding.deleted。所以你可以只订阅你关注的事件。
交换器的行为类似amq.rabbitmq.log,所有的信息都发布到这里,如果用户没有经过授权,你可以拒绝它们访问。
每个事件都有与之关联的各种属性,它们被转换成AMQP0-9-1数据编码并插入到消息头中。消息的正文始终为空。
启动插件
rabbitmq-pluginsenablerabbitmq_event_exchange
关闭插件
rabbitmq-pluginsdisablerabbitmq_event_exchange
二、事件(Events)RabbitMQ和相关插件通过routingkeys发送事件:
RabbitMQBroker
Queue,ExchangeandBindingevents:
queue.deletedqueue.createdexchange.createdexchange.deletedbinding.createdbinding.deleted
ConnectionandChannelevents:
connection.createdconnection.closedchannel.createdchannel.closed
Consumerevents:
consumer.createdconsumer.deleted
PolicyandParameterevents:
policy.setpolicy.clearedparameter.setparameter.cleared
Virtualhostevents:
vhost.createdvhost.deleted
Userrelatedevents:
user.authentication.successuser.authentication.failureuser.createduser.deleteduser.password.changeduser.password.cleareduser.tags.set
Permissionevents:
permission.createdpermission.deleted
ShovelPlugin
Workerevents:
shovel.worker.statusshovel.worker.removed
FederationPlugin
Linkevents:
federation.link.statusfederation.link.removed
三、集群中如何使用该插件在集群中每个节点都要开启此插件,否则amq.rabbitmq.event交换器不可以正常的被创建。
四、Springboot监听事件
添加rabbitmq配置
spring:
rabbitmq:
host:192.168.1.101
port:5672
username:root
password:root
定义事件监听器RabbitBrokerEventListener
importorg.springframework.amqp.core.Message;
importorg.springframework.amqp.rabbit.connection.ConnectionFactory;
importorg.springframework.amqp.rabbit.core.BrokerEventListener;
importjava.util.Iterator;
importjava.util.Map;
importjava.util.Set;
/**
*@author:Jiajiajia
*@createDate:2023/7/1120:20
*@description:事件监听器
*/
publicclassRabbitBrokerEventListenerextendsBrokerEventListener{
publicRabbitBrokerEventListener(ConnectionFactoryconnectionFactory,String...eventKeys){
super(connectionFactory,eventKeys);
}
@Override
publicvoidonMessage(Messagemessage){
System.out.println("");
System.out.println("--------------------------------");
System.out.println("");
finalStringreceivedRoutingKey=message.getMessageProperties().getReceivedRoutingKey();
System.out.println(receivedRoutingKey);
System.out.println();
finalMapString,Objectheaders=message.getMessageProperties().getHeaders();
finalSetMap.EntryString,Objectentries=headers.entrySet();
finalIteratorMap.EntryString,Objectiterator=entries.iterator();
while(iterator.hasNext()){
//打印header
finalMap.EntryString,Objectnext=iterator.next();
System.out.println(next.getKey()+":"+next.getValue());
}
super.onMessage(message);
}
}
配置监听器RabbitConfig
importorg.springframework.amqp.rabbit.connection.AbstractConnectionFactory;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
/**
*@author:Jiajiajia
*@createDate:2023/7/1120:20
*@description:配置事件监听器
*/
@Configuration
publicclassRabbitConfig{
@Bean
publicRabbitBrokerEventListenerbrokerEventListener(AbstractConnectionFactoryconnectionFactory){
//eventKeys是要监听的主题
returnnewRabbitBrokerEventListener(connectionFactory,"user.#","channel.#","queue.#","connection.#","consumer.#");
}
}
redis,springboot
0
1987
一、springboot集成redis一般配置pomdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependencydependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifact
blog
rabbitmq开启http安全认证插件
rabbitmq
0
1510
rabbitmq_auth_backend_http插件一、rabbitmq中启用rabbitmq_auth_backend_http插件二、修改配置文件三、开启验证缓存功能一、rabbitmq中启用rabbitmq_auth_backend_http插件命令:rabbitmq-pluginslist##查看插件列表rabbitmq-pluginsenablerabbitmq_auth_backend_http##启用mqtt插件[root@localhostrabbitmq]#rabbitmq-pluginslistListingpluginswithpattern".*"...Configured:E=explicitlyenabled;e=implicitlyenabled|Status:*=runningonrabbit@localhost|/[]rabbitmq_amqp1_03.9.10[]rabbitmq_auth_backend_cache3.9.10[E*]rabbitmq_auth_backend_http3.9.10[]rabbitmq_auth_backend_ldap3.9.10[]rabbitmq_auth_backend_oauth23.9.10[]rabbitmq_auth_mechanism_ssl3.9.10[]rabbitmq_consistent_hash_exchange3.9.10[E*]rabbitmq_delayed_message_exchange3.9.0[E*]rabbitmq_event_exchange3.9.10[]rabbitmq_federation3.9.10......[root@localhostrabbitmq]#rabbitmq-pluginsenablerabbitmq_auth_backend_http......前面带[E*]的代表已启用二、修改配置文件rabbitmq的配置文件默认在/etc/rabbitmq/rabbitmq.conf,如果没有这个文件,则需要自己手动创建这个文件。修改文件vi/etc/rabbitmq/rabbitmq.conf,写入如下内容:#优先使用内部认证auth_backends.1=internal#如果内部认证没有找到用户,则请求http认证auth_backends.2=http#认证请求类型auth_http.http_method=post#认证和授权地址,官方提供了SpringBoot示例auth_http.user_path=http://192.168.1.102:19085/auth/userauth_http.vhost_path=http://192.168.1.102:19085/auth/vhostauth_http.resource_path=http://192.168.1.102:19085/auth/resourceauth_http.topic_path=http://192.168.1.102:19085/auth/topic配置文件中依次配置了auth_backends.1=internal和auth_backends.2=http,意思是优先使用内部认证,如果内部认证没有找到用户,则请求http认证。当然也可以直接配置auth_backends.1=http,这样会直接走http认证,忽略内部认证。(内部认证为rabbitmq服务本地配置的内部用户)auth_http.user_path校验用户登录auth_http.vhost_path验证虚拟主机权限auth_http.resource_path校验使用资源权限(交换机,队列)auth_http.topic_path检查主题是否可以订阅rabbitmq官方给我们提供了一些后端校验的案例:https://github.com/rabbitmq/rabbitmq-auth-backend-http其中启动包含了springboot的案例,和一些其他语言的案例。三、开启验证缓存功能开启http认证后,每次登录或订阅主题登录都会请求http验证权限,过于频繁会影响性能,此时可以开启缓存,在缓存时间内不会重复请求http认证。启用缓存插件[root@localhostrabbitmq]#rabbitmq-pluginsenablerabbitmq_auth_backend_cache修改配置文件#启用cache后,不需要直接指定http方式auth_backends.1=internalauth_backends.2=cache#缓存后端指定为httpauth_cache.cached_backend=http#缓存时间,单位毫秒auth_cache.cache_ttl=10000#认证和授权地址,官方提供了SpringBoot示例auth_http.user_path=http://192.168.1.102:19085/auth/userauth_http.vhost_path=http://192.168.1.102:19085/auth/vhostauth_http.resource_path=http://192.168.1.102:19085/auth/resourceauth_http.topic_path=http://192.168.1.102:19085/auth/topic重启rabbitmq服务servicerabbitmq-serverrestart
blog
for in 和 for of 的区别
javascript,前端
0
1142
jsjavascriptforin和forof的区别,forof遍历的原理
一、区别
forin是ES5的语法,forof是ES6的语法forin是无序遍历数组或对象的,也就是随机遍历,不按照顺序来;forof是按照顺序遍历的forin是对key值遍历的,对于对象来说,遍历的是对象的key值,对于数组来说,遍历的是数组的下标;forof是对数组遍历的,不能遍历对象,可以遍历数组,是对数组的每一个元
前端,javascript
0
1624
比较点
普通函数
箭头函数
简写
箭头函数如果没有参数,同时函数体的返回值只有一句,则{}和return都可以省略。
this指向
this总是指向调用它的对象,如果作为构造函数,它指向创建的对象实例
箭头函数的this指向的是父级作用域的this,是通过查找作用域链来确定this的值,也就是说看的是上下文的this,指向的是定义它的对象,而不是使用时所在的对象。
this
blog
v-if和v-show的区别
vue
0
860
一.v-show与v-if的共同点在vue中v-show与v-if的作用效果是相同的(不含v-else),都能控制元素在页面是否显示。
当表达式都为false时,都不会占据页面位置当表达式结果为true时,都会占据页面的位置
二、v-show与v-if的区别
控制手段不同编译过程不同编译条件不同
控制手段:v-show隐藏则是为该元素添加css—display:none,dom元素依旧还在。v-
blog
使用openssl生成crt证书
搜索
0
904
官网下载https://www.oomake.com/download/openssl
检查是否安装opensslD:\tmp\sslopensslversion
OpenSSL3.1.014Mar2023(Library:OpenSSL3.1.014Mar2023)
创建证书密钥文件server.keyD:\tmp\sslopensslgenrsa-des3-outserver.key1024
EnterPEMpassphrase:##输入密码
Verifying-EnterPEMpassphrase:##输入确认密码
创建证书申请文件:server.csrD:\tmp\sslopensslreq-new-keyserver.key-outserver.csr
Enterpassphraseforserver.key:##输入前面设置的密码
Youareabouttobeaskedtoenterinformationthatwillbeincorporated
intoyourcertificaterequest.
WhatyouareabouttoenteriswhatiscalledaDistinguishedNameoraDN.
Therearequiteafewfieldsbutyoucanleavesomeblank
Forsomefieldstherewillbeadefaultvalue,
Ifyouenter'.',thefieldwillbeleftblank.
-----
CountryName(2lettercode)[AU]:CN##输入国家代号,中国输入CN
StateorProvinceName(fullname)[Some-State]:BeiJing##省的全名,拼音
LocalityName(eg,city)[]:BeiJing##市的全名,拼音
OrganizationName(eg,company)[InternetWidgitsPtyLtd]:Li##公司英文名
OrganizationalUnitName(eg,section)[]:##可以不输入
CommonName(e.g.serverFQDNorYOURname)[]:##可以不输入
EmailAddress[]:##可以不输入
Pleaseenterthefollowing'extra'attributes
tobesentwithyourcertificaterequest
Achallengepassword[]:##可以不输入
Anoptionalcompanyname[]:##可以不输入
备份一份服务器密钥文件server.key.orgD:\tmp\sslcopyserver.keyserver.key.org
去除文件口令server.keyD:\tmp\sslopensslrsa-inserver.key.org-outserver.key
Enterpassphraseforserver.key.org:##输入前面设置的密码
writingRSAkey
生成证书文件server.crtD:\tmp\sslopensslx509-req-days365-inserver.csr-signkeyserver.key-outserver.crt
Certificaterequestself-signatureok
subject=C=CN,ST=BeiJing,L=BeiJing,O=Li
此时文件夹内:
nginx配置server{
listen443ssl;
server_nametr.test.com;
ssl_certificateD:/tmp/ssl/server.crt;
ssl_certificate_keyD:/tmp/ssl/server.key;
ssl_session_cacheshared:SSL:1m;
ssl_session_timeout5m;
ssl_ciphersHIGH:!aNULL:!MD5;
ssl_prefer_server_cipherson;
location/{
roothtml;
indexindex.htmlindex.htm;
}
error_page500502503504/50x.html;
location=/50x.html{
roothtml;
}
}
数据结构,算法基础
0
987
[数据结构与算法]
一、什么是最小生成树?二、Kruskal算法三、Prim算法一、什么是最小生成树? 在给定一张无向图,如果在它的子图中,任意两个顶点都是互相连通,并且是一个树结构,那么这棵树叫做生成树。当连接顶点之间的图有权重时,权重之和最小的树结构为最小生成树!
在实际中,这种算法的应用非常广泛,比如我们需要在n个城市铺设电缆,则需要n-1条通信线路,那么我们如何铺设可以使得电缆最短呢
blog
并查集 算法分析
数据结构,算法基础
0
838
[数据结构与算法]
一、简介二、算法实现初始化FindUnion三、图示四、算法优化启发式合并路径压缩五、小结一、简介wiki上关于并查集的简介
在计算机科学中,并查集是一种树型的数据结构,用于处理一些不交集(DisjointSets)的合并及查询问题。有一个联合-查找算法(union-findalgorithm)定义了两个用于此数据结构的操作:
Find:确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一子集。Union:将两个子集合并成同一个集合。
并查集主要用于解决动态连通性问题
我们用一个代表来标识一个不交集.通常我们不关心哪个成员作为代表,但是对于属于同一个集合的两个变量,查询应该得到相同的代表。
举个栗子,假如有一个大型的计算机网络,其中有很多台计算机,如果计算机a与计算机b连通,b与c连通,那么a与c连通.对于网络中的两台计算机p,q我们可能有这些操作:判断p,q是否连通find(p)==find(q);在p,q之间建立一条路线使两者连通union(p,q)
通过上面的例子不难看出连通是一种等价关系,它有以下性质:
自反性:p与p是连通的对称性:p与q连通,则q与p连通传递性:p与q连通且q与r连通,则p与r连通
二、算法实现首先我们用一个数组记录所有元素,对于set[i]==k,i表示i个元素,k表示元素所属的集合,通常可以指向或者间接指向集合的代表来表示属于这个集合.当set[i]==i是表明i是一个根节点。set[i]==k可以理解为i,k之间有一条连通的路线,被称为链接。
初始化让所有元素指向自己,表示属于不同的集合,此时集合中每个元素都是一个根节点
privateint[]parent;
publicvoidinit(intn){
parent=newint[n];
for(inti=0;in;i++)
parent[i]=i;
}
Find从x向上查找,直到找到元素的根节点set[i]==i,此根节点就表示这个集合。
publicintfind(intx){
if(parent[x]!=x){
find(parent[x]);
}
returnparent[x];
}
Union把两个不同的点连起来,对于x,y两个点来说,相当与把x,y所在集合合并(传递性),即x,y所在集合所以元素都连通.所以我们可以找到两个集合的代表(根节点),然后把代表合并即可。
publicvoidunion(intx,inty){
//分别查询x、y所在集合的代表
introotX=find(x);
introotY=find(y);
if(rootX==rootY){
//如果存在同一个集合中,则返回
return;
}
//选取rootY作为新集合的代表,把x所在集合合并到y集合
parent[rootX]=rootY;
}
我们在选取谁合并到谁时是随便选取的,实际上合理的选取能够很好地优化算法。
三、图示
1
2
3
4
5
6
7
8
9
10
1
1
1
9
2
5
9
1
9
7
find(6)即为parent[parent[parent[parent[6]]]]==1
find(7)即为parent[parent[7]]==9
union(6,7)
1
2
3
4
5
6
7
8
9
10
9
1
1
9
2
5
9
1
9
7
则rootX=1,rootY=9,即parent[1]=9
1
2
3
4
5
6
7
8
9
10
9
1
1
9
2
5
9
1
9
7
合并完如图:
四、算法优化上面提到合并是随意选取的,那么怎么选取可以优化算法呢.考虑find算法的过程,从低向上查找代表,那么树的高度就决定了find的快慢.所以我们合并时可以考虑把比较矮的树合并到比较高的树上,这样可以有效降低树的高度,从而达到优化算法的目的
启发式合并定义一个数组rank,记录每个节点的树高度,合并时,让较低的树合并到较高的树上,以达到有效降低树高的目的。
privateint[]rank;//记录树的高度
publicvoidunion(intx,inty){
introotX=find(x);
introotY=find(y);
if(rootX==rootY){
return;
}
//比较树高,让较低的树合并到较高的树上
if(rank[rootX]rank[rootY]){
parent[rootX]=rootY;
}elseif(rank[rootX]rank[rootY]){
parent[rootY]=rootX;
}else{
parent[rootY]=rootX;
rank[rootX]++;
}
}
图示:
union(6,7),因为6所在树比7所在树高且大,所以此时parent[9]=1
可以看到相比没有优化的算法,这种合并方式有效地降低了树高
1
2
3
4
5
6
7
8
9
10
1
1
1
9
2
5
9
1
1
7
路径压缩既然把树高降低能优化算法,那么我们能在find中降低树高吗?
我们可以在find中把查找路径上遇到的所有节点都直接链接到根节点,从而实现路径压缩,把树高降低。
代码十分简单,甚至不比上面的复杂.时间复杂度非常接近但是没有达到1
publicintfind(intx){
if(parent[x]!=x){
parent[x]=find(parent[x]);
}
returnparent[x];
}
路径压缩图示
合并6、7两棵树union(6,7)
先会调用find(6),find(7),查找路径上的所以元素都会直接和根节点链接。
1
2
3
4
5
6
7
8
9
10
1
1
1
9
1
1
9
1
9
7
之后parent[1]=9
1
2
3
4
5
6
7
8
9
10
9
1
1
9
1
1
9
1
9
7
五、小结
路径压缩加上启发式合并就是并查集算法的最优解.一般来说用路径压缩算法就足够了,可以不再用启发式合并或者加权
webrtc,srs,音视频
0
1438
一、go语言环境搭建srs4.0安装需要go语言环境,所以如果服务器没有配置过go语言环境的话,需要先配置go语言环境。下载安装包官网:https://golang.google.cn/dl/下载和解析:[root@localhostopt]cd/usr/local/[root@localhostlocal]wgethttps://dl.google.com/go/go1.16.5.linux-amd64.tar.gz--no-check-certificate[root@localhostlocal]tar-C/usr/local-xzfgo1.16.5.linux-amd64.tar.gz配置GOROOT和PATH环境变量,在/etc/profile中配置。vi/etc/profile#将环境变量添加到/etc/profile文件末尾。exportGOROOT=/usr/local/goexportPATH=$PATH:$GOROOT/bin:$GOBIN使用source/etc/profile命令使配置文件生效[root@localhostlocal]source/etc/profile查看安装是否成功[root@localhostlocal]goversiongoversiongo1.16.5linux/amd64二、srs源码下载编译我把源码下载到了/opt/文件夹下[root@VM-0-13-centosopt]#gitclone-b4.0releasehttps://gitee.com/ossrs/srs.git编译,注意需要切换到srs/trunk目录:[root@VM-0-13-centossignaling]#cd/opt/srs/trunk[root@VM-0-13-centostrunk]#./configure[root@VM-0-13-centostrunk]#make编译信令服务器,信令服务在srs/trunk/3rdparty/signaling文件夹下[root@VM-0-13-centostrunk]#cd./3rdparty/signaling[root@VM-0-13-centossignaling]#make三、启动srs和信令服务修改rtc配置文件vi/opt/srs/trunk/conf/rtc.conf#WebRTCstreamingconfigforSRS.#@seefull.conffordetailconfig.listen1935;max_connections1000;daemonoff;srs_log_tankfile;srs_log_file/var/log/srs.log;http_server{enabledon;listen8080;dir./objs/nginx/html;}http_api{enabledon;listen1985;}stats{network0;}rtc_server{enabledon;listen8000;#UDPport#@seehttps://ossrs.net/lts/zh-cn/docs/v4/doc/webrtc#config-candidatecandidatedemo.com;}vhost__defaultVhost__{rtc{enabledon;#@seehttps://ossrs.net/lts/zh-cn/docs/v4/doc/webrtc#rtmp-to-rtcrtmp_to_rtcoff;#@seehttps://ossrs.net/lts/zh-cn/docs/v4/doc/webrtc#rtc-to-rtmprtc_to_rtmpoff;}http_remux{enabledon;mount[vhost]/[app]/[stream].flv;}}主要修改的配置如下:修改srs_log_tank,日志输出方式,原来是console,改成输出到文件file添加srs_log_file,配置日志文件路径值/var/log/srs.log修改candidate,改成服务端ip或域名启动srs服务,路径/opt/srs/trunk[root@VM-0-13-centostrunk]#./objs/srs-c./conf/rtc.conf&默认端口是:1985启动信令服务:[root@VM-0-13-centostrunk]#nohup./3rdparty/signaling/objs/signaling/var/log/signaling.log&disown默认端口是:1989三、配置nginx代理nginx安装#检查和安装nginx依赖[root@localhostlocal]#yum-yinstallgcczlibzlib-develpcre-developensslopenssl-devel#下载nginx[root@localhostlocal]#wgethttp://nginx.org/download/nginx-1.13.7.tar.gz#解压并进入目录[root@localhostlocal]tar-zxvfnginx-1.13.7.tar.gz[root@localhostnginx-1.13.7]cdnginx-1.13.7/#创建nginx安装目录[root@localhostnginx-1.13.7]mkdir/usr/local/nginx#配置,注意要配置安装ssl模块[root@localhostnginx-1.13.7]./configure--prefix=/usr/local/nginx/--pid-path=/var/run/nginx.pid--with-http_ssl_module#编译和安装[root@localhostnginx-1.13.7]make&&makeinstall[root@localhostnginx-1.13.7]test-d#启动nginx[root@localhostnginx-1.13.7]/usr/local/nginx/sbin/nginx生成ssl证书具体说明参考:https://www.cnblogs.com/pcx105/p/15434332.htmlopensslgenrsa-des3-outserver.key2048#需要输入两次密码,至少四位opensslrsa-inserver.key-outserver.key#需要输入密码opensslreq-new-x509-keyserver.key-outca.crt-days3650opensslreq-new-keyserver.key-outserver.csropensslx509-req-days3650-inserver.csr-CAca.crt-CAkeyserver.key-CAcreateserial-outserver.crtcatserver.keyserver.crtserver.pem修改nginx配置文件server{listen80;##配置httpslisten443ssl;##配置域名server_namewww.demo.com;#charsetkoi8-r;#access_loglogs/host.access.logmain;##配置证书ssl_certificate/usr/local/nginx/conf/ssl/server.pem;ssl_certificate_key/usr/local/nginx/conf/ssl/server.key;ssl_protocolsTLSv1TLSv1.1TLSv1.2;ssl_ciphersECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;ssl_prefer_server_cipherson;ssl_session_cacheshared:SSL:10m;ssl_session_timeout10m;##srs提供的demo文件路径location/{root/opt/srs/trunk/objs/nginx/html/;}##配置信令服务地址location/sig{proxy_set_headerHost$host;proxy_set_headerX-Real-IP$remote_addr;proxy_read_timeout3600s;proxy_set_headerUpgrade$http_upgrade;proxy_set_headerConnection"upgrade";proxy_set_headerX-Forwarded-For$proxy_add_x_forwarded_for;proxy_set_headerX-NginX-Proxytrue;proxy_passhttp://127.0.0.1:1989/sig;}##配置rtc服务location/rtc{proxy_http_version1.1;proxy_set_headerUpgrade$http_upgrade;proxy_set_headerConnection"Upgrade";proxy_passhttp://127.0.0.1:1985;}error_page500502503504/50x.html;location=/50x.html{roothtml;}}rtc服务端口是8000/udp,服务器需要放开该端口。firewall-cmd--zone=public--add-port=8000/udp--permanentfirewall-cmd--zone=public--add-port=443/tcp--permanentfirewall-cmd--reload因为webrtc必须在https、或localhost环境下才能访问,所以外网访问需要配置ssl,如果是在外网环境搭建,那么证书可以去阿里云购买,或申请免费的,服务都启动完成之后直接访问域名即可访问webrtc的测试页面。如果是在vm虚拟机上搭建的测试环境,则需要生成证书,证书生成完成后,在nginx上配置即可四、测试访问测试页面:https://192.168.127.128/点击进入srs播放器推流拉流
blog
javascript 计算值所占的百分比
前端
0
1134
js计算值所占的百分比:functiongetPercentValue(arr){//求和letsum=0;if(sum=0){for(leti=0;iarr.length;i++){sum+=arr[i];}}//10的2次幂是100,用于计算精度。letdigits=1;//扩大比例100letvotesPerQuota=[];for(leti=0;iarr.length;i++){letva
blog
java计算值所占的百分比
java基础,算法基础
0
998
输入一个整数数组a,输出一个同样长度的数组b表示对应a数组各个位置上的元素值占a数组总值的百分比。publicstaticdouble[]getPercentValue(int[]arr){//求和doublesum=0;if(sum=0){for(inti=0;iarr.length;i++){sum+=arr[i];}}//10的2次幂是100,用于计算精度。doubledigits=1;//
blog
java实现mqtt客户端案例
mqtt协议
0
971
pom依赖dependencygroupIdorg.eclipse.paho/groupIdartifactIdorg.eclipse.paho.client.mqttv3/artifactIdversion1.2.0/version/dependency发布端importorg.eclipse.paho.client.mqttv3.MqttClient;importorg.eclipse.pah
blog
{{data.title}}
{{data.type}}
{{data.createTime}}
{{data.praise}}
{{data.viewNum}}
{{data.description}}
今日推荐
没有一个冬天不可逾越,没有一个春天不会来临。最慢的步伐不是跬步,而是徘徊,最快的脚步不是冲刺,而是坚持。