首页 文章 精选 留言 我的

精选列表

搜索[递归超智能],共10000篇文章
优秀的个人博客,低调大师

超6100万可穿戴设备用户信息被曝光

随着更多的设备连接到互联网,不断存储和分享信息,数据安全已经成为一个长期关注的问题。网络安全研究员 Jeremiah Fowler 在 WebsitePlanet 上发布报告,表示由于一个集中式数据库并未受到保护,有超过 6100 万可穿戴设备的用户数据在网络上曝光。 Fowler 和他的团队通过扫描分析,发现 GetHealth 的数据库存在暴露风险。这是一个为从数百个可穿戴设备、医疗设备和应用程序访问健康和保健数据的统一解决方案的 API。 进一步的调查显示,这些数据包含潜在的敏感信息,包括人们的姓名、出生日期、体重、身高、性别,甚至地理位置。此外,研究人员发现,这些信息的流向可以追溯到 Fitbit、Microsoft Band、Misfit Wearables、Google Fit 和 Strava等来源,其用户来自世界各地。所有这些信息都是以纯文本形式存储的,而一个 ID 是加密的。 在确认了数据的所有权后,福勒私下联系了GetHealth,该公司对通知的反应很快。该公司在同一天晚些时候对研究人员表示感谢,声称该问题已经解决。不过,目前还不清楚这 16.71GB 的用户数据被暴露了多长时间,甚至也不清楚在此期间谁可能访问了该数据库。

优秀的个人博客,低调大师

数据泄露平均消耗成本已超420万美元

据外媒报道,由IBM安全部委托进行的一项全球研究发现,近三年来数据泄露的平均成本已超过420万美元。该研究在2020年5月至2021年3月期间考察了全球500家机构。结果显示,有14家公司被确认遭受了重大的数据泄露,涉及1000多万条记录的泄露,造成5200万美元损失,到涉及6500多万条记录的泄露事件,损失4.01亿美元不等。 研究显示,企业识别和控制漏洞所需的天数比前一年多了7天,平均为287.7天。数据泄露的成本中值比前一年增长了大约10%,从386万美元增长到424万美元。 研究还发现,近一半的违规事件涉及到个人信息暴露。每条个人信息暴露的平均成本为180美元,而每条记录的平均总成本为161美元,这两个数字都高于前一年的中位数146美元。医疗保健行业连续11年发生了最大的数据泄露平均成本,为923万美元,高于前一年的713万美元。另一方面,能源行业的数据泄露的平均成本在同一时期从639万美元下降到465万美元。 鸿蒙官方战略合作共建――HarmonyOS技术社区 【责任编辑:赵宁宁 TEL:(010)68476606】

优秀的个人博客,低调大师

华为ENSP模拟器安装和使用技巧-超详细

实验目的 在自己PC上完成华为模拟器ENSP的安装,建议安装模拟器版本510,如果510无法正常安装和使用,再尝试安装100或者200T。模拟器下载地址链接:链接 https://pan.baidu.com/s/1_JLr7ex71vhEJBElk7xpzw 提取码:g013 安装步骤: 第一步;右击软件-管理员运行,点下一步。 第二步;在此处安装进程会检索安装PC是否已经安装了所需软件,如果本机已经安装了所需软件,这些软件前面不会自动打√,如果未安装会自动打钩。默认就可以。 第三步;eNsp安装完毕后会自动安装vbox;点下一步即可; 第四步;请先别着急打开软件,请将本机电脑window自带防火墙临时关闭或者将ENSP相关进程加入白名单。控制面板-windows 防火墙-高级设置;如下; 打开“入站规则”,找到ensp及vbox相关进程,双击并修改允许连接。 切记一定要允许所有跟ensp、vbox相关进程; 第五步;以上操作完成后,在桌面上找到ENSP快捷方式双击打开,首次使用建议进行设备注册。 讲所有设备打上对勾,进行注册,一定要看到注册成功。 至此模拟器安装完毕,可以进行正常使用了。 接下来将演示eNSP的基本操作,熟悉eNSP中经常使用的一些菜单,掌握eNSP的使用技巧。先来熟悉下eNSP的工具栏,工具栏里的某些工具在本书后面也会有涉及,所以在这里先跟大家详细介绍一下。在eNSP主页面中的最上面,有一栏工具栏,如图所示。 如果需要新增网络设备,读者可以通过选择左侧的设备种类,再次选择设备型号,再在空白处点击即可,如图所示。这里只是通过路由器设备做了演示,其他设备的添加方法和路由器的添加方法是一致的,不做赘述。 通过以上方式可以依次添加多个不同类型的网络设备,然后再通过线缆进行连接,如图所示。 在网络拓扑中增加文字描述,通过选择工具栏中的“”,点击拓扑空白处输入文件即可,如图所示。 通过调色板工具,将两台网络设备划分进入指定区域。如图所示。 启动模拟设备时需要通过鼠标左键单击“”启动工具,开启拓扑中所有的模拟设备。也可以通过鼠标右击某台设备选择“启动”命令,单独开启某一台模拟设备,如图。 对设备进行操作的时候需要打开模拟设备的CLI命令行配置界面。此时可以通过鼠标左键单击“”工具,打开拓扑中所有设备的CLI命令行配置界面。也可以通过鼠标左键双机某台设备,单独打开某台设备的CLI命令行配置页面。打开CLI命令行配置页面后,就可以对设备进行操作了,比如修改一下设备的名字,如图所示。具体的设备操作命令有很多,相信部分读者也应该比较熟悉。本书后面也会涉及到更多命令的配置,届时在详细介绍。 操作完毕后,需要保存拓扑文件,此时选择工具栏中的“”工具,保存拓扑文件到本地目标目录即可,如图所示。 拓扑文件保存完毕后,在所保存文件的目标目录中会出现一个文件夹,文件夹中会出现拓扑文件和配置文件,下次使用的时候直接双击拓扑打开即可,如图所示。 想必大家对eNSP的操作有了一定的了解,本书后面的实验也全部都是使用eNSP模拟软件来演示,以上介绍的这些工具在后面实验中也会经常使用,所以大家一定要掌握这些工具的使用方法,为本书后面的实验打下基础。当然,还有一部分有关eNSP的使用的内容在本章节中未作介绍,因为以上介绍的内容完全满足本书后面实验的需求,大家可以通过访问华为官网下载eNSP使用指南查看更多eNSP使用的相关内容。

优秀的个人博客,低调大师

超详细的TCP、Sokcket和SuperSocket与TCP入门指导

kiba518脚本之家 作者 |kiba518 出品 | 脚本之家(ID:jb51net) 前言 本文主要介绍TCP、Sokcket和SuperSocket的基础使用。 创建实例模式的SuperSocket服务 首先创建控制台项目,然后Nuget添加引用SuperSocket.Engine。 然后编写服务代码,SuperSocket的服务代码主要是配置AppServer对象,因为AppServer已经很好的封装端口监听了。 代码如下所示: class Program { static AppServer appServer { get; set; } static void Main(string[] args) { var serverConfig = new SuperSocket.SocketBase.Config.ServerConfig(); serverConfig.Port = 5180; serverConfig.TextEncoding = "gb2312"; serverConfig.MaxConnectionNumber = 1000; appServer = new AppServer(); //配置 if (!appServer.Setup(serverConfig)) { Console.WriteLine("配置失败!"); return; } //启动 if (!appServer.Start()) { Console.WriteLine("启动失败!"); return; } Console.WriteLine("启动成功,按Q退出!"); appServer.NewSessionConnected += new SessionHandler<AppSession>(appServer_NewSessionConnected); appServer.SessionClosed += appServer_NewSessionClosed; appServer.NewRequestReceived += new RequestHandler<AppSession, StringRequestInfo>(appServer_NewRequestReceived); while (Console.ReadKey().KeyChar != 'q') { continue; } //停止 appServer.Stop(); Console.WriteLine("服务已停止"); Console.ReadKey(); } static void appServer_NewSessionConnected(AppSession session) { var count = appServer.SessionCount; Console.WriteLine($"服务端得到来自客户端的连接成功 ,当前会话数量:" + count); //这里也可以向会话的stream里写入数据,如果在这里向流写入数据,则客户端需要在Send之前先接收一次,不然的话,Send后接收的就是这条数据了 session.Send("连接成功"); } static void appServer_NewSessionClosed(AppSession session, CloseReason aaa) { var count = appServer.SessionCount; Console.WriteLine($"服务端 失去 来自客户端的连接" + session.SessionID + aaa.ToString()+ " 当前会话数量:" + count); } static void appServer_NewRequestReceived(AppSession session, StringRequestInfo requestInfo) { Console.WriteLine($"Key:" + requestInfo.Key + $" Body:" + requestInfo.Body); session.Send("我是返回值:" + requestInfo.Body); } } AppServer:AppServer是SuperSocket中定义的Socket服务类,他替我们实现了复杂的端口监听,不用再写While循环,不用再关心线程阻塞的问题,在监听端口在这里,我们只要调用AppServer的对象的Start方法,就可以了;AppServer还提供了一个配置文件类—ServerConfig,通过它,我们可以配置具体监听的端口、并发数量、编码、最大传输字节数、传输模式(TCP/UDP)等等属性;此外还提供三个重要事件:会话连接启动事件(NewSessionConnected)、会话关闭事件(SessionClosed)、请求接受事件(NewRequestReceived)。 注:文中在连接成功的事件中,我们向客户端发送消息了,即,客户端在连接后,发送消息前,需要接收该信息。 创建TCP发送消息客户端 服务建立后,我们建立客户端。 代码如下所示: staticvoidMain(string[]args){TCPConnect("127.0.0.1",5180);Console.ReadKey();}staticvoidTCPConnect(Stringserver,Int32port){stringmessage=$"ADDkiba518518"+"\r\n";try{TcpClientclient=newTcpClient();client.Connect(server,port);Byte[]data=System.Text.Encoding.Default.GetBytes(message);StringresponseData=String.Empty;NetworkStreamstream=client.GetStream();byte[]buffer=newbyte[1024*1024*2];Int32bytes=stream.Read(buffer,0,buffer.Length);responseData=System.Text.Encoding.Default.GetString(buffer,0,bytes);Console.WriteLine("接收服务器在连接事件中写入的数据:{0}",responseData);stream.Write(data,0,data.Length);Console.WriteLine("发送数据:{0}",message);data=newByte[256];bytes=stream.Read(buffer,0,buffer.Length);responseData=System.Text.Encoding.Default.GetString(buffer,0,bytes);Console.WriteLine("接收返回值:{0}",responseData);stream.Close();client.Close();}catch(ArgumentNullExceptione){Console.WriteLine("ArgumentNullException:{0}",e.Message);}catch(SocketExceptione){Console.WriteLine("SocketException:{0}",e.Message);}Console.Read();} 代码很简单,就是使用TcpClient连接服务器的IP和端口,然后发送消息。 因为我们使用的SuperSocket,有格式要求,所以我们需要准守。 格式要求如下: 命令名称+空格+参数+参数+...参数+"\r\n" 对应的字符串如下: $"ADD kiba518 518" + "\r\n" 因为上文中,服务在连接成功后就向客户端发送的流中写入了数据,所以,我们在Send消息前,先接收一下流中的数据。 客户端与服务联调 先运行服务,在运行客户端,结果服务端与客户端成功的完成了一次通信,如下图所示: 为了更清晰的了解通信内容,我们在服务接收消息事件中断点,如下图: 可以看到参数requestInfo完整的解析了我们发送的字符串【"ADD kiba518 518" + "\r\n"】。 创建配置模式的SuperSocket服务 现在我们创建一个配置模式的SuperSocket服务,这种模式客户通过配置创建多个SuperSocket,即可以在一个项目里通过配置监听多个端口,这里,我们只做一个端口监听的配置例子。 与实例模式的开始一样,先创建一个控制台程序,然后Nuget添加引用SuperSocket.Engine。 然后进行三步操作。 一,编写Main函数,启动SuperSocket,通过启动引导工厂BootstrapFactory实例化一个启动引导对象,然后初始化化,该初始化会遍历当前项目中所有继承了AppServer的类,然后调用他们的Start方法,代码如下所示: static void Main(string[] args){ #region 初始化Socket IBootstrap bootstrap = BootstrapFactory.CreateBootstrap(); if (!bootstrap.Initialize()) { Console.WriteLine(DateTime.Now + ":Socket初始化失败\r\n"); return; } var result = bootstrap.Start(); foreach (var server in bootstrap.AppServers) { if (server.State == ServerState.Running) { Console.WriteLine(DateTime.Now + ":serverName为:" + server.Name + "Socket运行中\r\n"); } else { Console.WriteLine(DateTime.Now + ":serverName为:" + server.Name + "Socket启动失败\r\n"); } } Console.ReadKey(); #endregion} 二,修改App.config配置文件,在configuration节点下,增加superSocket的section,并配置superSocket,代码如下: <configSections><sectionname="superSocket"type="SuperSocket.SocketEngine.Configuration.SocketServiceConfig,SuperSocket.SocketEngine"/></configSections><!--配置SocketServer路径--><superSocket><servers><!--serverType属性有两个参数,第一个是服务类的完全限定名,第二个是服务类的命名空间--><servername="MySocket"textEncoding="gb2312"serverType="SuperSocketServerSessionMode.SocketServer,SuperSocketServerSessionMode"ip="Any"port="5180"maxConnectionNumber="100"></server></servers></superSocket> 三,创建SocketServer类、SocketSession类、SocketCommand类。 SocketServer类:继承泛型AppServer(其泛型类指定一个会话类)该类用于创建SuperSocket的服务并监听端口;其Setup方法,默认读取App.config配置文件中的superSocket节点—servers节点—server节点;读取时根据server的serverType属性匹配读取。 publicclassSocketServer:AppServer<SocketSession>{protectedoverrideboolSetup(IRootConfigrootConfig,IServerConfigconfig){Console.WriteLine("正在准备配置文件");returnbase.Setup(rootConfig,config);}protectedoverridevoidOnStarted(){Console.WriteLine("服务已开始");base.OnStarted();}protectedoverridevoidOnStopped(){Console.WriteLine("服务已停止");base.OnStopped();}protectedoverridevoidOnNewSessionConnected(SocketSessionsession){Console.WriteLine("新的连接地址为"+session.LocalEndPoint.Address.ToString()+",时间为"+DateTime.Now);base.OnNewSessionConnected(session);}} SocketSession类:继承AppSession,是SuperSocket的会话类。 如果客户端所发送的消息不合法,则会被会话的HandleUnknownRequest函数截获,如果合法,则发送到指定的命令类中。 代码如下: publicclassSocketSession:AppSession<SocketSession>{publicoverridevoidSend(stringmessage){Console.WriteLine("发送消息:"+message);base.Send(message);}protectedoverridevoidOnSessionStarted(){Console.WriteLine("Session已启动");base.OnSessionStarted();}protectedoverridevoidOnInit(){this.Charset=Encoding.GetEncoding("gb2312");base.OnInit();}protectedoverridevoidHandleUnknownRequest(StringRequestInforequestInfo){Console.WriteLine($"遇到未知的请求Key:"+requestInfo.Key+$"Body:"+requestInfo.Body);base.HandleUnknownRequest(requestInfo);}} SocketCommand类:是SuperSocket的命令类,定义明确的会话命令;类名即客户端发送消息的第一个空格前的字符串。 代码如下: publicclassSocketCommand:CommandBase<SocketSession,StringRequestInfo>{publicoverridevoidExecuteCommand(SocketSessionsession,StringRequestInforequestInfo){//根据参数个数或者其他条件判断,来进行一些自己的操作Console.WriteLine($"调用成功Key:"+requestInfo.Key+$"Body:"+requestInfo.Body);session.Send("已经成功接收到你的请求\r\n");}} 创建配置模式的SuperSocket客户端 创建一个配置模式的SuperSocket客户端,这一次我们使用Socket类创建。 代码如下: staticSocketsocketClient{get;set;}staticvoidMain(string[]args){socketClient=newSocket(SocketType.Stream,ProtocolType.Tcp);IPAddressip=IPAddress.Parse("127.0.0.1");IPEndPointpoint=newIPEndPoint(ip,5180);socketClient.Connect(point);Threadthread=newThread(Recive);//不停的接收服务器端发送的消息thread.Start();Threadthread2=newThread(Send);//不停的给服务器发送数据thread2.Start();}staticvoidRecive(){while(true){//获取发送过来的消息byte[]buffer=newbyte[1024*1024*2];vareffective=socketClient.Receive(buffer);if(effective==0){break;}varstr=Encoding.Default.GetString(buffer,0,effective);Console.WriteLine("服务器---"+str);Thread.Sleep(2000);}}staticvoidSend(){inti=0;intparam1=0;intparam2=0;while(true){i++;param1=i+1;param2=i+2;Console.WriteLine($"Sendi:{i}param1:{param1}param2:{param2}");stringmsg=$"SocketCommand{param1}{param2}"+"\r\n";Console.WriteLine($"msg:{msg}");varbuffter=Encoding.Default.GetBytes(msg);vartemp=socketClient.Send(buffter);Console.WriteLine($"Send发送的字节数:{temp}");Thread.Sleep(1000);}} 可以看到Socket的使用方式与Tcp的使用方式几乎相同,都是指定IP和端口号,只是Socket多了一步,需要指定协议类型ProtocolType,这里我们指定了是TCP。 客户端与服务联调 先运行服务,在运行客户端,结果通信成功,如下图所示: 到此TCP、Sokcket和SuperSocket的基本使用已经介绍完了,代码已经传到Github上了,欢迎大家下载。 Github地址:https://github.com/kiba518/SuperSocketConsole 本文作者:kiba518,.NET系统架构师 声明:本文为 脚本之家专栏作者 投稿,未经允许请勿转载。

优秀的个人博客,低调大师

基于redis和shedlock实现分布式锁(超简单)

一、背景 线上部署了两台服务器,通过nginx轮询的方式进行负载均衡。但是这样存在一个问题同一个用户的session共享问题。你或许会说,使用ipHash模式就可以解决session共享的问题,是的确实可以解决这个问题,但是同样也会带来另外一个问题,就是一台服务器很繁忙,另外一台服务器闲置的情况。所以为了避免服务器闲置的现象,我们采用了ip轮询和共享session存入redis的解决方案。不过今天要讲的主题不是这个,我们在单机测试的时候完全运行正常,但是部署了到正式的环境的时候出现了客户支付金额对应不上的情况。后来经过排查发现是并发问题,虽然单机做了并发处理,但是如果有多台服务器的时候就会出现服务器之间的并发问题。所以需要引入分布式锁,解决多服务器间的。 二、分布式锁的实现 1. jar包的引入 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>net.javacrumbs.shedlock</groupId><artifactId>shedlock-provider-redis-spring</artifactId><version>2.3.0</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.0</version></dependency><dependency><groupId>net.javacrumbs.shedlock</groupId><artifactId>shedlock-spring</artifactId><version>2.3.0</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--swagger--><!--https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui--><dependency><groupId>com.github.xiaoymin</groupId><artifactId>swagger-bootstrap-ui</artifactId><version>1.9.6</version></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.2</version></dependency> 2. redis的配置 配置文件 #redisredis.host=192.168.1.6redis.password=redis.port=6379redis.taskScheduler.poolSize=100redis.taskScheduler.defaultLockMaxDurationMinutes=10redis.default.timeout=10redisCache.expireTimeInMilliseconds=1200000 配置类 packagecom.example.redis_demo_limit.redis;importio.lettuce.core.ClientOptions;importio.lettuce.core.resource.ClientResources;importio.lettuce.core.resource.DefaultClientResources;importnet.javacrumbs.shedlock.core.LockProvider;importnet.javacrumbs.shedlock.provider.redis.spring.RedisLockProvider;importnet.javacrumbs.shedlock.spring.ScheduledLockConfiguration;importnet.javacrumbs.shedlock.spring.ScheduledLockConfigurationBuilder;importorg.apache.commons.pool2.impl.GenericObjectPoolConfig;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.context.annotation.Primary;importorg.springframework.data.redis.connection.RedisConnectionFactory;importorg.springframework.data.redis.connection.RedisPassword;importorg.springframework.data.redis.connection.RedisStandaloneConfiguration;importorg.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;importorg.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;importorg.springframework.data.redis.core.RedisTemplate;importjava.time.Duration;@ConfigurationpublicclassRedisConfig{@Value("${redis.host}")privateStringredisHost;@Value("${redis.port}")privateintredisPort;@Value("${redis.password}")privateStringpassword;@Value("${redis.taskScheduler.poolSize}")privateinttasksPoolSize;@Value("${redis.taskScheduler.defaultLockMaxDurationMinutes}")privateintlockMaxDuration;@Bean(destroyMethod="shutdown")ClientResourcesclientResources(){returnDefaultClientResources.create();}@BeanpublicRedisStandaloneConfigurationredisStandaloneConfiguration(){RedisStandaloneConfigurationredisStandaloneConfiguration=newRedisStandaloneConfiguration(redisHost,redisPort);if(password!=null&&!password.trim().equals("")){RedisPasswordredisPassword=RedisPassword.of(password);redisStandaloneConfiguration.setPassword(redisPassword);}returnredisStandaloneConfiguration;}@BeanpublicClientOptionsclientOptions(){returnClientOptions.builder().disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS).autoReconnect(true).build();}@BeanLettucePoolingClientConfigurationlettucePoolConfig(ClientOptionsoptions,ClientResourcesdcr){returnLettucePoolingClientConfiguration.builder().poolConfig(newGenericObjectPoolConfig()).clientOptions(options).clientResources(dcr).build();}@BeanpublicRedisConnectionFactoryconnectionFactory(RedisStandaloneConfigurationredisStandaloneConfiguration,LettucePoolingClientConfigurationlettucePoolConfig){returnnewLettuceConnectionFactory(redisStandaloneConfiguration,lettucePoolConfig);}@Bean@ConditionalOnMissingBean(name="redisTemplate")@PrimarypublicRedisTemplate<Object,Object>redisTemplate(RedisConnectionFactoryredisConnectionFactory){RedisTemplate<Object,Object>template=newRedisTemplate<>();template.setConnectionFactory(redisConnectionFactory);returntemplate;}@BeanpublicLockProviderlockProvider(RedisConnectionFactoryconnectionFactory){returnnewRedisLockProvider(connectionFactory);}@BeanpublicScheduledLockConfigurationtaskSchedulerLocker(LockProviderlockProvider){returnScheduledLockConfigurationBuilder.withLockProvider(lockProvider).withPoolSize(tasksPoolSize).withDefaultLockAtMostFor(Duration.ofMinutes(lockMaxDuration)).build();}} 操作类 packagecom.example.redis_demo_limit.redis;publicinterfaceDataCacheRepository<T>{booleanadd(Stringcollection,Stringhkey,Tobject,Longtimeout);booleandelete(Stringcollection,Stringhkey);Tfind(Stringcollection,Stringhkey,Class<T>tClass);BooleanisAvailable();/***redis加锁**@paramkey*@paramsecond*@return*/Booleanlock(Stringkey,Stringvalue,Longsecond);ObjectgetValue(Stringkey);/***redis解锁**@paramkey*@return*/voidunLock(Stringkey);voidsetIfAbsent(Stringkey,longvalue,longttl);voidincrement(Stringkey);Longget(Stringkey);voidset(Stringkey,longvalue,longttl);voidset(Objectkey,Objectvalue,longttl);ObjectgetByKey(Stringkey);voidgetLock(Stringkey,StringclientID)throwsException;voidreleaseLock(Stringkey,StringclientID);booleanhasKey(Stringkey);} 实现类 packagecom.example.redis_demo_limit.redis;importcom.fasterxml.jackson.databind.ObjectMapper;importlombok.extern.slf4j.Slf4j;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.data.redis.core.RedisTemplate;importorg.springframework.data.redis.core.ValueOperations;importorg.springframework.data.redis.support.atomic.RedisAtomicLong;importorg.springframework.stereotype.Repository;importjava.time.Duration;importjava.util.TimeZone;importjava.util.concurrent.TimeUnit;@Slf4j@RepositorypublicclassCacheRepository<T>implementscom.example.redis_demo_limit.redis.DataCacheRepository<T>{privatestaticfinalObjectMapperOBJECT_MAPPER;privatestaticfinalTimeZoneDEFAULT_TIMEZONE=TimeZone.getTimeZone("UTC");static{OBJECT_MAPPER=newObjectMapper();OBJECT_MAPPER.setTimeZone(DEFAULT_TIMEZONE);}Loggerlogger=LoggerFactory.getLogger(CacheRepository.class);@AutowiredRedisTemplatetemplate;//andwe'reinbusiness@Value("${redis.default.timeout}00")LongdefaultTimeOut;publicbooleanaddPermentValue(Stringcollection,Stringhkey,Tobject){try{StringjsonObject=OBJECT_MAPPER.writeValueAsString(object);template.opsForHash().put(collection,hkey,jsonObject);returntrue;}catch(Exceptione){logger.error("Unabletoaddobjectofkey{}tocachecollection'{}':{}",hkey,collection,e.getMessage());returnfalse;}}@Overridepublicbooleanadd(Stringcollection,Stringhkey,Tobject,Longtimeout){LonglocalTimeout;if(timeout==null){localTimeout=defaultTimeOut;}else{localTimeout=timeout;}try{StringjsonObject=OBJECT_MAPPER.writeValueAsString(object);template.opsForHash().put(collection,hkey,jsonObject);template.expire(collection,localTimeout,TimeUnit.SECONDS);returntrue;}catch(Exceptione){logger.error("Unabletoaddobjectofkey{}tocachecollection'{}':{}",hkey,collection,e.getMessage());returnfalse;}}@Overridepublicbooleandelete(Stringcollection,Stringhkey){try{template.opsForHash().delete(collection,hkey);returntrue;}catch(Exceptione){logger.error("Unabletodeleteentry{}fromcachecollection'{}':{}",hkey,collection,e.getMessage());returnfalse;}}@OverridepublicTfind(Stringcollection,Stringhkey,Class<T>tClass){try{StringjsonObj=String.valueOf(template.opsForHash().get(collection,hkey));returnOBJECT_MAPPER.readValue(jsonObj,tClass);}catch(Exceptione){if(e.getMessage()==null){logger.error("Entry'{}'doesnotexistincache",hkey);}else{logger.error("Unabletofindentry'{}'incachecollection'{}':{}",hkey,collection,e.getMessage());}returnnull;}}@OverridepublicBooleanisAvailable(){try{returntemplate.getConnectionFactory().getConnection().ping()!=null;}catch(Exceptione){logger.warn("Redisserverisnotavailableatthemoment.");}returnfalse;}@OverridepublicBooleanlock(Stringkey,Stringvalue,Longsecond){Booleanabsent=template.opsForValue().setIfAbsent(key,value,second,TimeUnit.SECONDS);returnabsent;}@OverridepublicObjectgetValue(Stringkey){returntemplate.opsForValue().get(key);}@OverridepublicvoidunLock(Stringkey){template.delete(key);}@Overridepublicvoidincrement(Stringkey){RedisAtomicLongcounter=newRedisAtomicLong(key,template.getConnectionFactory());counter.incrementAndGet();}@OverridepublicvoidsetIfAbsent(Stringkey,longvalue,longttl){ValueOperations<String,Object>ops=template.opsForValue();ops.setIfAbsent(key,value,Duration.ofSeconds(ttl));}@OverridepublicLongget(Stringkey){RedisAtomicLongcounter=newRedisAtomicLong(key,template.getConnectionFactory());returncounter.get();}@Overridepublicvoidset(Stringkey,longvalue,longttl){RedisAtomicLongcounter=newRedisAtomicLong(key,template.getConnectionFactory());counter.set(value);counter.expire(ttl,TimeUnit.SECONDS);}@Overridepublicvoidset(Objectkey,Objectvalue,longttl){template.opsForValue().set(key,value,ttl,TimeUnit.SECONDS);}@OverridepublicObjectgetByKey(Stringkey){returntemplate.opsForValue().get(key);}@OverridepublicvoidgetLock(Stringkey,StringclientID)throwsException{Booleanlock=false;//重试3次,每间隔1秒重试1次for(intj=0;j<=3;j++){lock=lock(key,clientID,10L);if(lock){log.info("获得锁》》》"+key);break;}try{Thread.sleep(5000);}catch(InterruptedExceptione){log.error("线程休眠异常",e);break;}}//重试3次依然没有获取到锁,那么返回服务器繁忙,请稍后重试if(!lock){thrownewException("服务繁忙");}}@OverridepublicvoidreleaseLock(Stringkey,StringclientID){if(clientID.equals(getByKey(key))){unLock(key);}}@OverridepublicbooleanhasKey(Stringkey){returntemplate.hasKey(key);}} 三、使用方法 importcom.example.redis_demo_limit.annotation.LimitedAccess;importcom.example.redis_demo_limit.redis.DataCacheRepository;importlombok.extern.slf4j.Slf4j;importorg.springframework.web.bind.annotation.PostMapping;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjavax.annotation.Resource;importjava.util.UUID;@Slf4j@RestController@RequestMapping("/redis")publicclassRedisController{privatestaticfinalStringKEY="key";@ResourceprivateDataCacheRepositorydataCacheRepository;@LimitedAccess(frequency=1,second=1)@PostMapping("/add")publicStringadd(Stringstr){dataCacheRepository.set("str","addsuccess",200L);return"success";}//分布式锁使用示例@PostMapping("/pay")publicStringpay(StringuserName,Integeraccount){StringclientID=UUID.randomUUID().toString();//设置锁的过期时间,避免死锁Booleanlock=dataCacheRepository.lock(userName,clientID,6000L);if(!lock){log.info("未获取到锁{}",userName);return"程序繁忙,请稍后再试!";}try{//等待5s,方便测试Thread.sleep(5000);if(dataCacheRepository.hasKey(KEY)){LongaLong=dataCacheRepository.get(KEY);dataCacheRepository.set(KEY,aLong+account,-1);returnaccount+aLong+"";}else{dataCacheRepository.set(KEY,account,-1);returnaccount+"";}}catch(InterruptedExceptione){log.error(e.getMessage(),e);return"程序运行异常,请联系管理员!";}finally{if(clientID.equals(dataCacheRepository.getByKey(userName))){log.info("finally删除锁{}",userName);dataCacheRepository.unLock(userName);}}}} 四、结果测试 先在8082点击pay 再在8081点击pay 从结果来看,分布式锁起到了作用。很简单吧,还不来试一下! 本文分享自微信公众号 - 全民java空间(ljl236915692)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

从渲染原理出发探究Flutter内存泄漏(超详细)

作者:闲鱼技术-萧湘 背景 众所周知,内存的高低是评判一款app的性能优劣的重要的指标之一。作为开发者而言,都会尽可能的减少内存的使用,清除无用的内存块,从而减少整个app的内存使用量。这也是历来开发者是追求的目标。然而,开发者难免时常因为语言用法或者写法的缘故,导致该释放而未释放的对象迟迟未释放,从而内存泄漏,消耗殆尽内存空间,从而导致系统崩溃的情况。 如何更简单的帮助开发者分析、暴露且解决内存泄漏问题,几乎是每一个平台或框架、开发者亟需的一个的"标配"的feature。例如:苹果的instruments,Linux的Kmemleak等。但是对于flutter社区,缺少一款用得顺手的内存泄漏工具。对于使用flutter而言,因使用dart语言,通过形成渲染树提交到c++的skia进行渲染,从dart层到c++层拥有很长的渲染链路,使用者必须对整个渲染链路有通盘深刻的理解,才能深刻此时此刻的内存使用情况。 本文从flutter渲染原理出发,分析flutter的内存分配情况,理清渲染流程,提出一种基于渲染树个数的方式寻找内存泄漏的解决方案 flutter内存都包含哪些 虚拟内存还是物理内存? 当我们谈论内存时,通常说的是物理内存(Physical memory),同一个应用程序运行在不同机器或者操作系统上时,会因不同操作系统和机器的硬件条件的不同,分配的到物理内存大小会有所不同,但大致而言,一款应用程序所使用到的虚拟内存(Virtual Memory)而言便会大致一样,本文讨论的都值的是虚拟内存。 我们可以直观的理解,代码中操作的所有对象都是能用虚拟内存衡量,而不太关心对象是否存在于物理内存与否,只要能减少对象的应用,尽量少的持有对象,不管白猫黑猫,能减少对象的,都是“好猫”。 讨论flutter内存时,我们在谈论什么 flutter从使用的语言上,可以分成3大部分, Framework层 由Dart编写,开发者接触到顶层,用于应用层开发 Engine 层,由C/C++编写,主要进行图形渲染 Embedder层,由植入层语言编写,如iOS使用Objective-C/swift,Android使用java 当我们从进程角度谈论flutter应用的内存时,指的是这个三者所有的内存的总和。 为简化,这里可以简单的以使用者能直接接触的代码为边界,将其分成DartVM和native内存,DartVM指Dart虚拟机占用内存,而native内存包含Engine和平台相关的代码运行的内存。 既然说Flutter的使用者能接触到的最直接的对象都是使用Dart语言生成的对象,那么对于Engine层的对象的创建与销毁,使用者似乎鞭长莫及了?这就不得不说Dart虚拟机绑定层的设计了。 Dart绑定层如何工作 出于性能或者跨平台或其他原因,脚本语言或者基于虚拟机的语言都会提供c/c++或函数对象绑定到具体语言对象的接口,以便在语言中接着操控c/c++对象或函数,这层API称为绑定层。例如: 最易嵌入应用程序中的Lua binding ,Javascript V8 引擎的binding 等等。 Dart虚拟机在初始化时,会将C++声明的某个类或者函数和某个函数和Dart中的某个类或者绑定起来,依次注入Dart运行时的全局遍历中,当Dart代码执行某一个函数时,便是指向具体的C++对象或者函数。 下面是几个常见的绑定的几个c++类和对应的Dart类 flutter::EngineLayer --> ui.EngineLayer flutter::FrameInfo --> ui.FrameInfo flutter::CanvasImage --> ui.Image flutter::SceneBuilder --> ui.SceneBuilder flutter::Scene --> ui.Scene 以ui.SceneBuilder一个例子了解下Dart是如何绑定c++对象实例,并且控制这个c++实例的析构工作。 Dart层渲染过程是配置的layer渲染树,并且提交到c++层进行渲染的过程。ui.SceneBuilder便是这颗渲染树的容器 Dart代码调用构造函数ui.SceneBuilder()时,调用c++方法SceneBuilder_constructor 调用flutter::SceneBuilder的构造方法并生成c++实例sceneBuilder 因flutter::SceneBuilder 继承自内存计数对象RefCountedDartWrappable,对象生成后会内存计数加1 将生成c++实例sceneBuilder使用Dart的API生成一个WeakPersitentHandle,注入到Dart上下中。在这里之后,Dart便可使用这个builder对象,便可操作这个c++的flutter::SceneBuilder 实例。 程序运行许久后,当Dart虚拟机判断Dart 对象builder没有被任何其他对象引用时(例如简单的情况是被置空builder=null,也称为无可达性),对象就会被垃圾回收器(Garbage Collection)回收释放,内存计数将会减一 当内存计数为0时,会触发c++的析构函数,最终c++实例指向的内存块被回收 可以看到,Dart是通过将C/C++实例封装成WeakPersitentHandle且注入到Dart上下文的方式,从而利用Dart虚拟机的GC(Garbage Collection)来控制C/C++实例的创建和释放工作 更直白而言,只要C/C++实例对应的Dart对象能正常被GC回收,C/C++所指向的内存空间便会正常释放。 WeakPersistentHandle是什么 因为Dart对象在VM中会因为GC整理碎片化中经常移动,所以使用对象时不会直接指向对象,而是使用句柄(handle)的方式间接指向对象,再者c/c++对象或者实例是介乎于Dart虚拟机之外,生命周期不受作用域约束,且一直长时间存在于整个Dart虚拟机中,所以称为常驻(Persistent),所以WeakPersistentHandle专门指向生命周期与常在的句柄,在Dart中专门用来封装C/C++实例。 在flutter官方提供的Observatory工具中,可以查看所有的WeakPersistentHandle对象 其中Peer这栏也就是封装c/c++对象的指针 Dart对象的可达性 Dart对象释放会被垃圾回收器(Garbage Collection)进行释放,是通过判定对象是否还有可达性(availability)来达到的。可达性是指通过某些根节点出发,通过对象与对象间的引用链去访问对象,如可通过引用链去访问对象,则说明对象有可达性,否则无可达性。 黄色有可达性,蓝色无可达性 难以察觉的内存泄漏 看到这里我们会发现一个问题,其实我们很难从Dart侧难感知C/C++对象的消亡,因为Dart对象无统一的如同C++类一样的析构函数,一旦对象因为循环引用等的原因被长期其他对象长期引用,GC将无法将其释放,最终导致内存泄漏。 将问题放大一点,我们知道flutter是一个渲染引擎,我们通过编写Dart语言构建出一颗Widget树,进而经过绘制等过程简化成Element树,RenderObject树,Layer树,并将这颗Layer树提交至C++层,进而使用Skia进行渲染。 如果某个Wigdet树或Element树的某个节点长期无法得到释放,将可能造成他的子节点也牵连着无法释放,将泄漏的内存空间迅速扩大。 例如,存在两个A,B界面,A界面通过Navigator.push的方式添加B界面,B界面通过Navigator.pop回退到A。如果B界面因为某些写法的缘故导致B的渲染树虽然被从主渲染树解开后依然无法被释放,这会导致整个原来B的子树都无法释放。 通过检测渲染树节点来检测内存泄漏 基于上面的这一个情况,我们其实可以通过对比当前帧使用到的渲染节点个数,对比当前内存中渲染节点的个数来判断前一个界面释放存在内存泄漏的情况。 Dart代码中都是通过往ui.SceneBuilder添加EngineLayer的方式去构建渲染树,那么我们只要检测c++中内存中EngineLayer的个数,对比当前帧使用的EngineLayer个数,如果内存中的EngineLayer个数长时间大于使用的个数,那么我们可以判断存在有内存泄漏 依然以上次A页面pushB界面,B界面pop回退A界面为例子。正常无内存泄漏的情况下,正在使用的layer个数(蓝色),内存中的layer个数(橙色)两条曲线的虽然有波动,但是最终都会比较贴合。 但是在B页面存在内存泄漏的时候,退到A界面后,B树完全无法释放,内存中的layer个数(橙色)无法最终贴合蓝色曲线(正在使用的layer个数) 也就是说,对于渲染而言,如果代码导致Widget树或Element树长时间无法被GC回收,很可能会导致严重的内存泄漏情况。 如何导致内存泄漏? 目前发现异步执行的代码的场景(Feature, async/await,methodChan)长期持有传入的BuildContext,导致 element 被移除后,依然长期存在,最终导致以及关联的 widget, state 发生泄漏。 再继续看B页面泄漏的例子 正确与错误的写法的区别在于,错误的仅是在调用Navigator.pop之前,使用异步方法Future引用了BuildContext,便会导致B界面内存泄漏。 怎么发现泄漏点? 目前flutter内存泄漏检测工具的设计思路是,对比界面进入前后的对象,寻找出未被释放的对象,进而查看未释放的引用关系(Retaining path或Inbound references),再结合源码进行分析,最后找到错误代码。 使用Flutter自带的Observatory纵然可以一个一个查看每个泄漏对象的引用关系,但是对于一个稍微复杂一点的界面而言,最终生成的layer个数是非常庞杂的,想要在Observatory所有的泄漏对象中找到有问题的代码是一项非常庞杂的任务。 为此我们将这些繁杂的定位工作都进行了可视化。 我们这里将每一帧提交到engine的所有EngineLayer进行了一个记录,并且以折线图的形式记录下来,如果上文说的内存中的layer个数异常的大于使用中的layer个数,那么就可判断前一个页面存在有内存泄漏。 进而,还可以抓取当前页面的layer树的结构,用以辅助定位具体由哪个RenderObject树生成的Layer树,进而继续分析由哪个Element节点生成的RenderObject节点 或者也可以打印出WeakPersitentHandle的引用链辅助分析 但如今的痛点依然存在,依然需要通过查看Handle的引用链,结合源码的分析才能最终比较快捷的定位问题。这也是接下来亟需解决的问题。 总结与展望 我们这种从渲染树的角度去探寻flutter内存泄漏的方法,可以推广到所以其他Dart不同类型的对象。 开发者在编写代码时,需要时刻注意异步调用,以及时刻注意操纵的Element会否被引用而导致无法释放 闲鱼作为长期深耕flutter的团队,也在持续在flutter工具链中持续发力,当然也少不了这一重要的内存检测工具的深入开发,欢迎大家持续关注!

优秀的个人博客,低调大师

Nginx 安装 SSL 配置 HTTPS 超详细完整全过程

说到 [Nginx]() 服务器,个人认为最大特点就是轻量级和高性能。通过在几台不同的服务器上进行测试,发现它的并发能力特别强,并且相对而言吃的[内存]()少很多。目前已是绝大多数站长的首选 HTTP 和反向代理服务器。站长自己的网站,包括承接企业服务器运维服务所采用的都是 Nginx。Apache 当然也可以,如果有兴趣,可以看一下 Nginx 和 Apache 区别对比。 本文主要分享下 Nginx 安装 SSL 模块并且开启配置 HTTPS 的操作过程。 一、Nginx 的 SSL 模块安装 查看 nginx 是否安装 http_ssl_module 模块。 $ /usr/local/nginx/sbin/nginx -V 如果出现 configure arguments: –with-http_ssl_module, 则已安装(下面的步骤可以跳过,进入 nginx.conf 配置)。 下载 Nginx 安装包,当然是要去 Nginx 官网下载。 下载安装包到 src 目录 $ cd /usr/local/src $ wget http://nginx.org/download/nginx-1.15.9.tar.gz 解压安装包。 $ tar -zxvf nginx-1.15.9.tar.gz 配置 SSL 模块。 $ cd nginx-1.15.9 $ ./configure --prefix=/usr/local/nginx --with-http_ssl_module 使用 make 命令编译(使用make install会重新安装nginx),此时当前目录会出现 objs 文件夹。 用新的 nginx 文件覆盖当前的 nginx 文件。 $ cp ./objs/nginx /usr/local/nginx/sbin/ 再次查看安装的模块(configure arguments: –with-http_ssl_module说明ssl模块已安装)。 $ /usr/local/nginx/sbin/nginx -V nginx version: nginx/1.15.9 ... configure arguments: --with-http_ssl_module 二、SSL 证书部署 这里使用的是阿里云的免费证书,期限为1年,申请地址在此。 找不到阿里云免费ssl入口的可以参考文章:阿里云免费SSL HTTPS证书没有了?原来是被隐藏了!(图) 下载申请好的 ssl 证书文件压缩包到本地并解压(这里是用的 pem 与 key 文件,文件名可以更改)。 在 nginx 目录新建 cert 文件夹存放证书文件。 $ cd /usr/local/nginx $ mkdir cert 将这两个文件上传至服务器的 cert 目录里。这里使用 mac 终端上传至服务器的 scp 命令(这里需要新开一个终端,不要使用连接服务器的窗口): $ scp /Users/yourname/Downloads/ssl.pem root@xxx.xx.xxx.xx:/usr/local/nginx/cert/ $ scp /Users/yourname/Downloads/ssl.key root@xxx.xx.xxx.xx:/usr/local/nginx/cert/ scp [本地文件路径,可以直接拖文件至终端里面] [<服务器登录名>@<服务器IP地址>:<服务器上的路径>] 三、Nginx.conf 配置 编辑 /usr/local/nginx/conf/nginx.conf 配置文件: 配置 https server。注释掉之前的 http server 配置,新增 https server: server { # 服务器端口使用443,开启ssl, 这里ssl就是上面安装的ssl模块 listen 443 ssl; # 域名,多个以空格分开 server_name hack520.com www.hack520.com; # ssl证书地址 ssl_certificate /usr/local/nginx/cert/ssl.pem; # pem文件的路径 ssl_certificate_key /usr/local/nginx/cert/ssl.key; # key文件的路径 # ssl验证相关配置 ssl_session_timeout 5m; #缓存有效期 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; #加密算法 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #安全链接可选的加密协议 ssl_prefer_server_ciphers on; #使用服务器端的首选算法 location / { root html; index index.html index.htm; } } 将 http 重定向 https。 server { listen 80; server_name hack520.com www.hack520.com; return 301 https://$server_name$request_uri; } 四、重启 nginx $ /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf 如果 80 端口被占用,用kill [id]来结束进程: # 查看端口使用 $ netstat -lntp Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 21307/nginx: master tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 3072/sshd tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 21307/nginx: master # 结束 80 端口进程 $ kill 21307 再次重启 nginx: $ /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf 或者: service nginx restart 往期文章 Nginx系列教程(1)nginx基本介绍和安装入门 Nginx系列教程(2)nginx搭建静态资源web服务器 Nginx系列教程(3)nginx缓存服务器上的静态文件 Nginx系列教程(4)nginx处理web应用负载均衡问题以保证高并发 Nginx系列教程(5)如何保障nginx的高可用性(keepalived) Nginx系列教程(6)nginx location 匹配规则详细解说 Nginx系列教程(7)nginx rewrite配置规则详细说明 Nginx系列教程(8)nginx配置安全证书SSL Nginx系列教程(9)nginx 解决session一致性 Nginx系列教程(10)基于nginx解决前端访问后端服务跨域问题(Session和cookie无效)基于Nginx解决前端访问后端服务跨域问题(Session和cookie无效)")

优秀的个人博客,低调大师

2020 年恶意软件状况报告:Mac 威胁首次超 Windows

Malwarebytes Labs 发布了 2020 年恶意软件状况报告,该报告提供了从产品遥测、honey pots、intelligence,以及 Malwarebytes 威胁分析师和记者进行的其他研究中收集的数据集,以调查网络犯罪分子在 2019 年对消费者和企业造成的主要威胁。 Malwarebytes Labs 方面表示,其提供的分析内容包括了对 Mac 和 Windows PC,Android 和 iOS 的威胁,以及一些基于浏览器的攻击。此外,该团队还检查了消费者和企业对全球特定区域和行业所面临威胁的检测。并研究了 2019 年的数据隐私状况,包括州和联邦立法,以及一些大型科技公司的隐私失败与其他前瞻性政策并列。 该报告发现的一些威胁内容如下: 与针对 Windows PC 的威胁相比,Mac 威胁呈指数增长。 2019 年每个 Mac 端点平均 11 个威胁,几乎是 Windows 上每个端点 5.8 个威胁的平均值的两倍。总体而言,Mac 威胁同比增长了 400% 以上。 攻击性广告软件,特洛伊木马和 HackTools 主导了针对业务端点的全球威胁,比去年同期增长了 13%。 由特洛伊木马转为僵尸网络的 Emotet 和 TrickBot 在 2019 年回归,且威胁性名列前茅。特别是 TrickBot 的检测量比前一年增加了 50% 以上。 攻击企业的净新勒索软件活动达到历史最高水平,Ryuk 和 Sodinokibi 等勒索软件家族分别增长了 543% 和 820%。 要了解有关 Mac,Windows,Android 和 Web 一年中最大的威胁以及商业和法规中数据隐私状况的信息,可在此处查看完整的 2020 年恶意软件状况报告 。

优秀的个人博客,低调大师

GitHub 发布 2019 年年度报告,用户超 4000 万

GitHub 发布了 2019 年年度报告《The State of the Octoverse》,下边来看看一些主要数据。 全球用户超过 4 千万 目前 GitHub 上有超过 4000 万开发人员,其中有 80% 来自美国以外的地区。去年一年里有 1000 万新加入的开发者,2019 年创建第一个 repo 的人比 2018 年增加了 44%,还有 130 万人首次在开源中贡献。 组织正在跨时区进行协作,并依赖于开源软件 目前 GitHub 上有将近 300 万个组织帐户,它们来自世界各地,代表了公司、非营利组织与开源项目等的集体工作。其中,GitHub Enterprise Cloud 帐户来自 70 多个不同的国家。今年全球财富 50 强中有 35 家对开源做出了贡献,这反映出专有代码在很大程度上依赖于开源社区。 软件社区比以往任何时候都更加紧密地联系在一起 去年新创建了超过 4400 万个 repo,从医学上的机器学习和有关深度学习的学术论文,到各种各样的机器人,在这个基础上,开源项目的共享基础架构将所有软件联系在一起,并且它们的依赖关系十分紧密。 具体来看,平均而言,GitHub 上的每个公共和私有 repo 都依赖于 200 多个软件包,每个项目背后都有数百个依赖项。而且,如果按被依赖程度来查看前 50 个开源项目,可以看到,被依赖度最高的项目今年支持了超过 360 万个其它 repo,比如rails/rails、facebook/jest 与axios/axios 之类的项目对于全球代码已变得至关重要。 修复了超过 760 万个漏洞警报 安全性也是开源社区的一项工作,发现潜在的漏洞后,维护人员、开发人员、研究人员与工具生态系统都会协同工作,以确保代码安全。GitHub自 2017 年 11 月发布安全警报以来,目前已修复了超过 700 万条警报。 中国开发者相关 今年开源代码的使用在中国、印度和德国速度都有明显加快,其中中国的开发者 fork 并 clone 的项目比去年增加了 48%。 除了开源,整个 GitHub 上贡献方面的数据也在增加,从公共和私人贡献来看,亚洲的开发者社区在 2019 年增长迅速,其中亚洲贡献者中有 31% 来自中国。 更多 除了以上关于 GitHub 本身的数据,还一有些托管项目的数据: Python 成为 GitHub 上第二受欢迎的语言。 Dart 和 Rust 是增长最快的语言。 在过去三年中,使用 Jupyter Notebook 的同比增长超过 100%。 TensorFlow 的贡献者从 2238 涨长 25166 人。 详细报告可以查看: https://github.blog/2019-11-06-the-state-of-the-octoverse-2019 https://octoverse.github.com

优秀的个人博客,低调大师

如何使用阿里云搭建自己的云主机(超详细)

最近忙着弄一个项目,也没怎么更新,由于项目使用的是阿里云作为服务器,下面就简单说明下怎么搭建自己的云主机。如果只是练习,那学生党肯定要便宜的mini主机,阿里爸爸也提供了云翼计划让学生党进行学习,点击后选择弹性计算,登录你的淘宝账号,然后选择开通ecs服务器。选择云产品之前可先领取价值最高2000元优惠券以减少成本 建议使用Linux系统,一切为了学习嘛。购买完成到控制台,发现 点击服务器,可以看到 这就是你的主机ip,我们可以用ssh连接,账号密码是你购买时设置的。我用的SmarTTY,打开输入密码。 现在输入cat /proc/cpuinfo查看电脑的cpu信息 可以看到,9.5软妹币一个月,给你这个配置,运行Ubuntu来学习够够的,不多说,马爸爸良心! 接下来是开放端口的配置,因为阿里云是不能在主机上开放端口的,要到云服务器管理控制台上去设置,点击更多下面的安全组配置 点击配置规则 点击添加安全组规则 优先级越为1则级别最高,0.0.0.0/0表示所有ip都能连接,点击确定,mysql用的3306端口就映射出来了,在云主机上安装MySQL和平时你用的Ubuntu一样,不管你是直接安装还是Docker,只要映射到3306端口都能连上,Docker的简单配置之前文章有提到。等你安装好MySQL,现在你就可以用navicat连接并愉快的玩耍了。 数据库和表完全一样!这样你就可以把你的数据库放你的云主机上,对了云主机的硬盘有40G,可以够你存很多东西了,说到存取东西,还得给大家介绍一款软件WinSCP,这个非常强大,可以使用SSH连接直接向服务器传送文件 输入你的主机IP及用户名和密码,点击登录看到如下界面。 左边是本机文件目录,右边是云主机文件目录,选中文件,点击左上角的上传完成上传。

优秀的个人博客,低调大师

超详细的Python标准库介绍与基本使用方式!

趁着刚吃完饭偷个闲,写一篇关于Python标准库的详细操作,很简单的! 目录: Python 标准库概览概览 操作系统接口 os 模块提供了很多与操作系统交互的函数: 应该用 import os 风格而非 from os import *。这样可以保证随操作系统不同而有所变化的 os.open() 不会覆盖内置函数 open()。 在使用一些像 os 这样的大型模块时内置的 dir() 和 help() 函数非常有用: 针对日常的文件和目录管理任务,shutil 模块提供了一个易于使用的高级接口: glob 模块提供了一个函数用于从目录通配符搜索中生成文件列表: >>> import glob >>> glob.glob('*.py') ['primes.py', 'random.py', 'quote.py'] 命令行参数 x 通用工具脚本经常调用命令行参数。这些命令行参数以链表形式存储于 sys 模块的 argv 变量。例如在命令行中执行 python demo.py one two three 后可以得到以下输出结果: getopt 模块使用 Unix getopt() 函数处理 sys.argv。更多的复杂命令行处理由 argparse 模块提供。 错误输出重定向和程序终止 sys 还有 stdin, stdout 和 stderr 属性,即使在 stdout 被重定向时,后者也可以用于显示警告和错误信息: >>> sys.stderr.write('Warning, log file not found starting a new one ') Warning, log file not found starting a new one12 大多脚本的直接终止都使用 sys.exit()。 字符串正则匹配 re 模块为高级字符串处理提供了正则表达式工具。对于复杂的匹配和处理,正则表达式提供了简洁、优化的解决方案: 只需简单的操作时,字符串方法最好用,因为它们易读,又容易调试: >>> 'tea for too'.replace('too', 'two') 'tea for two' 数学 math 模块为浮点运算提供了对底层C函数库的访问: >>> import math >>> math.cos(math.pi / 4.0) 0.70710678118654757 >>> math.log(1024, 2) 10.0 random 提供了生成随机数的工具: 互联网访问 有几个模块用于访问互联网以及处理网络通信协议。其中最简单的两个是用于处理从 urls 接收的数据的 urllib.request 以及用于发送电子邮件的 smtplib: (注意第二个例子需要在 localhost 运行一个邮件服务器。) 日期和时间 datetime 模块为日期和时间处理同时提供了简单和复杂的方法。支持日期和时间算法的同时,实现的重点放在更有效的处理和格式化输出。该模块还支持时区处理。 数据压缩 以下模块直接支持通用的数据打包和压缩格式:zlib, gzip, bz2, lzma, zipfile 以及 tarfile。 性能度量 有些用户对了解解决同一问题的不同方法之间的性能差异很感兴趣。Python 提供了一个度量工具,为这些问题提供了直接答案。 例如,使用元组封装和拆封来交换元素看起来要比使用传统的方法要诱人的多。timeit 证明了后者更快一些: 相对于 timeit 的细粒度,profile 和 pstats 模块提供了针对更大代码块的时间度量工具。 质量控制 开发高质量软件的方法之一是为每一个函数开发测试代码,并且在开发过程中经常进行测试。 doctest 模块提供了一个工具,扫描模块并根据程序中内嵌的文档字符串执行测试。测试构造如同简单的将它的输出结果剪切并粘贴到文档字符串中。通过用户提供的例子,它发展了文档,允许 doctest 模块确认代码的结果是否与文档一致: unittest 模块不像 doctest 模块那么容易使用,不过它可以在一个独立的文件里提供一个更全面的测试集: “瑞士军刀” Python 展现了“瑞士军刀”的哲学。这可以通过它更大的包的高级和健壮的功能来得到最好的展现。列如: 好了,小编今天就分享到这,小伙伴们赶紧 去自己敲代码试试吧!

优秀的个人博客,低调大师

阿里云ECS建站超详细全套完整图文教程

第一步:如何以最低价格快速买到阿里云服务器? 1.1 如果我是学生,我如何通过¥9.9买到价值¥117的服务? 答:用¥9.9购买云服务器ECS是阿里云学生专属活动。首先,你需要在阿里云官网注册账号。然后在阿里云官网首页点击校园扶持,经学生认证后便可购买每月¥9.9的特价云服务器。活动内容如下图1.1。 1.2 如果我不是学生,我如何通过¥30买到价值¥117的服务? 答:首先,你需要在阿里云官网注册账号。然后点击阿里云官网首页的最新活动即可看到活动特价云服务器,此时你便可以通过¥30买到阿里云服务器。活动内容如下图1.2。 图1.1 学生专享服务器 图1.2 ¥30的服务器 1.3 我买云服务器时要选操作系统,服务器各操作系统有什么特点?怎么选? 答:Windows:操作简单,功能实用,安全性较差。 Linux:兼容性好、安全性很好、稳定,是目前大部分保密机构服务器操作系统都是它。(推荐,本文作者使用Linux,后文是Linux系统的建站教程) NetWare:批处理功能优秀,但目前市场占有率很少。 Unix:支持大型文件系统与数据库,对于系统应用软件支持较完善。 其他操作系统就不介绍了,想了解更多请搜索常见的操作系统及其优缺点比较。 PS:(1)除阿里云外,大多数云服务器公司(例如:西部××等)同配置云服务器的价格都在¥117左右。(2)如果看不懂配置,那就按照默认配置好了。 * 第二步:如何注册我的专属域名? 2.1 什么是域名?它有什么作用? 答:(1)按照百度百科解释,域名(Domain Name),是由一串用点分隔的名字组成的Internet上某一台计算机或计算机组的名称,用于在数据传输时标识计算机的电子方位。(例如:“baidu.com”)。(2)一个域名的作用是便于记忆和沟通的一组服务器的地址。 2.2 如何以最快方式注册域名? 答:登录阿里云,点击域名与网站(万网)-域名-域名注册,然后搜索你想注册的域名并进行购买,如图2.11和图2.12。 图2.1 搜索域名 图2.12 注册域名 PS:常见国际域名后缀:.com,.net,.top,tech,.ink,.info,.win等 常见国内域名后缀:.cn, .com.cn, .cx, .cc, .xin等 如果想了解更多域名后缀,请搜索域名后缀大全。 2.3 购买好域名后我就可以直接使用它吗? 答:不可以,域名只有经过备案审核后才能使用。 2.4 那我该如何备案呢? 答:(1)在阿里云登录后进入备案系统,申请备案。 (2)按表单要求填写真实的备案信息,然后点击提交。此操作需要证件照(身份证或其他有效证件)的正反面照片。 (3)提交申请后过一天或两天,阿里云工作人员会给你打电话,验证你的姓名和身份证后四位等信息,如果你回答全部正确,恭喜你,初审通过! (4)接下来你需要再次登录备案系统,申请幕布拍照,然后点击指定链接,网购一块价值¥15的幕布,以此为背景拍照再上传到备案系统。下图2.4是本文作者拍的照片。 (5)阿里云工作人员会对你的照片进行审核,照片审核通过后他们会把你的备案信息提交给省通信管理局审核,通信管理局一般会审核11—20天(本文作者只用了9天就审核通过了),审核通过后会发短信和邮件通知你。 图2.4 幕布拍照 PS:如果对备案还有疑问,请参考阿里云官方文档——首次备案图文引导。 * 第三步:我该如何控制我的云服务器?怎么用电脑和它传输文件呢? 3.1 是否有软件可以满足我控制云服务器的需求?我想用电脑和它传输文件怎么办? 答:的确有满足你需求的软件。那么我就向你推荐两款好用的软件并简单介绍一下这两个软件作用: (1)a.控制云服务器软件:Xshell b.能和电脑传输的软件:Xftp (2)我简单介绍一下这两款软件。Xshell:能在Windows界面下访问远端不同系统下的服务器。简单来说,你可以通过这款软件控制云服务器ECS。Xftp:基于 MSwindows平台的功能强大的SFTP、FTP文件传输软件。简单来说,通过这款软件你可以在你的电脑和云服务器之间传输文件。 PS:还有很多能实现类似功能的软件。如果你想了解更多,推荐你看看Putty、XShell、SecureCRT、SSH Secure Shell Slient哪个好用? 3.2 我觉得Xshell和Xftp不错!那我应该从哪里下载它们呢? 答:我都帮你整理好了。下面就贴出两个软件的下载地址: Xshell:Xshell官方下载链接 Xftp:Xftp官方下载链接 3.2 文中推荐的两个链接都挂了,我还有其他途径下载它们吗? 答:嘎嘎嘎!当然有!你可以下载本文作者百度云的分享文件: Xshell:Xshell百度云下载链接密码:kgig Xftp:Xftp百度云下载链接密码:lc01 PS:这两个文件下载好了后免安装,双击即可运行。 3.3 软件都下载好了!怎么使用Xshell和Xftp啊? 答:别着急,按照我下面步骤一步步做: (1)运行Xshell。 (2)新建会话属性,详细步骤请看下图3.32。 图3.32 新建会话属性 (3)连接会话,具体看下图3.33。 图3.33 连接会话 (4)输入用户名,具体看下图3.34。 图3.34 输入用户名 (5)输入密码,具体看下图3.35。注意:如果你忘记或者未设置你的密码可进入ECS控制台-实例列表-重置密码。重置密码成功后记得重启服务器。 图3.35 输入密码 (6)成功连接界面如下图3.36。 图3.36 成功连接服务器 (7)登录Xpft。这里介绍两种方法。a.点击Xshell上方导航栏的窗口-传输新建文件即可快速免密运行Xpft软件,具体看下图3.37。b.直接运行Xpft,输入用户名和密码后即可连接服务器。 图3.37 运行Xftp (8)Xftp运行界面如下图3.38。 图3.38 Xftp运行界面 第四步:如何在云服务器下部署Java Web项目? 4.1 在云服务器下部署 Java一共提供几种方式?不同方式优缺点是什么? 答:一共三种方式。这三种方式分别是Java镜像部署、一键安装包部署和手动部署。前两种方式优点是方便快捷,缺点是要花钱!而且价格个人觉得不便宜,Java镜像部署一个月要¥80,一键安装包部署虽然一次只要5块,但是本文作者没试过也就不好评价。而手动部署方式的优缺点正好与前两种方式相反,它优点是免费同时修炼了你的技术,缺点就是稍微费事了点。 4.2 我该选择哪种方式部署Java项目呢? 答:(1)如果你不差钱或者时间紧迫的话,你可以选择Java镜像部署或一键安装包部署。因为我没试过这两种方式,所以具体就不介绍了。具体操作方式请看阿里云官方介绍Java镜像部署或一键安装包部署。(2)如果你倾向于修炼技术的话,你还是选择手动部署吧,而我个人也推荐这个部署方式,下文我将详细介绍怎样手动部署。 4.3 手动部署需要做什么准备工作呢? 答:你需要下载在Java jdk安装包和Tomcat。我下面给出它们的官方下载链接: Java jdk:Java jdk官方下载链接(下载“jdk-序号-linux-x64.tar.gz”版本) Tomcat:Tomcat官方下载链接(点击首页左侧Tomcat 8,下载“tar.gz (pgp, md5, sha1)”) 4.4 jdk安装包我都下载好了,我该怎么安装jdk呢? 答:(1)首先打开Xshell和Xftp,用Xftp在云服务器创建文件夹,具体做法如下图4.41。 图4.41 创建文件夹 (2)将jdk安装包和tomcat安装包复制粘贴到云服务器对应的文件夹下。 (3)在Xshell输入指令,解压jdk安装包到指定文件夹,解码指令如下图4.43: tar-zxvf jdk-版本编号-linux-x64.tar.gz-C/usr/java/jdk/ 图4.43 解压指令 (4) 解压完毕后jdk文件夹里会有对应文件,开始配置环境变量,如下图4.44,具体指令如下: #vi /etc/profile export JAVA_HOME=/usr/java/jdk/jdk版本编号_121 export JRE_HOME=/usr/java/jdk/jdk版本编号_121/jre export CLASSPATH=.:$JAVA_HOME/lib$:JRE_HOME/lib:$CLASSPATH export PATH=$JAVA_HOME/bin:$JRE_HOME/bin/$JAVA_HOME:$PATH 图4.44 配置环境变量 编辑完内容后,按下Esc键,并输入“:wq”,然后回车可以保存退出。 (5)保存完毕后输入下面指令: #source /etc/profile (6)验证是否成功,如下图4.46,输入下面验证指令: # java -version 图4.46 jdk安装成功 4.5 jdk安装好了,那tomcat又要如何安装? 答:别着急!tomcat安装要轻松许多,具体安装步骤如下: (1)解压tomcat,解压指令如下: # tar -xvf apache-tomcat-版本编号.tar.gz -C /usr/java/tomcat/ 图4.51 解压tomcat (2)进入解压文件夹下的bin文件夹,指令如下: #cd/usr/java/tomcat/apache-tomcat-版本编号/bin/ 图4.52 进入指定文件夹 (3)编辑setclasspath.sh 脚本,指令如下: # vi setclasspath.sh (4) 添写如下内容: export JAVA_HOME=/usr/java/jdk/jdk版本编号 export JRE_HOME=/usr/java/jdk/jdk版本编号/jre (5)保存编辑内容,按下Esc键,并输入“:wq”,然后回车可以保存退出。 (6)启动tomcat,指令如下: #./startup.sh 图4.56 开启tomcat 4.6 jdk和tomcat都弄好了,接下来可以用浏览器访问我的云服务器吗? 答:当然可以!你可以从浏览器访问,输入http://云服务器的ip:8080就能访问啦!效果如下图4.6。 图4.6 访问成功 4.7 我部署自己的项目怎么做? 答:将项目上传到 Tomcat文件夹下的 Webapps 文件夹里就行。上传好了后,浏览器访问即可。例如:http://云服务器ip地址:8080/index/one.html等。 图4.7 部署自己项目 4.8 怎么通过我的域名访问我的网站呢? 答:别着急,你需要解析你的域名。你先登录阿里云,再控制台点击域名与网站(万网)下的域名,然后点击解析,请看下图4.8。解析好了后在浏览器输http://www.域名.com:8080即可访问。 图4.8 解析域名 感谢你的支持!如果你喜欢这个教程,可以点赞为我加油哟!谢谢啦!

优秀的个人博客,低调大师

超详细hadoop集群服务器安装配置教程

虚拟机以及Linux系统安装在之前的两篇分享中已经详细的介绍了方法,并且每一步的都配图了。如果有朋友还是看不懂,那我也爱莫能助了。本篇主要就hadoop服务器操作系统配置进行详细说明,hadoop安装会在下一篇文章中详细的介绍。 hadoop安装包用的是大快DKHadoop发行版,个人觉得DKHadoop的安装过程是比较简单,关于dkhadoop的安装在下一次的分享中再详细介绍吧。下面进入到本篇的主题——服务器操作系统配置教程 一、安装包准备 1、虚拟机分布式安装(三台及以上虚拟机) 若是个人电脑Windows系统或Linux系统,虚拟机上虚拟的三台服务器,则将安装包拷贝到服务器上,进行安装操作即可。 2、物理集群(三台及以上实体服务器) 1、 外网下载模式 2、 本地文件模式 将安装包文件直接拷贝到实体服务器root目录下,进行安装操作即可。 3、上传模式 当服务器在机房,且无显示和输入设备的情况下,应用该模式。 现将文件,安装在本地计算机上(默认为笔记本电脑,在机房现场),并将计算机与服务器连接,将安装包install、DKHInstall上传到服务器root目录下。 二、服务器操作系统配置教程 准备工作完成之后,就要进行服务器配置操作,首先必须三台服务器之间要互相ping通。所谓ping通,就是两台设备之间网络是通的。从一端发送一个数据包,另一端就能够收到,就代表两台设备是能够ping通了。 1、修改权限 目的:使install、DKHInstall两个安装包有可执行的权限。权限不足无法执行一些操作。install里面是脚本和所有组件,DKHInstall里面是安装界面。 步骤:在准备工作中拷贝安装包 install、DKHInstall到主节点目录后,修改文件权限。首先进入root目录,安装目录 install、DKHInstall的权限改为:文件所有者可读可写可执行,与文件所有者属于一个用户组的其他用户可读可执行,其他用户组可读可执行。 命令: cd /root/ unzip DKHPlantform.zip chmod -R 755 DKHPlantform 2、搭建Hadoop集群设置SSH免密登录 目的:Hadoop运行过程中需要管理远端Hadoop守护进程,在Hadoop启动以后,NameNode是通过SSH(Secure Shell)来启动和停止各个DataNode上的各种守护进程的。这就必须在节点之间执行指令的时候是不需要输入密码的形式,所以我们需要配置SSH运用无密码公钥认证的形式,这样NameNode使用SSH无密码登录并启动DataName进程,同样原理,DataNode上也能使用SSH无密码登录到NameNode。 步骤: (1)修改本机hosts文件,写入对应关系 为了区分局域网内的每台主机,都会给主机配一个主机名,每台主机之间又是通过IP进行通信,但IP地址不方便记忆,所以配置主机名和IP映射能够实现主机之间的快速方便的访问。 命令: vi /etc/hosts 通过按键盘上的insert或是I键进入编辑模式,编辑完成后按一下Esc键然后按一下按Shift+: 键,输入wq,后回车就可以保存。输入q!后回车则是放弃保存并退出. 进入编辑模式后,按照规则写入主机与ip的对应关系(主机名称dk41是自己命名的,如下图)例: 192.168.1.41 dk41 192.168.1.42 dk42 192.168.1.43 dk43 编辑完后,保存退出。把对应关系拷到其他两台或多台机器上。 命令: scp-r/etc/hosts192.168.1.42:/etc scp-r/etc/hosts192.168.1.43:/etc (2)执行集群之间免密前的准备工作 执行sshpass.sh的脚本的时候会去读sshhosts和sshslaves这两个文件,替换sshpass.sh中的master和slave文件。 修改文件sshhosts,输入全部机器的主机名,每行一个主机名(如下图) 命令: vi /root/DKHPlantform/autossh/sshhosts 通过按键盘上的insert或是I键进入编辑模式,编辑完成后按一下Esc键然后按一下按Shift+:键,输入wq,后回车就可以保存。输入q!后回车则是放弃保存并退出. 修改文件sshslaves,写入除主机名之外的所有机器名(如下图) 命令: vi /root/DKHPlantform/autossh/sshslaves 通过按键盘上的insert或是I键进入编辑模式,编辑完成后按一下Esc键然后按一下按Shift+:键,输入wq,后回车就可以保存。输入q!后回车则是放弃保存并退出. (3)执行集群免密工作 命令: cd /root/DKHPlantform/autossh ./autossh 主节点主机名 集群密码 例: ./autossh dk41 123456 (4)关闭防火墙 防止访问服务器时某些服务被拦截,需关闭防火墙。 命令: cd /root/DKHPlantform/autossh ./offIptables.sh 3、安装双机热备份的MySQL 目的:存放Hive的元数据 步骤: (1)从主节点分发mySQL安装目录到第二节点 命令: scp-r/root/DKHPlantform/mysqlInst/192.168.1.42:/root/ (2)主节点执行: 命令: cd /root/DKHPlantform/mysqlInst/ ./mysql.sh 1 从节点执行: 命令: cd /root/mysqlInst/ ./mysql.sh 2 (3)执行成功之后执行热备份(两台机器上都要执行,两个ip互换,41上写42,42上写41,密码是MySQL的密码为:123456。平台内已经设定好,请勿修改): 命令: source /etc/profile ./sync.sh 192.168.1.xxx(另一台mysql地址) 4、创建数据库 目的:MySQL是一种关联数据库管理系统,关联数据库将数据保存在不同的表中,增加了速度并提高了灵活性。 步骤: (1)导入MySQL数据表,只在主节点执行: 命令: mysql -uroot -p123456 < { 此处为sql文件,主目录下文件: dkh.sql} 如:mysql -uroot -p123456 </root/DKHPlantform/dkh.sql (2)执行完后查看一下两台mysql的数据表是否存在,从主节点中查看执行: 命令: mySQL-uroot-p123456showdatabases; use dkh; show tables; 5、启动安装 目的:服务器配置操作完成之后,启动DKH。 步骤:执行以下命令。 命令: cd /root/DKHPlantform/dkh-tomcat*/bin/ ./startup.sh 6、本地时间服务器搭建步骤 没联网或者装系统时时间未同步,需要搭建本地时间服务器。 (1)搭建内网的ntp服务器 修改/etc/ntp.conf 命令: Vim /etc/ntp.conf 通过按键盘上的insert或是I键进入编辑模式,编辑完成后按一下Esc键然后按一下按Shift+:键,输入wq后回车就可以保存。输入q!后回车则是放弃保存并退出. 修改下列三行: #server0.centos.pool.ntp.org #server1.centos.pool.ntp.org #server2.centos.pool.ntp.org 在文件最后添加下列两行: server127.127.1.0 fudge127.127.1.0stratum10 (2)启动ntp服务 service ntpd start (3)开机自动启动 chkconfig ntpd on (4)客户端同步时间 命令: Vim /etc/ntp.conf 通过按键盘上的insert或是I键进入编辑模式,编辑完成后按一下Esc键然后按一下按Shift+:键,输入wq,后回车就可以保存。输入q!后回车则是放弃保存并退出. 在文件最后添加一行: */15****root ntpdate192.168.27.35;hwclock-w

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册