首页 文章 精选 留言 我的

精选列表

搜索[数据库知识开放麦],共10000篇文章
优秀的个人博客,低调大师

webservice的一些知识点

SOA:(Service-Oriented Architecture)(面向服务的架构)它是有利于在不同应用程序间实现松散耦合集成的软件架构。 SOA架构的实体:服务提供商(Service Provider) 服务注册表(Service Register) 服务使用者(Service Consumer) SOA概念通过Web服务实现。 Web服务功能: 1.支持数据交换(XML) 2.支持文档交换(pdf,视频文件,图像文件) 3.支持同步或者异步客户端(同步:等待服务完成操作 异步:调用服务后执行其它函数而不是等服务完成) Web服务优点: 1.支持应用程序和数据集成(http以及跨平台支持 实现了此功能) 2.多功能(Web服务可以通过客户,Web应用以及其它Web服务调用 组合在一起 实现多功能) 3.代码可重用性(一个服务可对应多个客户端) 4.节约成本 Web服务使用JWSDP工具包开发。(这里特指了基于XML的web服务) JWSDP工具包提供了以下API: JAX-WS:用于开发XML Web服务的JAX-WS:(Java API forXML WebService) JAXP:用于解析XML的JAXP:(Java API forXML Parsing) JAXB:用于绑定XML到Java对象 形成映射关系的JAXB(Java API forXML Binding) SAAJ:用于将XML或非XML数据的大型文档作为SOAP消息的附件通过因特网传输的API SAAJ:(SOAP with Attachments API for Java)是RESTful Web服务的实现基础 JAXR:用于在Web服务中访问服务注册表API JAXR:(Java API forXML Registing) Web服务类型: 基于XML的Web服务:(架构由WSDL UDDI和SOAP组成 介绍Web服务1.9) RESTful Web服务(REST架构->Restful服务) 基于XML的Web服务:由三大组件构成,WSDL(描述基于XML的web服务) UDDI(注册基于XML的服务) SOAP(在Web应用间传递消息) WSDL:此组件基于XML的文档,用于描述基于XML的Web服务功能 UDDI:此组件基于XML的目录,用于注册基于XML的Web服务 SOAP:此组件基于XML的协议,用于在Web应用间交换消息(Simple Object Access Protocol) API是JAX-WS Restful Web服务:基于XML/JSON,以http/https为通信标准。 使用JAX-RS API创建。 JAX-RS API提供javax.ws.rs 来开发Rest Web服务。 javax.ws.rs.core javax.ws.rs.ext **************基于XML的web服务展开: WSDL文档的元素:<definitions> <types> <message> <portType> <binding> <service> 用来描述基于XML的web服务 其中:抽象模型:types,message,portType 具体模型:binding,service. UDDI: 用来注册基于XML的web服务 组成:白页,黄页,绿页 SOAP:用于在Web应用间通信 传递消息 组成:SOAP信封,SOAP报头,SOAP正文,SOAP故障。 创建基于XML的web服务: a.创建Web服务(在服务器端或者创建客户端应用程序) b.定义Web方法(在客户端) 客户端通过WSDL文件或者通过显式编码客户端应用程序实现。 **********:Rest与Restful Web服务展开 REST是基于SOA的软件样式架构,用于设计RESTful Web服务。 REST是架构,不是标准(RESTful才是标准),REST遵循面向资源的架构。 REST使用数据元素,组件,连接器来定义关键组件间的关系,REST架构图在 4.5 REST方法使用现有Web标准,Rest更常用(轻量级 简单) REST架构使用http或https通信。 REST四大设计原则: 使用http方法 显示无状态特性 公开目录结构 以XML/JSON数据格式传输。 Restful是与REST一起使用的标准: ①用于数据传输的XML/JSON ②用于访问web服务的URI 3.用于数据表示的MIME类型 Restful Web服务使用JAX-RS API创建。 JAX-RS API提供javax.ws.rs 来开发Rest Web服务。 javax.ws.rs.core javax.ws.rs.ext javax.ws.rs.WebApplicationException抛出异常 javax.ws.rs.ext.MessageBodyWriter和javax.ws.rs.ext.MessageBodyWriter接口负责序列化和反序列化java类型数据。 Restful Web使用从下到上或从上到下的方法开发 可以使用@path批注来指定资源类或其方法的访问url Restful Web服务与基于XML的Web服务对比: 优先选择RESTful Web服务: ①要开发的Web服务本质上无状态 ②客户端每次请求数据未动态生成Web服务要返回的数据 3.使用者的带宽有限。 优先选择基于XML的Web服务: ①客户端需要用于定义客户端与服务交互时必须使用的格式的合约才能与web服务通信时 ②需要实现非功能性功能时,例如事务和安全性 3.web服务本质上要异步执行 处理SOAP消息 (单SOAP以及SAAJ)(XML数据格式/非XML数据格式)(即基于XML和基于RESTful 的Web服务) 处理XML数据:JAXP API , JAXB API DOM和SAX API处理XML 处理非XML数据:SAAJ API DOM API允许读取和操作XML,DOM在内存中创建对象树,即DOM树。 SAX API以数据流形式处理XML,只允许读取,基于事件解析器。 JAXB以对象形式向Java显示XML: 包括两个步骤: 步骤①:绑定XML文档的模式 步骤②:取消列集XML的文档 SAAJ API在javax.xml.soap包中定义,附件可以是任何格式,纯文本,XML,JSON,音频等。 Metro是软件堆栈,提供更快,安全,可靠,可互操作且面向性能的Web服务 Metro使用JAX-WS和WSIT进行Web服务开发 JAX-WS提供核心,WSIT保证安全,快速可靠的消息传递。 Metro帮助创建具有事务,安全性,可靠性功能的web服务/ Metro三层服务栈: ①帮助开发者开发面向业务的web服务以满足业务需求 ②定义用于在客户端与web服务间通信的标准 3.定义用于处理web服务所使用的XML数据的API(DOM/SAX) WSIT Web服务栈的实现规范: ①核心XML ②引导和配置 3.优化 ④可靠性 5.安全性。 web服务模式: 设计模式是解决编程问题的经过深思熟虑且以前使用的解决方案。 Web服务设计模式优点: ①设计模式提供经验有效的解决方案,可以创建易于理解和维护的松散耦合的模块。 ②设计人员可以通过根据设计模式提供的高级设计调整其Web组件来解决设计问题。 常见重要的Web设计模式: ①异步交互模式 ②Web服务缓存 3.web服务代理模式 4。web服务日志器模式 导致web服务出现性能瓶颈的原则: ①网络等待事件 ②处理消息花费事件 3.执行web服务操作花费的时间 部署模式是解决部署问题的经过深思熟虑且以前使用的解决方案。 常见的重要的部署模式: HTTP负载均衡模式 容器集群模式 HTTP负载均衡所用算法: ①循环:将请求均分到各个服务器 ②加权循环:将请求分发到当前性能最好的服务器 3.最少连接:将请求分发到当前连接数最少的服务器 4.基于负载:将请求分发到当前负载最小的服务器 选择题: 第一单元:SOA架构以及基于XML的web服务API介绍。(JAX**) SOA代表Service-oriented Architecture(面向服务架构) WSDL用于描述基于XML的web服务 JAX-WS用来开发基于XML的web服务 JAXR用来访问web服务注册表 SAAJ以SOAP附件形式来发送视频,图像等文档,SOAP with Attachment API for Java 第二单元:基于XML的web服务组成 抽象WSDL文件包含portType元素 具体WSDL文件包含service元素 绿页提供关于帮助使用者的技术信息 SOAP消息处理程序用于截取Web服务的请求和响应中的SOAP消息。 第三单元:实现基于XML的web服务 @OneWay方法定义的Web方法具有输入但是没有输出 javax.xml.ws.spi包定义了JAX-WS的service provider接口 MTOM是一种新型的附件规范,应用于SOAP附件消息 javax.xml.ws包定义了JAX-WS API @WebMethod批注仅受具有@WebService批注的那些类支持 第四单元:REST架构: 显示有状态特性不是REST设计原则(使用HTTP方法,显示无状态特性,公开目录结构,以XML/JSON格式传输数据) 您想要易于开发和使用的轻量级Web服务是使用RESTful Web服务的场景 您想要服务器处理数据的序列化和反序列化是使用基于XML的web服务的场景 GET方法用于读取当前状态资源 JSON是用于数据交换的格式。 第五单元:实现RESTful Web服务:(JAX-RS相关:javax.ws.rs javax.ws.rs.core javax.ws.rs.ext) java.ws.rs.core才是JAX-RS API的一部分(java.ws.core不是) RuntimeDelegate类是在javax.ws.rs.ext包中定义的 @Context批注是由javax.ws.rs.core包提供的 javax.ws.rs包定义了WebApplicationException javax.ws.rs.ext定义了MessageBodyWriter和MessageBodyReader @POST后面没有/customer请求 也没有content-type=application/xml 仅仅只有@POST 第六单元:处理SOAP消息(单SOAP以及SAAJ)(基于XML以及RESTful) Java提供JAXP API来解析XML数据 org.xml.sax包包含SAX API的基本接口 javax.xml.bind包提供作为Java应用程序进入JAXB框架入口点的JAXBContent类 javax.xml.soap.DetailEntry接口存储关于SOAPFault对象的信息 javax.xml.soap包的MessageFactory类用来初始化SOAPMessage对象 第7单元:Metro堆栈 Metro堆栈不适用JAXR的XML处理库(JAXR是注册web服务的) WSIT web服务不实现事务规范 XML Infoset不是核心XML规范 引导是解析WSDL文件的过程。 WSIT不能创建RESTful Web服务 第8单元:Web服务设计模式 设计模式定义:解决编程问题的经过深思熟虑且以前使用的解决方案。 容器集群模式是部署模式 日志写入程序不是安全日志器模式的组件。 HTTP负载平衡模式是部署模式 HTTP负载均衡不适用低连接,使用最少连接算法。

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

Docker技术剖析:Docker背后的内核知识

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhaobryant/article/details/79599432 Docker本质上是运行在宿主机上的进程,它通过namespace实现了资源隔离,并通过cgroups实现了资源限制,同时通过写时复制(copy-on-write)实现了高效的文件操作。 一、通过namespace实现资源隔离 Linux内核中提供了6种namespace隔离的系统调用,分别完成对文件系统、网络、进程间通信、主机名、进程号以及用户权限的隔离。 具体如下所示: namespace 系统调用参数 隔离内容 UTS CLONE_NEWUTS 主机名与域名 IPC CLONE_NEWIPC 信号量/消息队列/共享内存 PID CLONE_NEWPID 进程编号 Network CLONE_NEWNET 网络设备/网络栈/端口等 Mount CLONE_NEWNS 挂载点(文件系统) User CLONE_NEWUSER 用户和用户组 Linux内核实现namespace的主要目的之一就是实现轻量级虚拟化容器服务。 在同一个namespace下的进程可以感知彼此的变化,而对外界的进程一无所知。这样就可以让容器中的进程产生错觉,仿佛置身于一个独立的系统环境中,从而达到独立和隔离的目的。 1. 进行namespace API操作的4种方式 namespace的API包括clone()、setns()、unshare()以及/proc下的部分文件。 (1)通过clone()在创建新进程的同时创建namespace 对于clone()系统调用,其调用方式如下: int clone(int (*child_func)(void *), void *child_stack, int flags, void *args); clone()实际上是Linux系统调用fork()的一种更通用的实现方式,它可以通过flags来控制使用多少功能。 clone()标志位参数中与namespace相关的四个参数分别是: child_func:用于传入子进程运行的程序主函数; child_stack:用于传入子进程使用的栈空间; flags:表示使用哪些CLONE_*标志位,主要包括如上表所示的系统调用参数; args:表示可用于传入的用户参数。 (2)通过setns()加入一个已经存在的namespace 对于setns()系统调用,其调用方式如下: int setns(int fd, int nstype); 通过setns()系统调用,进程可以从原来的namespace加入某个已存在的namespace中。 setns()系统调用中的参数如下: fd:表示要加入namespace的文件描述符。namespace实际上也是一个文件,有对应的文件描述符。它是一个指向/proc/[pid]/ns目录的文件描述符。 nstype:表示是否检查fd指向的namespace类型是否符合实际要求。该参数为0表示不检查。 通常,为了不影响进程的调用者,也为了使新加入的pid namespace生效,会在setns()函数执行后使用clone()创建子进程继续执行命令,让原先的进程结束运行。 例如,新创建namespace,并在该namespace中调用/bin/bash并接受参数,以运行shell。用法如下所示: fd = open(argv[1], O_RDONLY); // 获取namespace文件描述符 setns(fd, 0); // 加入新的namespace execvp(argv[2], &argv[2]); // 执行程序 假设编译后的程序名称为setnsdemo,于是可以执行: $ ./setnsdemo /proc/27514/ns/uts /bin/bash # uts是对应进程号为27514的进程对应uts的namespace号 至此,就可以在新加入的namespace中执行shell命令了。 (3)通过unshare()在原先进程上进行namespace隔离 对于unshare()系统调用,其调用方式: int unshare(int flags); 与clone()不同的是,unshare()运行在原来的进程上,不需要启动一个新进程。调用unshare()的主要作用是不启动一个新进程就可以起到隔离的效果,相当于跳出原先的namespace进行操作。 (4)查看/proc/[pid]/ns文件 从3.8版本的内核开始,用户就可以在/proc/[pid]/ns文件夹下看到指向不同namespace号的文件,如下图所示: 注意:如果两个进程指向的namespace编号相同,就说明它们在同一个namespace之下,否则便在不同namespace中。 那么为什么要在/proc/[pid]/ns中设置这些link链接呢? 其一:用于记录[pid]所对应的进程的namespace信息,方便查阅; 其二:一旦上述link文件被打开,只要打开的文件描述符存在,就算该namespace下的所有进程都已经结束,这个namespace也会一直存在,后续进程也可以再加入进来。 在Docker中,通过文件描述符定位和加入一个存在的namespace是最基本的方式。 2. UTS namespace UTS(Unix Time-sharing System)namespace提供了主机名和域名的隔离,这样,每个Docker容器就可以拥有独立的主机名和域名了,在网络上可以被当作一个独立的节点,而非宿主机上的一个进程,其标志位为CLONE_NEWUTS。 在Docker中,每个镜像基本都以自身所提供的服务名称来命名镜像的hostname,且不会对宿主机产生任何影响,其原理就是使用了UTS namespace。 使用对比: 没有使用UTS的情况 运行结果如下: 使用UTS的情况 运行结果如下: 可见,当使用UTS隔离之后,整个子进程的主机名和域名发生了改变。 3. IPC namespace 进程间通信(Inter-Process Communication, IPC)涉及的IPC资源包括常见的信号量、消息队列和共享内存,其标志位为CLONE_NEWIPC。 对于IPC资源申请,申请IPC资源就申请了一个全局唯一的32位ID,因此,IPC namespace中实际上包含了系统IPC标识符以及实现POSIX消息队列的文件系统。 在同一个IPC namespace下的进程彼此可见,不同IPC namespace下的进程则互相不可见。 对于IPC namespace隔离的测试,可以参考:http://crosbymichael.com/creating-containers-part-1.html 4. PID namespace PID namespace隔离对进程PID重新标号,即两个不同namespace下的进程可以有相同的PID。每个PID namespace都有自己的计数程序,标志位为CLONE_NEWPID。 内核为所有的PID namespace维护了一个树状结构,最顶层的是系统初始时创建的,被称为root namespace。它创建的新的PID namespace被称为child namespace(树的子节点),而原先的PID namespace就是创建的新的PID namespace的parent namespace(树的父节点)。通过这种方式,不同的PID namespace就会形成一个层级体系。所属的父节点可以看到子节点中的进程,并可以通过信号等方式对子节点中的进程产生影响,但是子节点却不能看到父节点PID namespace中的任何内容。 关于PID namespace的相关结论: 每个PID namespace中的第一个进程“PID 1”,都如同init进程一样具有特殊作用。 namespace中的进程不能通过kill或ptrace来影响父节点或兄弟节点中的进程。 在root namespace中可以看到所有的进程,并且递归包含所有子节点中的进程。 一种在外部监控Docker中运行程序的方法:监控Docker daemon所在的PID namespace下的所有进程及其子进程,再进行筛选即可。 对于PID namespace中的init进程,其主要用于维护所有后续启动进程的运行状态。当系统中存在树状嵌套结构的PID namespace时,若某个子进程成为孤儿进程,收养该子进程的责任就交给了该子进程所属的PID namespace中的init进程。通观而言,PID namespace维护这样一个树状结构有利于系统的资源监控与回收。因此,如果确实需要在一个Docker容器中运行多个进程,最先启动的命令进程应该是具有资源监控与回收等管理能力的,如/bin/bash。另外,对于PID namespace中的init进程,其同时具有信号屏蔽的特权。也就是说,与init在同一个PID namespace下的进程(即使有超级权限)发送给它的所有信号都会被屏蔽,以防止init进程被误杀。但是,当父节点PID namespace中的进程发送相同的信号给子节点PID namespace中的init进程时,如果该信号是SIGKILL(销毁进程)或SIGSTOP(暂停进程),子节点的init进程会强制执行,其余的信号则会被忽略。同时,一旦init进程被销毁,同一PID namespace中的其他进程也随之接收到SIGKILL信号而被销毁。 对于PID namespace的ps命令,如果只想看到PID namespace本身应该看到的进程,需要重新挂载/proc,命令如下: zjl@ubuntu:~$ mount -t proc proc /proc zjl@ubuntu:~$ ps a 5. mount namespace mount namespace通过隔离文件系统挂载点对文件系统的隔离提供支持,它是第一个Linux namespace,因此标志位比较特殊,为CLONE_NEWNS。 可以通过/proc/[pid]/mount查看到所有挂载在当前namespace中的文件系统,还可以通过/proc/[pid]/mountstats看到mount namespace中文件设备的统计信息,包括挂载文件的名字、文件系统类型、挂在位置等。 具体如下图所示: $ vim /proc/2430/mounts $ vim /proc/2430/mountstats 进程在创建mount namespace时,会把当前的文件结构复制给新的mount namespace。新的mount namespace中的所有mount操作都只影响自身的文件系统,对外界不会产生任何影响。 mount namespace机制:挂载传播(mount propagation)。 挂载传播定义了挂载对象(mount object)之间的关系,这样的关系包括共享关系和从属关系,系统用这些关系决定任何挂载对象中的挂载事件如何传播到其他挂载对象。 共享关系(share relationship):如果两个挂载对象具有共享关系,那么一个挂载对象中的挂载事件会传播到另一个挂载对象,反之亦然。 从属关系(slave relationship):如果两个挂载对象形成从属关系,那么一个挂载对象中的挂载事件会传播到另一个挂载对象,但是反之不行。 一个挂载状态可能为以下一种: 共享挂载(shared):传播事件的挂载对象。 从属挂载(slave):接收传播事件的挂载对象。 私有挂载(private):既不传播也不接收传播事件的挂载对象。 不可绑定挂载(unbindable):不允许执行绑定挂载。 示意图如下: 如图,可以得知: mount namespace下的/bin目录与child namespace通过master/slave方式进行挂载传播,当mount namespace中的/bin目录发生变化时,其挂载事件会自动传播到child namespace中; /lib目录使用完全的共享挂载传播,各namespace之间发生的变化都会互相影响; /proc目录使用私有挂载传播的方式,各个mount namespace之间相互隔离; /root目录一般都是管理员所有,不能让其他mount namespace挂载绑定。 在默认情况下,所有挂载状态都是私有挂载。 设置为共享挂载的命令如下: $ mount --make-shared <mount-object> 从共享挂载状态的挂载对象克隆的挂载对象,其状态也是共享的,它们互相传播挂载事件。 设置为从属挂载的命令如下: $ mount --make-slave <shared-mount-object> 来源于从属挂载对象克隆的挂载对象也是从属挂载,它也从属于原来的从属挂载的主挂载对象。 将一个从属挂载对象设置为共享/从属挂载的命令如下: $ mount --make-shared <slave-mount-object> 对于CLONE_NEWNS,当CLONE_NEWNS生效之后,子进程进行的挂载与卸载操作都将只作用于该mount namespace。 6. network namespace network namespace主要提供了关于网络资源的隔离,包括网络设备、IPv4和IPv6协议栈、IP路由表、防火墙、/proc/net目录、/sys/class/net目录以及套接字(socket)等。 对于网络设备,其最多存在于一个network namespace中,可以通过创建veth pair在不同的network namespace间创建通道,以达到通信的目的。对于veth pair,其表示虚拟网络映射对,它有两端,类似管道,如果数据从一端传入,另一端也能接收到。一般情况下,物理网络设备都分配在最初的root namespace中,但是,如果有多块物理网卡,也可以把其中一块或多块分配给新创建的network namespace。 对于network namespace,我们可以认为其是将网络独立出来,模拟一个独立网络实体与外部用户实体进行通信。对于该过程,容器的经典做法就是:创建一个veth pair,一端放置于新的network namespace中,通常命名为eth0,另一端放置在原来的network namespace中连接物理网络设备,然后,再通过把多个设备接入网桥或进行路由转发,以实现网络通信的目的。 另外,在建立起veth pair之前,新的network namespace和旧的network namespace之间通过管道(pipe)来进行通信。具体示意图如下图所示: 与其他namespace类似,对network namespace的使用其实就是在创建的时候添加CLONE_NEWNET标志位。 7. user namespace user namespace主要隔离了安全相关的标识符(identifier)和属性(attributes),包括用户ID、用户组ID、root目录、密钥以及特殊权限。也就是说,一个普通用户的进程通过clone()创建的新进程在新user namespace中可以拥有不同的用户和用户组。这意味着一个进程在容器外属于一个没有特权的普通用户,但是它创建的容器进程却属于拥有所有权限的超级用户。相应的,其在clone()中的标志位为CLONE_NEWUSER。 8. 小结 本节从namespace使用的API开始,结合Docker逐步对6个namespace进行了讲解。 二、cgroups资源限制 对于cgroups,它可以用于限制被namespace隔离起来的资源,还可以为资源设置权重、计算使用量、操控任务启动和停止等。 1. cgroups概念 cgroups是Linux内核提供的一种机制,这种机制可以根据需求把一系列系统任务及其子任务整合(或分隔)到按资源划分等级的不同组内,从而为系统资源管理提供一个统一的框架。也就是说,cgroups可以限制、记录任务组所使用的物理资源(包括CPU、memory、IO等),为容器实现虚拟化提供了基本保证,是构建Docker等一系列虚拟化管理工具的基石。 cgroups具有如下四个特点: cgroups的API以一个伪文件系统的方式实现,用户态的程序可以通过文件操作实现cgroups的组织管理; cgroups的组织管理操作单元可以细粒度到线程级别,另外用户可以创建和销毁cgroup,从而实现资源再分配和管理; 所有资源管理的功能都以子系统的方式实现,接口统一; 子任务创建时与其父任务处于同一个cgroups的控制组。 从本质上,cgroups是内核附加在程序上的一系列钩子(hook),通过程序运行时对资源的调度触发相应的钩子以达到资源追踪和限制的目的。 2. cgroups作用 从单个任务的资源控制到操作系统层面的虚拟化,cgroups提供了如下四大功能: 资源限制:cgroups可以对任务使用的资源总额进行限制。 优先级分配:通过分配的CPU时间片数量以及磁盘IO带宽大小,实际上就相当于控制了任务运行的优先级。 资源统计:cgroups可以统计系统的资源使用量,如CPU使用时长等。 任务控制:cgroups可以对任务执行挂起、恢复等操作。 3. cgroups结构 在cgroups中,主要有如下几个术语: task(任务):任务表示系统的一个进程或线程; cgroup(控制组):cgroup是cgroups进行资源控制的单位,它表示按某种资源控制标准划分而成的任务组,包含一个或多个子系统。一个任务可以加入某个group,也可以从某个cgroup迁移到另外一个cgroup中; subsystem(子系统):cgroups中的子系统就是一个资源调度控制器,如CPU子系统可以控制CPU时间分配,内存子系统可以限制cgroup内存使用量; hierachy(层级):层级由一系列cgroup以一个树状结构排列而成,每个层级通过绑定对应的子系统进行资源控制。层级中的cgroup节点可以包含零或多个子节点,子节点继承父节点挂载的子系统。 出于易于管理的目的,在Docker中,每个子系统独自构成一个层级。 对于cgroups的组织结构,主要有以下几个基本规则: 规则1:同一个层级可以附加一个或多个子系统。 规则2:一个子系统可以附加到多个层级,当且仅当目标层级只有唯一一个子系统时。 规则3:系统每次新建一个层级时,该系统上的所有任务默认加入这个新建层级的初始化cgroup,这个cgroup又称root cgroup。对于创建的每个层级,任务只能存在于其中一个cgroup中,即一个任务不能存在于同一个层级的不同cgroup中,但一个任务可以存在于不同层级中的多个cgroup中。如果操作时把一个任务添加到同一个层级的另一个cgroup中,则会将它从第一个cgroup中移除。 规则4:任务在fork/clone自身时创建的子任务默认与原任务在同一个cgroup中,但是子任务允许被移动到不同的cgroup中。 4. cgroups子系统 在cgroups中,子系统实际上就是cgroups的资源控制系统,每种子系统独立地控制一种资源,目前Docker使用如下9种子系统,具体如下: blkio:为块设备设定输入/输出限制,比如物理驱动设备(包括磁盘、固态硬盘、USB等)。 cpu:使用调度程序控制任务对CPU的使用。 cpuacct:自动生成cgroup中任务对CPU资源使用情况的报告。 cpuset:可以为cgroup中的任务分配独立的CPU和内存。 devices:可以开启或关闭cgroup中任务对设备的访问。 freezer:可以挂起或恢复cgroup中的任务。 memory:可以设定cgroup中任务对内存使用量的限定,并且自动生成这些任务对内存资源使用情况的报告。 perfevent:使用后使得cgroup中的任务可以进行统一的性能测试。 net_cls:Docker没有直接使用,它通过使用等级识别符(classid)标记网络数据包,从而允许Linux流量控制程序(TC:Traffic Controller)识别从具体cgroup中生成的数据包。 5. cgroups实现方式及工作原理 cgroups的实现本质上是给任务挂上钩子,当任务运行的过程中涉及某种资源时,就会触发钩子上所附带的子系统进行检测,然后根据资源类别的不同使用对应的技术进行资源限制和优先级分配。 (1)cgroups如何判断资源超限及超出限额之后的措施 对于不同的系统资源,cgroups提供了统一的接口对资源进行控制和统计,但限制的具体方式不尽相同。 (2)cgroup的子系统与任务之间的关联关系 实现上,cgroup与任务之间是多对多的关系,因此它们并不直接关联,而是通过一个中间结构把双向的关联信息记录起来。每个任务结构体task_struct都包含了一个指针,可以查询到对应cgroup的情况,同时也可以查询到各个子系统的状态,这些子系统状态中也包含了找到任务的指针,不同类型的子系统按需定义本身的控制信息结构体,最终在自定义的结构体中把子系统状态指针包含进去,然后内核通过container_of等宏定义来获取对应的结构体,关联到任务,以此达到资源限制的目的。 在实际的使用过程中,需要通过挂载cgroup文件系统来新建一个层级结构,挂载时需要指定要绑定的子系统,缺省情况下默认绑定系统所有子系统。在将cgroup文件系统挂载以后,就可以像操作文件一样对cgroups的hierarchy层级进行浏览和操作管理(包括权限管理、子文件管理等等)。除了cgroup文件系统以外,内核没有为cgroups的访问和操作添加任何系统调用。当一个顶层的cgroup文件系统被卸载时,如果其中创建后代cgroup目录,那么就算上层的cgroup被卸载了,层级也是激活状态,其后代cgoup中的配置依旧有效。只有递归式的卸载层级中的所有cgoup,那个层级才会被真正删除。层级激活后,/proc目录下的每个task PID文件夹下都会新添加一个名为cgroup的文件,列出task所在的层级,对其进行控制的子系统及对应cgroup文件系统的路径。同时,一个cgroup创建完成,不管绑定了何种子系统,其目录下都会生成以下几个文件,用来描述cgroup的相应信息。同样,把相应信息写入这些配置文件就可以生效,内容如下: tasks:这个文件中罗列了所有在该cgroup中task的PID。该文件并不保证task的PID有序,把一个task的PID写到这个文件中就意味着把这个task加入这个cgroup中。 cgroup.procs:这个文件罗列所有在该cgroup中的线程组ID。该文件并不保证线程组ID有序和无重复。写一个线程组ID到这个文件就意味着把这个组中所有的线程加到这个cgroup中。 notify_on_release:填0或1,表示是否在cgroup中最后一个task退出时通知运行release agent,默认情况下是0,表示不运行。 release_agent:指定release agent执行脚本的文件路径(该文件在最顶层cgroup目录中存在),在这个脚本通常用于自动化umount无用的cgroup。 可参考:http://www.infoq.com/cn/articles/docker-kernel-knowledge-cgroups-resource-isolation 6. 小结 本节浅入深出地讲解了cgroups,从cgroups是什么,到cgroups该怎么用,最后对大量地cgroup子系统配置参数进行了梳理。

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

8张图带你轻松温习Java知识

年初四好,一图胜千言,下面图解均来自Program Creek 网站,目前它们拥有最多的票选。 如果图解没有阐明问题,那么你可以借助它的标题来一窥究竟。 1 字符串不变性 下面这张图展示了这段代码做了什么 [code ]String s = "abcd"; s = s.concat("ef");[/code] 2 equals()方法、hashCode()方法的区别 HashCode被设计用来提高性能。equals()方法与hashCode()方法的区别在于: 如果两个对象相等(equal),那么他们一定有相同的哈希值。 如果两个对象的哈希值相同,但他们未必相等(equal)。 3 Java异常类的层次结构 图中红色部分为受检查异常。它们必须被捕获,或者在函数中声明为抛出该异常。 4 集合类的层次结构 注意Collections和Collection的区别。(Collections包含有各种有关集合操作的静态多态方法) 5 Java同步 Java同步机制可通过类比建筑物来阐明。 6 别名 别名意味着有多个变量指向同一可被更新的内存块,这些别名分别是不同的对象类型。 7 堆和栈 图解表明了方法和对象在运行时内存中的位置。 8 Java虚拟机运行时数据区域 图解展示了整个虚拟机运行时数据区域的情况。 推荐:成为架构师的四阶段学习资料 推荐:分享一套高级Java笔试题(实拍高清图) 推荐:过年回家,程序猿最怕的5件事 如果对你有用,欢迎分享到朋友圈

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

聊一聊虚拟化基础知识

【大咖・来了 第7期】10月24日晚8点观看《智能导购对话机器人实践》 引言 开始前给大家举个例子: 场景如下:一台服务器只有有8G内存,程序A需要4G内存,程序B需要4G内存,传统架构无法满足这样的场景,那只有依靠虚拟化来解决,通过虚拟化方式,我们可以不仅提供2台4G内存,更可以通过内存气泡、内存复用、内存置换等技术实现超分配! Part A.虚拟化简介 虚拟化是云计算的基础,基于虚拟化我们可以实现私有云、公有云、桌面云等。 虚拟化是一种资源管理技术,是将计算机的各种实体资源(CPU、内存、磁盘空间、网络适配器等),予以抽象、转换后呈现出来并可供分区、组合为一个或多个电脑配置环境。由此,打破实体结构间的不可切割的障碍,使用户可以比原本的配置更好的方式来应用这些电脑硬件资源。这些资源的新虚拟部分是不受现有资源的架设方式,地域或物理配置所限制。一般所指的虚拟化资源包括计算能力和数据存储。 虚拟化架构 几个重要的概念: A.宿主机:Host ,即物理服务器 B.虚拟机:Guest ,也称客户机、虚机 C.VMM(virtual Machine Monitor):即Hypervisors,它是一种运行在基础物理服务器和操作系统之间的中间软件层,可允许多个操作系统和应用共享硬件。Hypervisors是一种在虚拟环境中的“元”操作系统。他们可以访问服务器上包括磁盘和内存在内的所有物理设备。Hypervisor不但协调着这些硬件资源的访问,也同时在各个虚拟机之间施加防护。当服务器启动并执行Hypervisor时,它会加载所有虚拟机客户端的操作系统同时会分配给每一台虚拟机适量的内存、CPU、网络和磁盘。 Part B.虚拟化的分类 【常规分类】 此外还有混合虚拟化,是指将一个内核级驱动器插入到宿主操作系统内核。这个驱动器作为虚拟硬件管理器来协调虚拟机和宿主操作系统之间的硬件访问。混合虚拟化需要底层硬件支持虚拟化扩展功能。 【基于Guest OS CPU对硬件访问分类】 CPU的运行级别,Ring 0也称为核心态,操作系统需要直接访问硬件和内存,使用特权指令,控制中断、修改页表、访问设备,因此它的代码需要运行在***运行级别。Ring 3也称为用户态,需要访问磁盘、写文件时,则需要调用系统函数,这样的操作称为用户态到核心态。 大家都知道宿主机的操作系统运行级别是Ring 0,虚拟机的操作系统就无法在Ring 0级别运行,但是虚拟机OS不知道这一点,执行的命令与物理机无异,但是没有执行权限是会出错的。所以这时候虚拟机管理程序(VMM)需要避免这件事情发生。 虚机怎么通过 VMM 实现 Guest CPU 对硬件的访问,根据其原理不同有三种实现技术: 1. 全虚拟化 2. 半虚拟化 3. 硬件辅助的虚拟化 主要区别见下图: A.全虚拟化 一般采用优先级压缩技术(Ring Compression)和二进制代码翻译技术(BinaryTranslation)。优先级压缩技术让VMM和Guest运行在不同的特权级下。对x86架构而言,即VMM运行在***特权级别Ring 0下,guest OS运行在Ring 1下,用户应用运行在Ring 3下。因此,Guest OS的核心指令无法直接下达到计算机系统硬件执行,而是需要经过VMM的捕获和模拟执行(部分难以虚拟化的指令需要通过Binary Translation技术进行转换)。 B.辅助虚拟化 当前主要有Intel的VT-x和AMD的AMD-V这两种技术。其核心思想都是通过引入新的指令和运行模式,使VMM和Guest OS分别运行在不同模式(ROOT模式和非ROOT模式)下,且Guest OS运行在Ring 0下。通常情况下,Guest OS的核心指令可以直接下达到计算机系统硬件执行,而不需要经过VMM。当Guest OS执行到特殊指令的时候,系统会切换到VMM,让VMM来处理特殊指令。 C.全虚拟化 采用Hypercall技术。Guest OS的部分代码被改变,从而使Guest OS会将和特权指令相关的操作都转换为发给VMM的Hypercall(超级调用),由VMM继续进行处理。而Hypercall支持的批处理和异步这两种优化方式,使得通过Hypercall能得到近似于物理机的速度。 【按虚拟化技术分类】 1.服务器虚拟化,计算、存储、网络和IO的虚拟化 2.存储虚拟化,如Serversan,支持虚拟化的存储阵列等 3.网络虚拟化,如vlan、虚拟防火墙、虚拟分布式交换机 4.桌面(应用)虚拟化,即桌面云 其他分类这里不在细说,下面给大家分享下KVM和XEN的一些区别: 【对比KVM和XEN】 Xen作为***秀的半虚拟化引擎,在基于硬件的虚拟化帮助下,现在也完全支持虚拟化MS Windows。被设计成一个独立的内核,它只需要Linux执行 I/O,这样使得它非常的大,并且它有自己的调度程序、内存管理器、计时器和机器初始化程序。 做华为虚拟化的同学应该都知道有个Dom0,这个Dom0是个什么东西呢?这个Domain 0(特权虚拟机)是其他虚拟机的管理者和控制者,可以构建其他更多Domain,并管理虚拟设备。它还能执行管理任务,比如虚拟机的休眠、唤醒和迁移其他虚拟机。此外,还有个Dom u,这个是指除了Dom 0之外的普通虚拟机。 KVM是一个独特的管理程序,其让Linux内核自身变成一个管理程序,通过KVM作为一个内核模块实现,在虚拟环境下Linux内核集成管理程序将其作为一个可加载的模块,可以简化管理以及提升性能。KVM使用标准Linux调度程序、内存管理器和其他服务。将虚拟技术建立在内核上而不是去替换内核。 KVM架构 Xen架构 此外,还有微软的Hyper-V、OpenVz,这里不再跟大家介绍! Part C.虚拟化的优势 1.降低运营成本 服务器虚拟化降低了IT基础设施的运营成本,运维人员可以从繁重的物理服务器、OS、中间件及兼容性的管理工作解放处理,减少人工干预频率,使管理更加强大、便捷。 2.缩短上线周期 虚拟化中对可以将需要批量预安装机器进行模板化,使用模板创建虚拟机,不仅可以缩短安装周期,也可以减少人工带来的配置失误。从而缩短操作系统安装部署周期,进而缩短业务的上线周期。 3.提高可靠性 通过集群部署、双网卡、双电源以及OS盘的RAID策略都可以为我们提升基础架构的可靠性。通过对集群设置,我们可以实现虚拟机的冷热迁移,故障恢复甚至容错等,从而在架构上实现了高可靠。 4.提高资源利用率 摆脱传统架构单台服务器单个应用,通过虚拟化技术,资源可以以更小的单位提供,可以实现一比多的形式,很大程度提高了物理资源的利用率,同时,可对虚拟机进行隔离,保证了安全性。 5.动态资源调度(DRS) 通过DRS可以实现机房节能环保,降低功耗,在资源闲置时自动迁移并关闭部分资源,资源紧张时可自动开启资源并负载均衡 Part D.几种虚拟化关键技术 一、内存复用 a.内存共享:虚拟机内存只读时,可共享同一内存空间,需要写时,再分配空间。 b.内存气泡:虚拟机之间的内存交换负载,即内存使用低的释放给内存使用较高的虚拟机。 c.内存置换:暂时不用的内存置换到存储中,从而提高内存使用。 二、CPU相关 CPU虚拟化的开启,物理在BIOS里面设置相关Virtual Technology项,如果需要开启虚拟化嵌套,则需要在VMwareworkstation设置相关虚拟化模式,如果是kvm的嵌套则可能需要升级内核。 三、ServerSan ServerSan通常基于传统的X86服务器,配以SSD做缓存和万兆网卡做传输,同时满足了计算和存储资源,从而实现了计算和存储的融合,大多数的ServerSan都基于开源的Ceph,不仅可以实现高性能,也可以实现数据的多副本,更可以实现存储的高级功能,如快照、链接克隆、精简配置等。 主要特点如下: 1.软件定义,独立于硬件; 2.分布式,不存在单点故障; 3.系统自治,自动进行故障自愈和数据平衡; 4.融合系统,存储和计算部署在相同硬件上; 5.横向扩展,最小部署(至少3台),按需扩容; 6.强一致性,只有所有副本写成功,单次写操作完成,确保从任意副本数据的完整性;

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

Android学习笔记(三)基础知识(2)

交互对话框 使用Android SDK中,具有交互功能的对话框是AlertDialog窗口。 package com.example.test8; import android.os.Bundle; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.support.v4.app.NavUtils; public class MainActivity extends Activity { private Button bt; int n=0; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt=(Button)findViewById(R.id.button1); bt.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub n++; String str=Integer.toString(n); bt.setText("点击次数:"+n); new AlertDialog.Builder(MainActivity.this) .setTitle("提示") .setMessage("对话框") .setPositiveButton("确定",new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub } } ) .show(); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } } 拖放相片特效 在Android中,拖动图片的特效可以通过Android.content.Context,Android,widget.BaseAdapter和Android.widget.imageView等来实现。 在下面的列子中,context可以像画布一样,随时可以被处理覆盖。Context是作为Android.content子类。通过widget.BaseAdapter作为容器来存放Gallery所需要的图片。 这里是通过使用Gallery实现的相片拖拽功能,具体代码如下: package com.example.test9; import android.os.Bundle; import android.app.Activity; import android.content.Context; import android.graphics.Color; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.Gallery; import android.widget.ImageView; import android.widget.TextView; import android.support.v4.app.NavUtils; public class MainActivity extends Activity { private TextView textview; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textview = (TextView)findViewById(R.id.textView1); textview.setText("特效演示"); textview.setTextColor(Color.BLUE); Gallery gallery=(Gallery)findViewById(R.id.gallery1); gallery.setAdapter(new ImageAdapter(this)); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } public class ImageAdapter extends BaseAdapter{ private Context myContext; private int[] myImageID={android.R.drawable.btn_minus, android.R.drawable.btn_radio, android.R.drawable.ic_lock_idle_low_battery, android.R.drawable.ic_menu_camera }; public ImageAdapter(Context c){ this.myContext=c; } public int getCount() { // TODO Auto-generated method stub return this.myImageID.length; } public Object getItem(int position) { // TODO Auto-generated method stub return position; } public long getItemId(int position) { // TODO Auto-generated method stub return position; } public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub ImageView i=new ImageView(this.myContext); i.setImageResource(this.myImageID[position]); i.setScaleType(ImageView.ScaleType.FIT_XY); i.setLayoutParams(new Gallery.LayoutParams(120,120)); return i; } } } 设置about关于信息 创建一个onCreateOptionsMenu(Menu menu)类函数,用于添加Menu菜单项,再利用onOptionItemSelected选择菜单项 package com.example.test10; import android.os.Bundle; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.view.Menu; import android.view.MenuItem; import android.support.v4.app.NavUtils; public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0,0,0,"关于"); menu.add(0,1,1,"退出"); return super.onCreateOptionsMenu(menu); } public boolean onOptionsItemSelected(MenuItem item){ super.onOptionsItemSelected(item); switch(item.getItemId()){ case 0: openOptionsDialog(); break; case 1: finish(); } return true; } private void openOptionsDialog(){ new AlertDialog.Builder(this) .setTitle("关于") .setMessage("***") .setPositiveButton("OK",new OnClickListener() { public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub } }) .show(); } } 程序加载中状态框 程序加载中的提示,此功能是通过Progress Dialog类来运行,此类在Android.app.ProgressDialog类里。但是,我们需要注意使用dismiss()函数来关闭取得焦点的对话框,否则程序将陷入死循环,也不能在线程里更改CONTEXT或parent view的任何状态。 package com.example.test11; import android.os.Bundle; import android.app.Activity; import android.app.ProgressDialog; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.support.v4.app.NavUtils; public class MainActivity extends Activity { private TextView text; private Button bt; public ProgressDialog myDialog=null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); text=(TextView)findViewById(R.id.textView1); bt=(Button)findViewById(R.id.button1); bt.setOnClickListener(myShowProgressBar); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } Button.OnClickListener myShowProgressBar=new Button.OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub final CharSequence strDialogTile="请等待"; final CharSequence strDialogBody="程序正在运行"; myDialog=ProgressDialog.show(MainActivity.this,strDialogTile,strDialogBody,true); text.setText(strDialogBody); new Thread(){ public void run(){ try{ text.setText("start"); sleep(3000); text.setText("end"); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); } finally{ myDialog.dismiss(); } } }.start(); } }; } 本文转自cococo点点博客园博客,原文链接:http://www.cnblogs.com/coder2012/archive/2013/05/16/3076677.html,如需转载请自行联系原作者

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

Android学习笔记(二)基础知识(1)

更改文字颜色 文字色: TextView.setTextColor(Color.***); 背景色: Resources resources = getBaseContext().getResources(); Drawable HippoDrawable = resources.getDrawable(R.drawable.white); TextView.setBackgroundDrawable(HippoDrawable); 获取手机分辨率 import android.util.DisplayMetrics DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); String x,y; x=dm.widthPixels; y=dm.heightPixels; 页面转换 在Android应用中,是通过setContentView来实现页面的转换处理的,也就是在不同的layout之间进行切换。 setContentView(R.layout.****); 例子: package com.example.test4; import android.os.Bundle; import android.app.Activity; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.support.v4.app.NavUtils; public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button b1=(Button)findViewById(R.id.button1); b1.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub jumpToMylayout(); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } public void jumpToMylayout(){ setContentView(R.layout.mylayout); Button b2 = (Button)findViewById(R.id.button1); b2.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub jumpToLayout(); } }); } public void jumpToLayout(){ setContentView(R.layout.activity_main); Button b1=(Button)findViewById(R.id.button1); b1.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub jumpToMylayout(); } }); } } 调用其他Activity 与上面在不同layout之间转换不同,这里我们需要移交主权到另外一个Activity。 //一个Activity Intent intent=new Intent(); intent.setClass(MainActivity.this,replace.class); startActivity(intent); MainActivity.this.finish(); //另外一个Activity Intent intent=new Intent(); intent.setClass(replace.this, MainActivity.class); startActivity(intent); replace.this.finish(); 不同Activity之间的数据转换 利用Android.os.Bundle对象封装数据的能力,将欲传递的数据或参数,通过Bundle来传递不同Intent之间的数据。 发送: Intent intent=new Intent(); intent.setClass(MainActivity.this,display.class); Bundle bundle = new Bundle(); bundle.putString("num",et1.getText().toString()); bundle.putString("name",et2.getText().toString()); intent.putExtras(bundle); startActivity(intent); 接收: Bundle bundle = this.getIntent().getExtras(); String num = bundle.getString("num"); String name = bundle.getString("name"); 返回数据到前一个Activity 唤起一个Activity: startActivityForResult(intent,0) 重载onActivityResult: protected voidonActivityResult(int requestCode,int resultCode,Intent data){ switch(resultCode){ case RESULT_OK: Bundle bundle=data.getExtras(); //code there break; default: break; } } 返回数据: input.this.setResult(RESULT_OK, intent); 部分代码: //main_activity package com.example.test7; import android.os.Bundle; import android.app.Activity; import android.content.Intent; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.support.v4.app.NavUtils; public class MainActivity extends Activity { TextView tx; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button bt=(Button)findViewById(R.id.button1); tx=(TextView)findViewById(R.id.textView1); bt.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub Intent intent = new Intent(); intent.setClass(MainActivity.this, input.class); startActivityForResult(intent,0); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } @Override protected void onActivityResult(int requestCode,int resultCode,Intent data){ switch(resultCode){ case RESULT_OK: Bundle bundle=data.getExtras(); String str=bundle.getString("str").toString(); tx.setText(str); break; default: break; } } } /** * input.java */ package com.example.test7; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; public class input extends Activity { Intent intent; Bundle bundle; EditText et; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.input); Button bt=(Button)findViewById(R.id.button1); et=(EditText)findViewById(R.id.editText1); intent = this.getIntent(); bundle= new Bundle(); bt.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub bundle.putString("str", et.getText().toString()); intent.putExtras(bundle); input.this.setResult(RESULT_OK, intent); input.this.finish(); } }); } } 本文转自cococo点点博客园博客,原文链接:http://www.cnblogs.com/coder2012/archive/2013/05/13/3075259.html,如需转载请自行联系原作者

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

IOS开发需要知道的知识-RunLoops

什么是Run Loops Run Loops是与线程想关联的基础部分。一个Run Loop就是事件处理循环,它是用来调度和协调接收到的事件处理。使用Run Loop的目的,就是使得线程有工作需要做时可以忙碌起来,而当没有事可做时,又可以使得线程睡眠。 Run Loop管理不都是自动的。我们必须手动设计线程代码,在合适的时候来启动Run Loop,并回应到来的事件。Cocoa和Core Foundation都提供了run loop对象来帮助我们配置和管理线程的run loop。我们的应用没有必要显式地创建这些对象;每个线程,包括应用程序的主线程,都有一个与之关联的run loop。只有子线程才需要显式地运行其run loop。App会将自动配置和来运行主线程的run loop的任务作为应用程序启动处理的一部分。 对于想要更深入地了解Run Loop Objects,阅读NSRunLoop Class Reference、CFRunLoop Reference 一个Run Loop的结构 Run Loop就像它的名字一样,它使得线程进入事件循环,能对到来的事件启动事件处理。你的代码中提供了流程控制说一句来实现run loop实实在在的循环部分,换句话说,你的代码提供了while或者for循环来驱动run loop。在你的循环中,你使用run loop对象在事件到达时,运行事件处理的代码并调起已安装的处理程序。Run Loop接收来自两种不同类型的源(sources)的事件: 输入源:异步传递事件,通常是来自不同的线程或不同的应用的消息。输入源异步传递事件到对应的处理程序和在线程关联的NSRunLoop对象调起runUntilDate:方法来退出事件处理。 Timer源:同步地传递事件,发生在每个定时器调用或周期性地调用。Timer源传递事件到他们的处理程序,但是不会调用run loop来退出处理。 这两种源在事件到达时都使用应用程序特定的处理程序来处理事件。 如下图所示,展示了run loop和不同的源的概述结构。 image 除了处理输入源之外,run loops还发出关于run loop行为的通知。我们可以注册成为run loop的观察者,就可以接收这些通知和使用它在线程上做一些额外处理。我们可以使用Core Foundation在对应的线程上注册成为run loop的观察者。 Run Loop Modes Run Loop模式是一个监视输入源和定时器的集合和注册成为run loop的观察者的集合。每次要运行run loop,都需要显示或隐式地指定某种运行的mode。只有与这种指定的mode关联的源才会被监视和允许传递他们的事件,同样地,只有与这种模式关联的观察者都会收到run loop行为变化的通知。与其它模式想关联的源,直到随后在合适的模式通过循环后,都会接收到新的事件(比如,将timer加入run loop default模式下,当滚动时,timer不会收到回调,直到停止滚动回到default模式下)。 在我们的代码中,我们通过名称来唯一标识mode。在Cocoa和Core Foundation中都定义了default模式和几个常用的模式,都是通过字符串名称来指定。我们也可以自定义模式,但是我们需要手动添加至少一个input source/timers/observers。 我们可以通过使用mode来过滤掉我们不希望接收到来自不想要的通过run loop的源。大部分情况下,我们都是使用系统定义的default模式。对于子线程,我们可以使用自定义模式在关键性操作时阻止低优先级的源传递事件。注意:Modes是通过事件源来区分,而不是事件类型来区分。比如说,我们不能使用mode来匹配只有mouse-down事件或者只有键盘事件。我们可以使用modes来监听不同系统的端口,临时挂起定时器,甚至改变正在被监视的sources和run loop观察者。 表格.png Input Sources 输入源异步传递事件到你的线程。事件的源由输入源的类型来决定,也就是两种源中的其中一种: Port-based:基于端口号的输入源监听应用程序的Mach端口。 Custom Input Sources:自定义输入源监听自定义的事件源。 系统通常实现了这两种输入源。唯一的不同点是它们是如何被发出信号的。port-based源是由内核(kernel)自动发出信号,而custom sources必须手动从其它线程发出信号。 当我们创建输入源时,可以指定mode。Modes会影响任何时刻被监视的输入源。大部分情况下,我们都让run loop在default mode下运行,但是也可以指定自定义的mode。如果一个输入源不是当前所监视的model,它所产生的任何事件都会被保留直接进入正常的mode。 Port-Based Sources Cocoa和Core Foundation提供了内建支持,可以使用与port相关的对象和函数来创建基于端口的输入源。举个例子,在Cocoa中永远不需要手动创建输入源。我们只需要简单地创建一个port对象和使用NSPort的方法。port对象为我们处理所需要的输入源的创建和配置。 在Core Foundation中,我们必须手动创建port和source。在这两种情况下,我们可以使用与port opaque type关联的函数(CFMessagePortRef, or CFSocketRef) 来创建合适的对象。 Custom Input Sources 在Core Foundation中,要创建自定义输入源,我们必须使用与CFRunLoopSourceRef关联的函数。我们配置自定义输入源可以使用几个回调函数。Core Foundation会在不同点回调这些函数来配置source,处理任何到达的事件和销毁已从run loop移除的source。 除了定义在事件到达时自定义源的行为之外,我们也必须定义事件传递机制。这部分源运行在单独的线程,负责提供输入源的数据,当数据准备好可以处理时,signaling(通知相关线程)这个消息。事件传递机制是我们自己来决定,但是不需要过于复杂。 Cocoa Perform Selector Source 除了基于端口的源之外,Cocoa还定义了自定义输入源允许我们在任意线程上执行selector。就像port-based源一样,执行selector请求会在目标线程上序列化,以减少在同一个线程中出现多个方法同步执行的问题。与port-based源不同的是,执行selector源在执行完毕后会自动将自己从run loop中移除。 当执行在其它线程执行selector时,目标线程必须要有运行的run loop。当我们创建线程时,这意味着直到启动了run loop都会显式地执行selector代码。 Run Loop每次经过一个循环,就会处理队列中所有的selector,而不仅仅是处理一个。 方法和说明。 Timer Sources Timer源在未来设定的时间会同步地传递事件到你的线程。Timers是线程通知自己去做一些事情的一种方式。比如说,搜索框可以使用定时器来初始化在一定时间就自动搜索,以便提供更多地联想词给用户。 尽管它发送基于时间的通知,但定时器并不是一种实时的机制。像输入源一样,定时器只有与run loop的mode一样才会发送通知。如果timer在run loop中并不是所被监视的mode,它不会触发定时器,直到run loop的mode与timer所支持的mode一样。 同样地,如果run loop正在处理中,timer已经fire了,这时候会被中断,直到下一次通过run loop才会调志处理程序。如果run loop已经不再运行了,则timer永远不会再fire。 我们可以配置timer只产生事件一次或者重复产生。重复的timer会自动根据调度的firing time自动调度,而不是真实的firing time。比如说,如果一个timer在特定的时间调度,然后每5秒重复一次。如果firing time被延迟导致缺少一或多次调用,那么timer在缺失的周期中只会调用一次。 Run Loop Observers 与sources在适当时机异步或同步发出事件不同,observers在run loop本身执行期间,会在特定的地方发出。你可能需要到run loop observers去准备线程处理特定的事件或者在进入睡眠之前。我们可以通过以下事件来关联run loop observers: 进入runlooprunloop将要处理timer runloop将要处理输入源 runloop将要进入睡眠 runloop被唤醒,但是还没有处理事件 退出runloop 我们可以通过Core Foundation来添加run loop observers。要创建run loop observer,可以通过CFRunLoopObserverRef来创建新的实例。这个类型会跟踪你所定义的回调函数和所感兴趣的活动。 与timers类型,run-loop observers可以使用一次或者重复多次。一次性的observer会在fire之后自动从run loop移除,而重复性的observer会继续持有。 The Run Loop Sequence Of Events 本小节讲的是RunLoop事件顺序。每次运行它,你的线程的run loop处理待处理的事件和给所有attached observers发出通知。处理的顺序如下: 1.通知observersrunloop已经进入2.通知observerstimers准备要fire3.通知observers有不是基于port-based的输入源即将要fire4.fire任何已经准备好的non-port-based输入源5.如果port-based输入源准备好且等待fire,则立即处理这个事件。然后进入步骤96.通知observers线程即将进入睡眠7.让线程进入睡眠,直到以下任何一种事件到达: *port-based输入源有事件到达 *timerfire *runloop超时 *runloop被显式唤醒8.通知observers线程被唤醒9.处理待处理的事件: *如果用户定义的timerfired了,处理timer事件并重新启动循环。进入步骤2 *如果输入源fired了,则传递事件 *如果runloop被显式唤醒,但是又未超时,则重启循环,进入步骤210.通知observersrunloop退出 由于observer对timer和输入源的通知会在事件真正发生之前被传递,这样就产生了间隙。如果这个间隙是很关键的,那么我们可以通过使用sleep和awake-from-sleep通知来帮助我们纠正这个时间间隔问题。 When Would You Use A Run Loop? 什么时候应该使用run loop呢? 只有当我们需要创建子线程的时候,才会需要到显示地运行run loop。应用程序的主线程的run loop是应用启动的基础任务,在启动时就会自动启动run loop。所以我们不需要手动启动主线程的run loop。 对于子线程,我们需要确定线程是否需要run loop,如果需要,则配置它并启动它。我们并不问题需要启动run loop的。比如说,如果我们开一个子线程去执行一些长时间的和预先决定的任务,我们可能不需要启动run loop。Run loop是用于那么需要在线程中有更多地交互的场景。比如说,我们会在下面的任何一种场景中需要开启run loop: 使用端口源或者自定义输入源与其它线程通信 在线程中使用定时器 使用Cocoa中的任何performSelector…方法 保持线程来执行周期性的任务 Using Run Loop Objects Run Loop对象给添加输入源、定时器和观察者到run loop提供了主接口。每个线程都有一个单独的run loop与之关联(对于子线程,若没有调用过任何获取run loop的方法是不会有run loop的,只有调用过,才会创建或者直接使用)。 在Cocoa中,通过NSRunLoop来创建实例,在low-level应用中,可以使用CFRunLoopRef类型,它是指针。 Getting A Run Loop Object 通过以下两种方式来获取run loop对象: 在Cocoa中,使用[NSRunLoop currentRunLoop]获取 使用CFRunLoopGetCurrent()函数获取 配置RunLoop 在子线程运行run loop之前,你必须至少添加一种输入源或者定时器。如果run loop没有任何的源需要监视,它就会立刻退出。 除了添加sources之外,你还可以添加观察者来检测runloop不同的执行状态。要添加观察者,可以使用CFRunLoopObserverRef指针类型和使用CFRunLoopAddObserver函数来添加到run loop中。我们只能通过Core Foundation来创建run loop观察者,即使是Cocoa应用。 下面这段代码展示主线程如何添加观察者到run loop以及如何创建run loop观察者: -(void)threadMain{//应用程序使用垃圾收集,因此不需要autorelease池。 NSRunLoop*myRunLoop=[NSRunLoopcurrentRunLoop];//创建一个运行循环观察者并将它附加到运行循环。 CFRunLoopObserverContextcontext={0,self,NULL,NULL,NULL};CFRunLoopObserverRefobserver=CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities,YES,0,&myRunLoopObserver,&context);if(observer){CFRunLoopRefcfLoop=[myRunLoopgetCFRunLoop];CFRunLoopAddObserver(cfLoop,observer,kCFRunLoopDefaultMode); }//创建和安排计时器。 [NSTimerscheduledTimerWithTimeInterval:0.1target:self selector:@selector(doFireTimer:)userInfo:nilrepeats:YES];NSIntegerloopCount=10;do{//运行运行循环10次让计时器。 [myRunLooprunUntilDate:[NSDatedateWithTimeIntervalSinceNow:1]]; loopCount--; }while(loopCount); } 在为长时间存在的线程配置run-loop时,最好添加至少一个输入源来接收事件。尽管我们可以只用timer源,但是一旦timer调用后,经常会被invalidate,这会导致run loop退出。 Starting the Run Loop 只有子线程才有可能需要启动run loop。Run loop必须至少有一种输入源或者timer源来监视。如果没有任何源,则run loop会退出。 下面的几种方式可以启动run loop: 无条件地:无条件进入run loop是最简单的方式,但也是最不希望这么做的,因为这样会导致run loop会进入永久地循环。可以添加、删除输入源和timer源,但是只能通过kill掉run loop才能停止。而且还不能使用自定义mode。 限时:与无条件运行run loop不同,最好是给run loop添加一个超时时间。 在特定的mode:除了添加超时时间,还可以指定mode。 下面是运行run loop的一段代码: -(void)skeletonThreadMain{//建立一个autorelease如果不使用垃圾收集池。 BOOLdone=NO;//添加你的来源或计时器运行循环,做其他任何设置。 do{//启动运行循环但每个源处理后返回。 SInt32result=CFRunLoopRunInMode(kCFRunLoopDefaultMode,10,YES); //如果源明确停止运行循环,或如果没有源或计时器,然后退出。if((result==kCFRunLoopRunStopped)||(result==kCFRunLoopRunFinished)) done=YES; //检查任何其他退出条件和设置完成所需的变量。}while(!done); //清理代码。一定要释放任何生成自动分配池。 } Exiting the Run Loop 有两种方法使run loop在处理事件之前,退出run loop: 给runloop设定超时时间 告诉runloop要stop 设定超时时间是比较推荐的。我们可以通过CFRunLoopStop函数来停止run loop。 Thread Safety and Run Loop Objects Core Foundation中的Run Loop API是线程安全的(以CF开头的API),而Cocoa中的NSRunLoop不是线程安全的。 Configuring Run Loop Sources 下面是展示如何配置不同类型的输入源。 Defining a Custom Input Source 创建自定义输入源涉及到以下部分: 想要处理的输入源的信息 让感兴趣的客户端知道如何联系输入源的调度程序 执行任何客户端发送的请求处理程序 使输入源失效的取消程序 Timer Source NSRunLoop*myRunLoop=[NSRunLoopcurrentRunLoop]; //创建和安排第一个定时器。NSDate*futureDate=[NSDatedateWithTimeIntervalSinceNow:1.0];NSTimer*myTimer=[[NSTimeralloc]initWithFireDate:futureDate interval:0.1 target:self selector:@selector(myDoFireTimer1:) userInfo:nil[myRunLoopaddTimer:myTimerforMode:NSDefaultRunLoopMode]; 或者使用Core Foundation: CFRunLoopRefrunLoop=CFRunLoopGetCurrent();CFRunLoopTimerContextcontext={0,NULL,NULL,NULL,NULL};CFRunLoopTimerReftimer=CFRunLoopTimerCreate(kCFAllocatorDefault,0.1,0.3,0,0, &myCFTimerCallback,&context);CFRunLoopAddTimer(runLoop,timer,kCFRunLoopCommonModes); 最后 本篇文章主要是官方文档的部分翻译版本,不过有很多无关的都省略了,而且有都转换成笔者的语言来表达出来,如果读不懂,最好还是去看官方文档吧。毕竟,英文与中文翻译不管怎么翻译都存在很大的问题。 疑问 官方文档中提到,每个线程都有一个run loop与之关联。但是实质上子线程在没有访问过run loop时,是不存在的。当访问时,若不存在则创建run loop并放到全局数组中。 本文转自 卓行天下 51CTO博客,原文链接:http://blog.51cto.com/9951038/1766775,如需转载请自行联系原作者

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

学习笔记-Linux系统基础知识2

shell GUI :graphic User Interface x-window CS架构 Gnome KDE Xface CLI: Command Line Interface sh bash csh ksh zsh tcsh dll: Dynamic Link Library .so: shared object login: 用户名:用户ID 认证机制: Authentication 授权:Authorization 审计:Audition(日志) prompt:命令提示符 命令: magic number:魔数 标识二进制命令执行的格式 Linux上的Shebang符号(#!) #!/bin/bash # command option arguments 短选项 - 长选择 -- arguments 作用对象 option 执行方式 有些选项可以带参数 目录:文件,路径映射 路径:从指定起始点到目的地所经过的路径 层次化文件管理的机制 File System Filesystem Hierarchy Standard(文件系统层次化标准)FHS FHS定义了系统中每个区域的用途、所需要的最小构成的文件和目录, 同时还给出了例外处理与矛盾处理 最顶级的/ ls:列出list pwd:Print Working Directory 文件类型: -:普通文件 d:目录文件 c:字符设备文件(character) b:块设备文件(block) l:符号连接文件(sysbolic link file)软连接 p:命令管道(pipe) s:套接字文件(socket) Xshell 远程登录工具 文件权限:9位 每3位一组,rwx 文件硬链接的次数 文件的属主(owner) 文件的属组(group) 文件大小(size) 单位是字节 时间戳(timestamp)最近一次被修改的时间(共有3个时间戳) 访问(access) 修改(modify)文件的内容发生了改变 改变(change),metadata,元数据,文件的属性 ls 指令 -h(human人类识别) :做单位转换 -a(all)显示以.开头的隐藏文件 (蓝色表示目录) -A :除..和.外的所有文件 -d : 显示目录自身属性 -i : 显示文件的索引节点号 index node(inode) -r : 逆序显示 -R :递归(recursive)显示 cd: change directory 家目录,主目录,home directory cd ~ 回到家目录 cd ~USERNAME 进入指定用户的家目录 cd - :当前目录和前一次所在的目录之间来回切换 命令类型: 内置命令(shell内置) 外部命令:在文件系统的某个路径下有一个与命令名称相应的可执行文件 环境变量:命名的内存空间 printenv 显示环境变量 PATH :使用冒号隔开的一堆路径 type:显示指定属于哪种类型 hash(hash表,键值对):缓存,记录缓存记录使用过的命令,次数和路径 o(1)速度级别 缓冲是实现系统加速的 本文转自飞行萌51CTO博客,原文链接:http://blog.51cto.com/8527508/1937448 ,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

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

Nacos

Nacos

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

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部分的功能。

用户登录
用户注册