首页 文章 精选 留言 我的

精选列表

搜索[基础搭建],共10000篇文章
优秀的个人博客,低调大师

Android--Service之基础

Service概述 与开发一个Activity类似,它需要继承Service这个抽象类,并在实现类中,需要重写一些回调方法,用于处理Service的生命周期各部分的操作。而Service也是继承自Context,因此它也可以调用Context里定义的如getResource()、getContentResolver()等方法。 Service中定义的生命周期方法,对Service服务的开发大部分工作就围绕以下几个方法进行操作: void onCreate():当该Service第一次被创建后将立即回调该方法。 void onStartCommand(Intent intent,int flags,int startId):每次通过startService()方法启动Service时都会被回调。 void onDestroy():当Service被关闭前会被回调。 abstract IBinder onBind(Intent intent):该方法是Service子类必须实现的方法,如果不需要通过绑定的方式启动服务,可以返回Null。 boolean onUnbind(Intent intent):当Service上绑定的所有客户端都断开连接将回调该方法。 通过服务的启动方式与适用范围,可将服务分为两类服务: start:启动服务,当一个Android组件(如一个Activity)调用startService()的时候,启动一个服务。服务一旦启动,就可以一直在后台运行下去,即使这个启动它的组件被摧毁。这样的服务模式,通常用于执行一个操作而不需要返回结果给调用者。 Bound:绑定服务,当一个Android组件(如一个Activity)调用bindService()。一个绑定服务提供了一个客户端到服务端的接口,允许组件与服务之间进行交互,这样可以实现跨进程的通信。绑定服务的生命周期默认是跟随它的绑定组件的,但是一个绑定服务可以绑定多个Android组件,如果这些Android组件都被销毁,那么这个绑定服务也将被销毁。 虽然上面提到了服务有两种类别,但是一个服务类所要继承的类是一样的,都是Service类。也就是说,一个服务,可以包含上面两种运行方式的服务,只是与它重载的方法有关,如果重写了onStartCommand()即支持启动服务,如果重写onBiind()即支持绑定服务,所以如果同时重载实现这两个方法即可实现两种服务。 而对于两种启动方式的服务,生命周期中被回调的方法也不一样,下图明确说明了Service两种情况下的生命周期: 清单文件的配置 Service是Android四大组件之一,所以它也必须在AndroidManifest清单文件中进行配置,否则系统将找不到这个服务。与Activity一样,Service的配置也是在<application/>节点下,使用<service/>配置,其中android:name属性为Service类。 如果开发的服务需要被外部应用操作,还需要配置<intent-filter/>节点,但是如果仅本程序使用,则无需配置它也可以。 如果这个服务强制仅本应用操作,可以配置<service/>节点的android:exported属性为false,这样即使配置了<intent-filter/>,外部应用也无法操作这个服务,android:exported属性默认为true。 清单文件配置示例: 1 <application> 2 <!-- 普通的服务 --> 3 <service android:name=".Service1"></service> 4 <!-- 可被外部应用访问的服务 --> 5 <service android:name=".Service2"> 6 <intent-filter > 7 <action android:name="com.bgxt.Service2"/> 8 </intent-filter> 9 </service> 10 <!-- 无法被外部应用访问的服务 --> 11 <service android:name=".Service3" android:exported="false"> 12 <intent-filter > 13 <action android:name="com.bgxt.Service3"/> 14 </intent-filter> 15 </service> 16 </application> Service的开发步骤 既然Service是一个与Activity类似的Android组件,所以它的开发步骤大致也为一下几步: 开发一个服务类,需要继承Service或者IntentService。 在AndroidManifest清单文件中注册Service组件。 在一个Android组件中启动这个开发的Service组件。 服务使用完成之后,需要停止这个服务。 启动服务 启动服务必须实现Service.onStartCommond()方法。启动服务使用startService(Intent intent)方法开启一个服务,仅需要传递一个Intent对象即可,在Intent对象中指定需要启动的服务。而使用startService()方法启动的服务,在服务的外部,必须使用stopService()方法停止,在服务的内部可以调用stopSelf()方法停止当前服务。一旦使用startService()或者stopSelf()方法请求停止服务,系统会就会尽快销毁这个服务。 对于启动服务,一旦启动将与访问它的组件无任何关联,即使访问它的组件被销毁了,这个服务也一直运行下去,直到被销毁! 启动服务-示例 下面开发一个简单的使用startService()启动的服务,首先开发一个服务类: 1 package com.example.intentdemo2; 2 3 import android.app.Service; 4 import android.content.Intent; 5 import android.os.IBinder; 6 import android.util.Log; 7 8 public class StartService extends Service { 9 private final static String TAG = "main"; 10 11 @Override 12 public IBinder onBind(Intent arg0) { 13 // 仅通过startService()启动服务,所以这个方法返回null即可。 14 return null; 15 } 16 17 @Override 18 public void onCreate() { 19 super.onCreate(); 20 Log.i(TAG, "Service is Created"); 21 } 22 23 @Override 24 public int onStartCommand(Intent intent, int flags, int startId) { 25 Log.i(TAG, "Service is started"); 26 return super.onStartCommand(intent, flags, startId); 27 } 28 29 @Override 30 public void onDestroy() { 31 Log.i(TAG, "Service is Destroyed"); 32 super.onDestroy(); 33 } 34 35 } 虽然这个Service类没有什么处理逻辑,但是它包含了Service框架,在实际开发过程中,只需要在其中回调的方法中加入实际的业务实现代码即可。下面再使用一个Activity来操作这个服务,在这个Activity中有两个按钮,分别用于启动和停止这个服务。 1 package com.example.intentdemo2; 2 3 import android.app.Activity; 4 import android.content.ComponentName; 5 import android.content.Intent; 6 import android.os.Bundle; 7 import android.util.Log; 8 import android.view.View; 9 import android.widget.Button; 10 11 public class ServiceActivity1 extends Activity { 12 private Button btnSer1, btnSer2; 13 private Intent service=null; 14 @Override 15 protected void onCreate(Bundle savedInstanceState) { 16 super.onCreate(savedInstanceState); 17 setContentView(R.layout.activity_service1); 18 btnSer1 = (Button) findViewById(R.id.btnSer1); 19 btnSer2 = (Button) findViewById(R.id.btnSer2); 20 // 设置服务启动的Intent 21 service=new Intent(ServiceActivity1.this,StartService.class); 22 btnSer1.setOnClickListener(new View.OnClickListener() { 23 24 @Override 25 public void onClick(View v) { 26 // 启动服务 27 startService(service); 28 } 29 }); 30 31 btnSer2.setOnClickListener(new View.OnClickListener() { 32 33 @Override 34 public void onClick(View v) { 35 // 停止服务 36 stopService(service); 37 } 38 }); 39 } 40 } 执行结果均在日志中,可以在LogCat中查看,先启动服务,再停止服务: 绑定服务 如果Service和宿主之间需要进行方法调用或者数据交换,则应该使用Context对象的bindService()和unbindService()方法来绑定和解除绑定服务。 Context的bindService()方法的完整方法签名为: bindService(Intent service,ServiceConnection conn,int flags) 下面简单介绍一下这个方法的三个参数的意义: service:通过Intent指定要绑定的Service。 conn:一个ServiceConnection对象,该对象用于监听访问者与Service对象的onServiceConnected()方法。 flags:指定绑定时是否自动创建Service。0不自动创建、BIND_AUTO_CREATE,自动创建。 从上面的bindService方法可以看出,绑定一个服务于宿主交互,依托于一个ServiceConnection接口,这个接口对象必须声明在主线程中,通过实现其中的两个方法,来实现与Service的交互,下面分别介绍一下这两个方法: void onServiceConnection(ComponentName name,IBinder service):绑定服务的时候被回调,在这个方法获取绑定Service传递过来的IBinder对象,通过这个IBinder对象,实现宿主和Service的交互。 void onServiceDisconnected(ComponentName name):当取消绑定的时候被回调。但正常情况下是不被调用的,它的调用时机是当Service服务被意外销毁时,例如内存的资源不足时这个方法才被自动调用。 在使用绑定的服务的时候,该Service类必须提供一个IBinder onBind(Intent intent)方法,在绑定本地Service的情况下,onBind()方法说返回的IBinder对象会传给宿主的ServiceConnection.onServiceConnected()方法的service参数,这样宿主就可以通过IBinder对象与Service进行通信。实际开发中一般会继承Binder类(IBinder的实现类)的方式实现自己的IBinder对象。 需要注意的是,如果绑定服务提供的onBind()方法返回为Null,则也可以使用bindService()启动服务,但不会绑定上Service,因此宿主的ServiceConnection.onServiceConnected()方法不会被执行,也就不存在于宿主与服务的交互。 绑定服务-示例 说了这么多绑定服务相关的内容,下面通过一个例子来实现Service的绑定与数据交互。 开发一个Service类,用于进行绑定,在Service类中,做一个简单的数值累加,每秒加一。 1 package com.example.intentdemo2; 2 3 import android.app.Service; 4 import android.content.Intent; 5 import android.os.Binder; 6 import android.os.IBinder; 7 import android.util.Log; 8 9 public class BindService extends Service { 10 private final static String TAG = "main"; 11 private int count; 12 private boolean quit; 13 14 private Thread thread; 15 private MyBinder binder=new MyBinder(); 16 public class MyBinder extends Binder 17 { 18 // 声明一个方法,把count暴露给外部程序。 19 public int getCount(){ 20 return count; 21 } 22 } 23 24 @Override 25 public void onCreate() { 26 super.onCreate(); 27 Log.i(TAG, "Service is Created"); 28 thread=new Thread(new Runnable() { 29 @Override 30 public void run() { 31 // 每间隔一秒count加1 ,直到quit为true。 32 while(!quit){ 33 try{ 34 Thread.sleep(1000); 35 }catch(InterruptedException e){ 36 e.printStackTrace(); 37 } 38 count++; 39 } 40 } 41 }); 42 thread.start(); 43 } 44 45 @Override 46 public boolean onUnbind(Intent intent) { 47 Log.i(TAG, "Service is Unbinded"); 48 return true; 49 } 50 51 @Override 52 public int onStartCommand(Intent intent, int flags, int startId) { 53 Log.i(TAG, "Service is started"); 54 return super.onStartCommand(intent, flags, startId); 55 } 56 57 @Override 58 public void onDestroy() { 59 super.onDestroy(); 60 Log.i(TAG, "Service is Destroyed"); 61 this.quit=true; 62 63 } 64 65 @Override 66 public IBinder onBind(Intent intent) { 67 Log.i(TAG, "Service is Binded"); 68 return binder; 69 } 70 } 然后使用一个Activity来绑定上面这个Service类,并且声明一个ServiceConnection对象,用于进行数据交互。 1 package com.example.intentdemo2; 2 3 import android.app.Activity; 4 import android.app.Service; 5 import android.content.ComponentName; 6 import android.content.Intent; 7 8 import android.content.ServiceConnection; 9 import android.os.Bundle; 10 import android.os.IBinder; 11 import android.util.Log; 12 import android.view.View; 13 import android.widget.Button; 14 import android.widget.Toast; 15 16 public class ServiceActivity2 extends Activity { 17 private final String TAG = "main"; 18 Button bind, unbind, getServiceStatus; 19 BindService.MyBinder binder; 20 private ServiceConnection conn = new ServiceConnection() { 21 @Override 22 public void onServiceDisconnected(ComponentName name) { 23 Log.i(TAG, "--Service Disconnected--"); 24 } 25 @Override 26 public void onServiceConnected(ComponentName name, IBinder service) { 27 Log.i(TAG, "--Service Connected--"); 28 // 取得Service对象中的Binder对象 29 binder = (BindService.MyBinder) service; 30 } 31 }; 32 33 @Override 34 protected void onCreate(Bundle savedInstanceState) { 35 super.onCreate(savedInstanceState); 36 setContentView(R.layout.activity_bindservice1); 37 38 bind = (Button) findViewById(R.id.bind); 39 unbind = (Button) findViewById(R.id.unbind); 40 getServiceStatus = (Button) findViewById(R.id.getServiceStatus); 41 42 final Intent intent = new Intent(); 43 // 指定开启服务的action 44 intent.setAction("com.bgxt.BindServiceDemo"); 45 46 bind.setOnClickListener(new View.OnClickListener() { 47 48 @Override 49 public void onClick(View v) { 50 // 绑定服务到当前activity中 51 bindService(intent, conn, Service.BIND_AUTO_CREATE); 52 } 53 }); 54 unbind.setOnClickListener(new View.OnClickListener() { 55 56 @Override 57 public void onClick(View v) { 58 // 解除绑定 59 binder=null; 60 unbindService(conn); 61 } 62 }); 63 getServiceStatus.setOnClickListener(new View.OnClickListener() { 64 65 @Override 66 public void onClick(View v) { 67 if(binder!=null) 68 { 69 // 通过绑定服务传递的Binder对象,获取Service暴露出来的数据 70 Toast.makeText(ServiceActivity2.this, 71 "Service的Count值为" + binder.getCount(), 72 Toast.LENGTH_SHORT).show(); 73 Log.i(TAG, "Service的Count值为" + binder.getCount()); 74 } 75 else 76 { 77 Toast.makeText(ServiceActivity2.this, 78 "还没绑定呢,先绑定。", 79 Toast.LENGTH_SHORT).show(); 80 } 81 } 82 }); 83 } 84 } 执行结果,先绑定服务,然后获取当前服务运行时count的值,最后解除绑定,把执行过程输出到LogCat中。 Service的选用 相信看完以上的内容,对Android下Service组件有了一定的了解,但是对于选用startService()还是使用bindService(),有一些原则需要讲明。如果仅仅是想要启动一个后台服务长期驻留在内存中执行某项任务,那么仅使用startService()启动一个服务即可。但是如果想要与正在运行的服务进行交互,一种方式是使用broadcast,这个以后再介绍,另外一种方式就是使用bindService()绑定一个服务到组件上,使用broadcast的缺点是如果数据交互频繁,容易造成性能上的问题,并且BroadcastReceiver本身执行代码的时间不确定,也许代码执行到一半,后面的代码将不被执行,但是使用bindService()绑定服务即没有这些问题。另外,如果一个服务是依托于某项应用的,那么也最好使用绑定服务,在依托的应用启动的时候绑定服务,这样可以在不使用的时候避免浪费系统资源。 源码下载 总结 值得注意的是,Android下的Service组件也是运行在主线程中的,所以一些Android4.0+无法在主线程上进行的操作,在Service中也必须另外开启线程来完成,如访问网络,还可以使用继承Service的子类IntentService来实现,这个内容会在之后的博客中介绍。Android系统本身还提供了大量的Service组件,开发人员可以通过这些系统Service来操作Android系统本身,这不属于本篇博客的范畴,以后再慢慢详解。 本文转自承香墨影博客园博客,原文链接:http://www.cnblogs.com/plokmju/p/Android_Service1.html,如需转载请自行联系原作者

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

6 docker网络基础配置

一、从外部访问容器应用 1、端口映射实现访问容器 root@docker-test:~# docker run -d -P training/webapp python app.py 61975c6a1981e829a7edb8e07d24c849aad7132c80e14338e6aaab4d12d25021 root@docker-test:~# docker ps -l CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 61975c6a1981 training/webapp:latest "python app.py" 8 seconds ago Up 7 seconds 0.0.0.0:32783->5000/tcp furious_pasteur 大写的-P。会随机映射一个49000-49900的端口至容器内部开放的网络端口 小写的-p,则指定固定端口 上面的ps -l看出,本地的32783端口被映射到了容器的5000端口,访问宿主机的32783端口即可访问容器内web应用提供界面 通过我宿主机的IP地址进行访问 http://192.168.89.130:32783/ 2、通过docker logs查看应用的信息 root@docker-test:~# docker logs -f furious_pasteur * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit) 192.168.89.1 - - [12/Aug/2017 12:58:34] "GET / HTTP/1.1" 200 - 192.168.89.1 - - [12/Aug/2017 12:58:35] "GET /favicon.ico HTTP/1.1" 404 - 192.168.89.1 - - [12/Aug/2017 12:59:56] "GET / HTTP/1.1" 200 - 3、映射所有接口地址 将本地的5000端口映射到容器的5000端口 docker run -d -p 5000:5000 training/webapp python app.py #此时会绑定本地所有接口上的所有地址 4、映射到指定地址的指定端口 docker run -d -p 192.168.89.130:5000:5000 training/webapp python app.py 5、映射到指定地址的任意端口 docker run -d -p 192.168.89.130::5000 training/webapp python app.py 6、查看映射端口配置 root@docker-test:~# root@docker-test:~# docker port testweb 5000/tcp -> 0.0.0.0:32782 root@docker-test:~# docker port web 5000/tcp -> 0.0.0.0:32781 root@docker-test:~# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 61975c6a1981 training/webapp:latest "python app.py" 14 minutes ago Up 14 minutes 0.0.0.0:32783->5000/tcp furious_pasteur 235a7f166a79 training/webapp:latest "/bin/bash" 33 minutes ago Up 33 minutes 0.0.0.0:32782->5000/tcp testweb 6c498fba9a26 training/webapp:latest "/bin/bash" 40 minutes ago Up 40 minutes 0.0.0.0:32781->5000/tcp web 39d71abc194d ubuntu:latest "/bin/bash" About an hour ago Up About an hour db2 593de70961a0 ubuntu:latest "/bin/bash" About an hour ago Up About an hour db1 a6a32f7838ee ubuntu:latest "/bin/bash" About an hour ago Up About an hour dbdata root@docker-test:~# docker port 61975c6a1981 5000/tcp -> 0.0.0.0:32783 root@docker-test:~# 二、自定义容器命名 1、自定义容器命名 root@docker-test:~# docker run -d -P --name web training/webapp python app.py #使用--name选项 2、查看设定后的命名 root@docker-test:~# docker ps -l 3、使用inspect查看指定容器ID的容器的名字 root@docker-test:~# docker inspect -f "` `.`Name `" 382b382521b5 二、容器互联(实现容器间通信) 使用--link参数可以让容器之间安全的进行交互 创建一个新的数据库容器进行演示 1、创建并运行数据库容器,名称为db root@docker-test:~# docker run -d --name db training/postgres #如本地没有training/postgres镜像,则会自动从docker hub搜索到镜像并下载 2、创建完成之后查看一下 root@docker-test:~# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 19f67a71ac16 training/postgres:latest "su postgres -c '/us 2 minutes ago Up 2 minutes 5432/tcp db 3、然后创建一个新的web容器,并将它连接到db容器 root@docker-test:~# docker run -d -P --name web --link db:db training/webapp python app.py 3ac18b1df0d487c99b0f07e2fd273c53ad7b6f5beb29b830985c89fd6df40241 4、查看创建的两个docker容器(web容器和db容器) root@docker-test:~# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3ac18b1df0d4 training/webapp:latest "python app.py" 6 seconds ago Up 4 seconds 0.0.0.0:32769->5000/tcp web 651b10778678 training/postgres:latest "su postgres -c '/us 2 minutes ago Up 2 minutes 5432/tcp db 本文转自 TtrToby 51CTO博客,原文链接:http://blog.51cto.com/freshair/1958350

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

zabbix监控基础知识

Zabbix 一、Zabbix是什么? Zabbix是一个高度集成的网络监控套件;它能监视各种网络参数,保证服务器系统的安全运营;并提供灵活的通知机制以让系统管理员快速定位/解决存在的各种问题。是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。 二Zabbix的特性: 数据收集、历史数据存储、实时绘图 配置简单、灵活的阀值定义、高级告警配置 三、Zabbix工作原理 一个监控系统运行的大概的流程是这样的: zabbix agent需要安装到被监控的主机上,它负责定期收集各项数据,并发送到zabbix server端,zabbix server将数据存储到数据库中,zabbix web根据数据在前端进行展现和绘图。这里agent收集数据分为主动和被动两种模式: 主动:agent请求server获取主动的监控项列表,并主动将监控项内需要检测的数据提交给server/proxy 被动:server向agent请求获取监控项的数据,agent返回数据。 四、Zabbix的重要组件以及进程 zabbix由以下几个组件部分构成: 1、Zabbix Server:负责接收agent发送的报告信息的核心组件,所有配置,统计数据及操作数据均由其组织进行; 2、Database Storage:专用于存储所有配置信息,以及由zabbix收集的数据; 3、Web interface:zabbix的GUI接口,通常与Server运行在同一台主机上; 4、Proxy:可选组件,常用于分布监控环境中,代理Server收集部分被监控端的监控数据并统一发往Server端; 5、Agent:部署在被监控主机上,负责收集本地数据并发往Server端或Proxy端; 注:zabbix node也是 zabbix server的一种 。 zabbix进程介绍:(默认情况下zabbix包含5个程序) 1、zabbix_agent:客户端守护进程,此进程收集客户端数据,例如cpu负载、内存、硬盘使用情况等 2、zabbix_get:zabbix工具,单独使用的命令,通常在server或者proxy端执行获取远程客户端信息的命令。通常用户排错。例如在server端获取不到客户端的内存数据,我们可以使用zabbix_get获取客户端的内容的方式来做故障排查。 3、zabbix_sender:zabbix工具,用于发送数据给server或者proxy,通常用于耗时比较长的检查。很多检查非常耗时间,导致zabbix超时。于是我们在脚本执行完毕之后,使用sender主动提交数据。 4、zabbix_server:zabbix服务端守护进程。zabbix_agentd、zabbix_get、zabbix_sender、zabbix_proxy、zabbix_java_gateway的数据最终都是提交到server 备注:当然不是数据都是主动提交给zabbix_server,也有的是server主动去取数据。 5、zabbix_proxy:zabbix代理守护进程。功能类似server,唯一不同的是它只是一个中转站,它需要把收集到的数据提交/被提交到server里。为什么要用代理?代理是做什么的? 6、zabbix_java_gateway是可选的,这个需要另外安装 这个进程是zabbix2.0之后引入的一个功能。顾名思义:Java网关,类似agentd,但是只用于Java方面。需要特别注意的是,它只能主动去获取数据,而不能被动获取数据。它的数据最终会给到server或者proxy。 五、zabbix监控环境中基本概念 1、主机(host):要监控的网络设备,可由IP或DNS名称指定; 2、主机组(host group):主机的逻辑容器,可以包含主机和模板,但同一个组织内的主机和模板不能互相链接;主机组通常在给用户或用户组指派监控权限时使用; 3、监控项(item):一个特定监控指标的相关的数据;这些数据来自于被监控对象;item是zabbix进行数据收集的核心,相对某个监控对象,每个item都由"key"标识; 4、触发器(trigger):一个表达式,用于评估某监控对象的特定item内接收到的数据是否在合理范围内,也就是阈值;接收的数据量大于阈值时,触发器状态将从"OK"转变为"Problem",当数据再次恢复到合理范围,又转变为"OK"; 5、事件(event):触发一个值得关注的事情,比如触发器状态转变,新的agent或重新上线的agent的自动注册等; 6、动作(action):指对于特定事件事先定义的处理方法,如发送通知,何时执行操作; 7、报警升级(escalation):发送警报或者执行远程命令的自定义方案,如每隔5分钟发送一次警报,共发送5次等; 8、媒介(media):发送通知的手段或者通道,如Email、Jabber或者SMS等; 9、通知(notification):通过选定的媒介向用户发送的有关某事件的信息; 10、远程命令(remote command):预定义的命令,可在被监控主机处于某特定条件下时自动执行; 11、模板(template):用于快速定义被监控主机的预设条目集合,通常包含了item、trigger、graph、screen、application以及low-level discovery rule;模板可以直接链接至某个主机; 12、应用(application):一组item的集合; 13、web场景(web scennario):用于检测web站点可用性的一个活多个HTTP请求; 14、前端(frontend):Zabbix的web接口; 六、Zabbix的监控架构 在实际监控架构中,zabbix根据网络环境、监控规模等 分了三种架构: 1、server-client架构 是zabbix的最简单的架构,监控机和被监控机之间不经过任何代理 ,直接由zabbix server和zabbix agentd之间进行数据交互。适用于网络比较简单,设备比较少的监控环境。 2、server-proxy-client架构 其中proxy是server、client之间沟通的一个桥梁,proxy本身没有前端,而且其本身并不存放数据,只是将agentd发来的数据暂时存放,而后再提交给server 。该架构经常是和master-node-client架构做比较的架构 ,一般适用于跨机房、跨网络的中型网络架构的监控。 3、master-node-client架构 该架构是zabbix最复杂的监控架构,适用于跨网络、跨机房、设备较多的大型环境 。每个node同时也是一个server端,node下面可以接proxy,也可以直接接client 。node有自已的配置文件和数据库,其要做的是将配置信息和监控数据向master同步,master的故障或损坏对node其下架构的完整性。 本文转自西鼠 51CTO博客,原文链接:http://blog.51cto.com/10630401/1976053,如需转载请自行联系原作者

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

iOS开发-UI基础Demo

现在更多的学习资料都是xCode4.X的,发现xCode6.1还是很多东西,如果有正在学习iOS开发的可以通过Demo简单了解下iOS的UI开发~ 1.新建单视图文件: 2.新建项目名称,语言选择OC: 3.这个就是拖了两个控件放在View上面的,其中有一个比Android好的就是不需要自己新建模拟器,取消一下自动布局和auto size classes,不然页面很大: 4.如果你只是简单的写个Hello World,那么这个程序已经结束了,不过第一次还是做个事件: 5.新手错误之this class is not key value coding-compliant for the key result,这个就是连线连太多了,连错了,结果连接那边没有删除,具体修改如下: 6.运行效果如下: 7.代码如下: 1 <span style= "font-family: 'Microsoft YaHei'; font-size: 14px;" > ViewController.h中代码:</span> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // // ViewController.h // Demo01 // // Created by keso on 15/1/12. // Copyright (c) 2015年 keso. All rights reserved. // #import <UIKit/UIKit.h> @interface ViewController : UIViewController @property (weak, nonatomic ) IBOutlet UIView *name; @property (weak, nonatomic ) IBOutlet UITextField *realName; @property (weak, nonatomic ) IBOutlet UILabel *result; @end ViewController.m中代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 // // ViewController.m // Demo01 // // Created by keso on 15/1/12. // Copyright (c) 2015年 keso. All rights reserved. // #import "ViewController.h" @interface ViewController () @end @implementation ViewController - ( void )viewDidLoad { [ super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } - ( void )didReceiveMemoryWarning { [ super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - ( IBAction )showName:( id )sender { NSString *textName=[_realName text]; [_result setText:textName]; } @end 本文转自Fly_Elephant博客园博客,原文链接:http://www.cnblogs.com/xiaofeixiang/p/4223057.html,如需转载请自行联系原作者

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

Docker 基础 : 数据管理

用户在使用 Docker 的过程中,往往需要能查看容器内应用产生的数据,或者需要把容器内的数据进行备份,甚至多个容器之间进行数据的共享,这必然涉及容器的数据管理操作。容器中管理数据主要有两种方式:数据卷(Data Volumes),数据卷容器(Data Volume Containers)。 数据卷 数据卷是一个可供容器使用的特殊目录,它绕过文件系统,可以提供很多有用的特性:1. 数据卷可以在容器之间共享和重用。2. 对数据卷的更改会立即生效。3. 对数据卷的更新不会影响镜像。4. 数据卷会一直存在,直到没有容器使用。 数据卷的使用,类似于 linux 下对目录或文件进行 mount 操作。 在容器内创建一个数据卷 在用 docker run 命令的时候,使用 -v 标记可以在容器内创建一个数据卷。多次使用 -v 标记可以创建多个数据卷。 下面的例子中我们使用 myimg/webapp 镜像创建一个 web 容器,并创建一个数据卷挂载到容器的 /webdata 目录。 $ sudo docker run -d -P –name web -v /webdata myimg/webapp python app.py 挂载一个主机目录作为数据卷 使用 -v 标记也可以指定挂载一个本地的已有目录到容器中去作为数据卷: $ sudo docker run -d -P –name web -v /var/data:/opt/webdata myimg/webapp python app.py 上面的命令挂载主机的 /var/data 目录到容器的 /opt/webdata 目录。 这个功能在接下测试的时候特别方便,比如用户可以放置一些程序或数据到本地目录中,然后在容器中使用。另外,本地目录的路径必须是绝对路径,如果目录不存在,Docker 会自动创建。Docker 挂载数据卷的默认权限是可读写(rw),用户也可以通过 ro 标记指定为只读: $ sudo docker run -d -P –name web -v /var/data:/opt/webdata:ro myimg/webapp python app.py 加了 :ro 之后,容器内挂载的数据卷内的数据就变成只读的了。 挂载一个本地主机文件作为数据卷 -v 标记也可以挂载一个主机中的文件到容器中作为数据卷,但是这样做会带来一些问题。建议还是挂载文件所在的目录。 数据卷容器 如果用户需要在容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器。数据卷容器其实就是一个普通的容器,专门用它提供数据卷供其他容器挂载。下面简单介绍其使用方法。 首先要创建一个数据卷容器 mydata,并在其中创建一个数据卷挂载到 /data 目录。 $ sudo docker run -it -v /data –name mydata ubuntu 然后在其他容器中使用 --volumes-from 来挂载 mydata 容器中的数据卷。例如创建两个容器 mycon1 和 mycon2,并从 mydata 容器挂载数据卷: $ sudo docker run -it --volumes-from mydata –name mycon1 ubuntu $ sudo docker run -it --volumes-from mydata –name mycon2 ubuntu (注意,命令中没有指定数据卷的信息,也就是说新容器中挂载数据卷的目录和源容器中是一样的。) 此时容器 mycon1 和 mycon2 都挂载同一个数据卷到相同的目录 /data。三个容器任何一个在该目录下写入数据其他容器都能看到。可以多次使用 --volumes-from 参数来从多个容器挂载多个数据卷。还可以从其他已经挂载了容器的容器来挂载数据卷。并且使用 --volumes-from 参数所挂载数据卷的容器自身并不需要保持在运行状态。但删除挂载了数据卷的容器时,数据卷并不会被自动删除。如果要删除一个数据卷,必须在删除最后一个还挂载着它的容器时显式的使用 docker rm -v 命令来指定同时删除关联的容器。使用数据卷容器可以让用户在容器之间自由的升级和移动数据卷,下面会进行详细的介绍。 利用数据卷容器迁移数据 可以利用数据卷容器对其中的数据卷进行备份、恢复,以实现数据的迁移。 备份 使用下面的命令来备份 mydata 数据卷容器内的数据卷: $ sudo docker run --volumes-from mydata -v $(pwd):/backup –name worker ubuntu tar cvf /backup/backup.tar /data 这个命令首先利用 Ubuntu 镜像创建了一个容器 worker。又使用 --volumes-from mydata 参数来让 worker 容器挂载 mydata 容器的数据卷。接下来使用 -v $(pwd):/backup 参数来挂载本地的当前目录到 worker 容器的 /backup 目录。在 worker 容器启动后,使用了 tar cvf /backup/backup.tar /data 命令来将 /data 下内容备份为容器内的 /backup/backup.tar,即宿主主机的当前目录下的backup.tar。 恢复 如果要恢复数据到一个容器,可以按照下面的操作。首先创建一个带有数据卷的容器 mydata2: $ sudo docker run -v /data –name mydata2 ubuntu /bin/bash 然后创建另一个新的容器,挂载 mydata2 的数据卷,并使用 tar 解压缩备份文件到所挂载的容器卷中: $ sudo docker run --volumes-from mydata2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar ,如需转载请自行联系原作者

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

Android Animation(动画)---基础一

动画分类: 传统动画(帧动画(Frame Animation)/ 补间动画(Tweened Animation))。 属性动画(Attribute Animation) 帧动画 帧动画是将图片一张一张的连续播放,适当的速度,让人感觉是连续的动画。 xml文件 <?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="true"> <!--oneshot为true则动画只执行一遍, 为false则重复执行--> <item android:drawable="@color/md_red_50" android:duration="200"/> <item android:drawable="@color/md_red_100" android:duration="200"/> <item android:drawable="@color/md_red_200" android:duration="200"/> <item android:drawable="@color/md_red_300" android:duration="200"/> <item android:drawable="@color/md_red_400" android:duration="200"/> <item android:drawable="@color/md_red_500" android:duration="200"/> <item android:drawable="@color/md_red_600" android:duration="200"/> <item android:drawable="@color/md_red_700" android:duration="200"/> <item android:drawable="@color/md_red_800" android:duration="200"/> <item android:drawable="@color/md_red_900" android:duration="200"/> </animation-list> Activity内容 private ImageView mIvFrame; mIvFrame = (ImageView) this.findViewById(R.id.iv_frame); mIvFrame.setImageResource(R.drawable.frame_list); AnimationDrawable animationDrawable = (AnimationDrawable) mIvFrame.getDrawable(); animationDrawable.start(); 补间动画 Alpha(淡入淡出) Translate(位移) Scale(缩放大小) Rotate(旋转) (1) Alpha(淡入淡出) <?xml version="1.0" encoding="utf-8"?> <alpha xmlns:android="http://schemas.android.com/apk/res/android" android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="2000" android:interpolator="@android:anim/accelerate_decelerate_interpolator"/> /**补间动画*/ private ImageView mIvTweened; mIvTweened = (ImageView) this.findViewById(R.id.iv_tween); // 淡入淡出 //Animation animation = AnimationUtils.loadAnimation(this, R.anim.alpha); mIvTweened.startAnimation(animation); (2) Translate(位移) <translate xmlns:android="http://schemas.android.com/apk/res/android" android:fromXDelta="0.0" android:toXDelta="100.0" android:toYDelta="100.0" android:fromYDelta="0.0" android:duration="2000" android:interpolator="@android:anim/accelerate_interpolator" /> /**补间动画*/ private ImageView mIvTweened; mIvTweened = (ImageView) this.findViewById(R.id.iv_tween); // 淡入淡出 //Animation animation = AnimationUtils.loadAnimation(this, R.anim.translate); mIvTweened.startAnimation(animation); (3) Scale(缩放大小) <scale xmlns:android="http://schemas.android.com/apk/res/android" android:fromXScale="0.0" android:toXScale="1.0" android:fromYScale="0.0" android:toYScale="1.0" android:pivotX="50%" android:pivotY="50%" android:duration="2000" /> /**补间动画*/ private ImageView mIvTweened; mIvTweened = (ImageView) this.findViewById(R.id.iv_tween); // 淡入淡出 //Animation animation = AnimationUtils.loadAnimation(this, R.anim.scale); mIvTweened.startAnimation(animation); (4) Rotate(旋转) <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:pivotX="50%" android:pivotY="50%" android:drawable="@color/md_green_A700" android:fromDegrees="0.0" android:toDegrees="45" android:duration="2000" /> /**补间动画*/ private ImageView mIvTweened; mIvTweened = (ImageView) this.findViewById(R.id.iv_tween); // 淡入淡出 //Animation animation = AnimationUtils.loadAnimation(this, R.anim.scale); mIvTweened.startAnimation(animation); (5) 组合动画 <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="2000" android:interpolator="@android:anim/accelerate_decelerate_interpolator"/> <rotate android:pivotX="50%" android:pivotY="50%" android:drawable="@color/md_green_A700" android:fromDegrees="0.0" android:toDegrees="45" android:duration="2000" /> <scale android:fromXScale="0.0" android:toXScale="1.0" android:fromYScale="0.0" android:toYScale="1.0" android:pivotX="50%" android:pivotY="50%" android:duration="2000" /> <translate android:fromXDelta="0.0" android:toXDelta="100.0" android:toYDelta="100.0" android:fromYDelta="0.0" android:duration="2000" android:interpolator="@android:anim/accelerate_interpolator" /> </set> /**补间动画*/ private ImageView mIvTweened; mIvTweened = (ImageView) this.findViewById(R.id.iv_tween); // 淡入淡出 //Animation animation = AnimationUtils.loadAnimation(this, R.anim.set); mIvTweened.startAnimation(animation); (6) 属性解释 android:interpolator主要作用是可以控制动画的变化速率。Android 系统已经为我们提供了一些Interpolator ,比如 accelerate_decelerate_interpolator,accelerate_interpolator等。 pivot决定了当前动画执行的参考位置。pivot 这个属性主要是在translate 和 scale 动画中,这两种动画都牵扯到view 的“物理位置“发生变化,所以需要一个参考点。而pivotX和pivotY就共同决定了这个点;它的值可以是float或者是百分比数值。 pivotX取值 含义 10 距离动画所在view自身左边缘10像素 10% 距离动画所在view自身左边缘 的距离是整个view宽度的10% 10%p 距离动画所在view父控件左边缘的距离是整个view宽度的10% 属性动画(Attribute Animation) 属性动画,顾名思义它是对于对象属性的动画。因此,所有补间动画的内容,都可以通过属性动画实现。 属性动画使用方法: /** * 属性动画 */ private void attrAnimation() { // 淡入淡出 //ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mIvAttr, "alpha", 0.0f, 0.5f, 0.8f, 1.0f); //objectAnimator.setDuration(2000); //objectAnimator.start(); // 位移 /*ObjectAnimator objectAnimatorX = ObjectAnimator.ofFloat(mIvAttr, "translationX", 100, 300); ObjectAnimator objectAnimatorY = ObjectAnimator.ofFloat(mIvAttr, "translationY", 100, 300); AnimatorSet animatorSet = new AnimatorSet(); // 同时播放 //animatorSet.playTogether(objectAnimatorX, objectAnimatorY); // 有序播放 animatorSet.playSequentially(objectAnimatorX, objectAnimatorY); animatorSet.setDuration(5000); animatorSet.start();*/ // 缩放 //ObjectAnimator objectAnimatorX = ObjectAnimator.ofFloat(mIvAttr, "scaleX", 0.0f, 1.0f); //ObjectAnimator objectAnimatorY = ObjectAnimator.ofFloat(mIvAttr, "scaleY", 0.0f, 2.0f); //AnimatorSet animatorSet = new AnimatorSet(); //animatorSet.playTogether(objectAnimatorX, objectAnimatorY); //animatorSet.setDuration(5000); //animatorSet.start(); // 旋转 ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mIvAttr, "rotation", 0, 360); objectAnimator.setDuration(2000); objectAnimator.start(); } 代码下载

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

MongoDB学习笔记(一)--基础

Insert MongoDB在执行插入时,首先会将插入的数据转换成BSON格式。然后MongoDB数据库会对BSON进行解剖,并检查是否存在_id建。 >doc = { "_id" : 1, "author" : "yyd", "title" : "MongoDB Test", "text" : "this is a test", "tags" : [ "love", "test" ], "comments" : [ { "author" : "yyd_guest", "comment" : "yes" }, { "author" : "yyd_admin", "comment" : "no" } ] } > db.yyd.insert(doc); Query 全部查找 返回除了 tags 字段外的所有字段 返回 tags = test 除了 comments 的所有列 返回 id=1 的 title 字段 <, <=, >, >= 大于 $gt、小于 $lt、大于等于 $gte、小于等于 $lte $all $all 操作类似$in 操作,但是不同的是,$all 操作要求数组里面的值全部被包含在返回的记录里面。 $exists $exists 操作检查一个字段是否存在。 $exists:true代表返回存在这个键的值。 $exists:false代表返回不存在这个键的值。 $mod > db.user.find("this._id%2==1"); > db.user.find({_id:{$mod:[2,1]}}); 两句话一样的效果。 $ne $ne 意思是 not equal,不等于。 $in $in 操作类似于传统关系数据库中的 IN。 $nin $nin 跟$in 操作相反。 $or $nor $nor 跟$or 相反。 $size $size 操作将会查询数组长度等于输入参数的数组。 skip 跳过前 2 条记录。 limit 每页返回 3 条记录 sort() sort()方法对返回记录集按照指定字段进行排序返回,1 表示升序,-1 表示降序。 count() count()方法返回查询记录的总数目。 Remove Update update() db.collection.update( criteria, objNew, upsert, multi ) 参数说明: Criteria:用于设置查询条件的对象 Objnew:用于设置更新内容的对象 Upsert:如果记录已经存在,更新它,否则新增一个记录 Multi:如果有多个符合条件的记录,全部更新 注意:默认情况下,只会更新第一个符合条件的记录 save() 如果存在更新它,如果不存在,新增记录。 $inc 增加1,对int等有效。 对一个_id=3 的 user 的年龄进行加 1,两种方法。 $set { $set : { field : value } } 把 field 的值设置成 value,当 field 不存在时,增加一个字段,类似 SQL 的 set 操作,value 支持所有类型。 $unset { $unset : { field : 1} } 删除给定的字段 field。 $push { $push : { field : value } } 如果 filed 是一个已经存在的数组,那么把 value 追加给 field; 如果 field 原来不存在,那么新增 field 字段,把 value 的值赋给 field; 如果 field 存在,但是不是一个数组,将会出错。 $pushAll { $pushAll : { field : value_array } } 功能同$push,只是这里的 value 是数组,相当于对数组里的每一个值进行$push操作。 $addToSet { $addToSet : { field : value } } 如果 filed 是一个已经存在的数组,并且 value 不在其中,那么把 value 加入到数组; 如果 filed 不存在,那么把 value 当成一个数组形式赋给 field;$pop 如果 field 是一个已经存在的非数组类型,那么将会报错。 $pop { $pop : { field : 1 } } 删除数组中最后一个元素 { $pop : { field : -1 } } 删除数组中第一个元素 $pull { $pull : { field : _value } } 如果 field 是一个数组,那么删除符合_value 检索条件的记录; 如果 field 是一个已经存在的非数组,那么会报错。 $pullAll { $pullAll : { field : value_array } } $rename { $rename : { old_field_name : new_field_name } 重命名指定的字段名称。 本文转自我爱物联网博客园博客,原文链接:http://www.cnblogs.com/yydcdut/p/3557414.html,如需转载请自行联系原作者

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

iOS基础—单元测试

单元测试(unit testing):对软件中最小可测试单元进行检查和验证。一般面向过程的语言中,基本单元为函数,面向对象的语言中,基本单元通常是类,其实对于一个手机上的app来说基本单元也可以是一个UI页面。平时我们写了一个函数,执行以下看是否正常工作,也属于单元测试。 测试用例(test case):对测试任务的描述,体现测试方案、方法、技术和策略。内容包括测试目标、测试环境、输入数据、输出数据、测试步骤、预期结果、测试脚本等。 它是一种检验行为,便于我们写出高质量代码。 它是一种设计行为,有利于我们编程能力的提高。 它是一种文档编写行为,让我们的程序有据可依。 Xcode内置了OCUnit单元测试框架。在Xcode5之前,建立项目的时候有一个选项,让我们选择是否建立一个含有单元测试target的项目,而在Xcode5中只要建立一个项目就默认带有一个单元测试的target。 在Xcode5之前,建立一个工程的时候如果没有勾选单元测试的话也不要紧,可以自己添加一个单元测试的target。 在弹出选择框中 IOS-->Other---> Cocoa Touch Unit Testing Bundle 这里看似OK,但还是差一步,在点击RUN,长按后产生TEST,点击TEST进行开启测试时,将产生一个提示:The scheme "工程名" is not configured for testing. edit the scheme to enable testing,or cancel the action.即我们还没有给工程配置测试工程行,点击修改来添加,或点击取消进行结束。点击Edit Scheme (或菜单中Product->edit Scheme) 弹出scheme窗体。选中Test,然后点击+号来没加一个scheme 选中之前创建的CoredataDemoTest后点击ADD 说明: 在Xcode5中测试类必须继承自XCTestCase。在Xcode5之前测试类必须继承自SenTestCase。 测试函数的形式必须是无返回值且以‘test’为前缀,如:- (void)testLogin; 每个测试用例都是从- (void)setUp;开始,进行初始化,以- (void)tearDown结束,释放资源。 运行测试用例: command + u。 长按运行按钮选择列表中的test; 最新内容请见作者的GitHub页:http://qaseven.github.io/

资源下载

更多资源
Mario

Mario

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

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

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

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册