首页 文章 精选 留言 我的

精选列表

搜索[笔记软件],共10010篇文章
优秀的个人博客,低调大师

Docker学习笔记之compose

一、compose compose 作用 你的应用可能需要很多个服务,比如web服务,数据库服务,缓存服务等等。我们可以把这些服务放到单独的容器里面,如果手工去配置这些服务会有些麻烦,docker compose可以帮我们解决这个问题。 我们可以创建一个compose文件,在这个文件上面描述你都需要哪些服务,服务使用什么镜像、数据卷、网络等等,然后再用一条命令就可以管理、启动所有的服务。 compose 文件 compose文件用的yml格式,docker规定了一些指令,使用它们可以去设置对应的东西,它主要分为了3个区域: services:是服务,在它下面可以定义应用需要的一些服务,每个服务都有自己的名字、使用的镜像、挂载的数据卷、所属的网络、依赖哪些其他服务等等; networks:是应用的网络,在它下面可以定义应用的名字、使用的网络类型等等; volumes:是数据卷,在它下面可以定义的数据卷(名字等等),然后挂载到不同的服务下去使用; 二、Services 先创建一个文件夹beck-docker,并在里面新建docker-compose.yml文件,然后使用version指定一下compose使用的版本号。 定义服务 在应用里需要定义的服务,可以放到services下面。比如,我们去定义一个dog的服务,使用nginx镜像,指定主机上的8080端口映射到容器中得80端口,也就是nginx的http的访问端口。 version:'2' services: dog: image:nginx ports: -"8080:80" 以同样的方式,定义一个cat的服务,同样使用nginx镜像,然后指8081端口对应80端口。 version:'2' services: dog: image:nginx ports: -"8080:80" cat: image:nginx ports: -"8081:80" 需要注意的是,cat与dog要在同一个级别,还有ports是个数组,可以指定多个端口映射关系。 启动服务 定义好服务以后,在项目的目录启动这些服务,可以执行: docker-composeup 这样会启动,在compose文件下定义的所有服务。由于这是第一次启动这个服务,所以可以看到它是creating,也就是去创建相关的东西。首先会创建这个服务使用的网络,这里是叫做「beckdocker_default」的网络,然后是dog和cat的服务,这些网络和服务的名字,默认会加上一个前缀,由于在创建应用的时候没有指定名字,所以会默认使用项目目录的名字,后面还有一个数字的后缀。最后会有一个「Attaching to …」,将网络应用到服务上。 启动成功后,在浏览器访问一下。8080对应的是dog的服务,8081是cat的服务。 回到终端,可以看到服务的访问日志,日志的开头会有服务的名字,标志着日志是从哪个服务来的: 如果希望服务在后台运行,可以使用-d选项(也就是detach): docker-composeup-d 服务的生命周期 查看正在运行的服务 docker-composeps 停止一个服务 docker-composestop[服务名] 如果后面不加服务名,会停止所有的服务。 启动某一个服务 docker-composestart[服务名] 如果后面不加服务名,会启动所有的服务。 查看服务运行的log docker-composelogs-f 加上-f选项,可以持续跟中服务产生的log。 进入服务容器中 docker-composeexecdogbash 删除服务 docker-composerm 注意这个docker-compose rm不会删除应用的网络和数据卷。查看一下网络,可以看到应用创建的网络「beckdocker_default」,如果要删除所有的这些,可以使用: docker-composedown 会提示我们删除网络 beckdocker_default。 三、Networks 网络决定了服务之间以及服务和外界之间如何去通信,在执行docker-compose up的时候,docker会默认创建一个默认的网络,创建的服务也会默认地属于这个默认网络。服务和服务之间,可以使用服务的名字进行通信。也可以自己创建网络,并将服务属于到这个网络之中,这样服务之间可以相互通信,而外界就不能够与这个网络中的服务通信,可以保持隔离性。 下面登录dog服务去连接cat服务,登录到cat服务连接dog服务: 可以通过服务的名称进行连接。 自定义网络 1、在networks中先定义一个名为animal,类型为bridge的网络: version:'2' services: dog: image:nginx ports: -"8080:80" cat: image:nginx ports: -"8081:80" networks: animal: driver:bridge 2、让dog和cat服务使用这个网络: **version:'2' services: dog: image:nginx ports: -"8080:80" networks: -"animal" cat: image:nginx ports: -"8081:80" networks: -"animal" networks: animal: driver:bridge 3、再增加一个叫pig的服务,使用默认网络,来体现于自定义网络的隔离性: version:'2' services: dog: image:nginx ports: -"8080:80" networks: -"animal" cat: image:nginx ports: -"8081:80" networks: -"animal" pig: image:nginx ports: -"8082:80" networks: -"default" networks: animal: driver:bridge 4、重新启动应用 5、登录cat服务,尝试去连接dog服务和pig服务: 因为cat与dog同在animal网络,所以可以通过名字连接,而pig在default网络中,所以不能。 四、Volumes 在compose文件中,还可以指定一些有名字的数据卷,让服务去使用。方法是:在与networks同级的地方,添加volumes,接着是数据卷的名字,下面使用driver去指定数据卷的类型。 定义好数据卷后,就将这个数据卷交给一个服务去使用。可以用volumes给服务指定需要使用的数据卷: dog: ... volumes: -nest:/mnt 以dog服务为例,volumes下指定使用的数据卷,冒号左边是数据卷名称,冒号右边是挂载到的docker对应目录位置。接着给cat服务也添加同样的数据卷。 回到终端,执行docker-compose up -d,下面测试一下数据卷: 因为cat与dog服务都使用nest的数据卷,所以在dog中/mnt目录下创建的data1,在cat服务的/mnt目录下可以看到。 指定位置的数据卷 dog和cat都是一个web服务,现在我想将主机的某一个位置当做是服务的一个内容,那么我们可以去创一个指定位置的数据卷。首先可以在当前目录,创建./app/web文件夹,在里面创建个index.html。 编辑内容: 内容编辑好后,就给dog与cat服务指定数据卷,冒号左边是主机上的目录,冒号右边是服务内挂载的目录: 说明:/usr/share/nginx/html 目录是nginx默认主机的根目录,也就是nginx欢迎界面的目录。 本文转自 dengaosky 51CTO博客,原文链接:http://blog.51cto.com/dengaosky/1854570,如需转载请自行联系原作者

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

【SIP协议】学习初学笔记

1.SIP这玩意是怎么走来和如何构建的? 通俗的说,SIP就是一个轻量级信令协议,它可以作为音频、视频、及时信息的信令。 说到SIP是怎么出来的就要提H.323,而提到这个标准由不得不提到ITU-T,我们就先说说指定SIP的IETF(Internet Engineering Task Force)和制定H.323的ITU-T(International Telecommunications Union–Telecommunications Standard Sector)之间一些小趣事吧。ITU-T和IETF想事儿总是不一样的,它们俩往往从两个不同的角度来进行。ITU-T作为一个隶属于美国的国际标准化组织,传承了美国政策的一致性和试图完成维护世界和平的角色,所以它制定出来的标准一定是经过无数轮的反复和草案,花了N年制定出一个最终的,广为接受的结果。而恰恰相反,IETF则更趋近于实用主义,信奉“rough consensus and running code”,也就是说能用进行,边用边补充呗。因此在大多数时候,IETF标准制定的周期要比ITU-T短一些,这可能也归因于IETF每年举办三次开放性论坛。这些春季、夏季、秋季会议会安排在世界各地,并且向各个对此感性趣的组织开放(去瞅一瞅吧:http://www.ietf.org/meetings/meetings.html )多个IETF工作组在这些会议上相聚,针对他们现在的系统开发敲定一些技术细节,对于要是到了会议结束时还是没有解决的问题那就几个月后的下次开会继续研究呗。简而言之,IETF以一种实际实用的角度去完善体系架构和协议设计。 说了这么多可能你还没有意识到我在扯这些是为了什么,但是请记住这些正是SIP(Session Initiation Protocol)架构所体现的核心思想——先用着,再扩展。SIP的结构是建立于两个常用协议之上的:在RFC 2821中的SMTP 协议(Simple Mail Transfer Protocol )——它定义了电子邮件的消息格式,以及定义在RFC 2616的HTTP协议 (Hypertext Transfer Protocol )——它定义了基于Web的多媒体通信消息。另外,SIP又使用了定义在RFC 3550中的RTP/RTCP协议(Real Time Transport Protocol/Real Time Control Protocol )——它定义了在IP网上的多媒体包格式,还使用了定义在RFC 2327的SDP协议(Session Description Protocol )——它定义了一个多媒体会话的参数和特征。因此,SIP是建立在其他IETF提出的协议之上的,这有点像H.323建立在诸如H.225.0和H.245等ITU-T制定的协议之上,它的两个比较基础的RFC分别是版本1.0 RFC2543和版本2.0 RFC3261。当然,SIP还运行于其他IETF定义的传输协议之上,比如TCP(Transport Control Protocol ), UDP(User Datagram Protocol ) 和IP (Internet Protocol )等。这样,这么多著名的,并且被广泛应用的协议为SIP提供了超于H.323的简单明了的特性。 在网上看到了这样三个MindMap,觉得很能表达SIP的基本核心思想: 关于SIP的架构,我们一定要知道这玩意不是什么新鲜玩意,你看看它基于什么就知道了,这么个拼出来的东东架构能崭新到什么地步呢?我的粗浅理解是SIP的主要架构其实就是一个典型的C-S架构:一个Client客户端在RFC3261中定义为一个发送SIP请求并接收SIP回应的网络元素,这个Client可能与也可能不与人进行交互。对应的,一个Server服务器是接受SIP请求并且给予其回应的网络元素。比如最典型的是一个SIP请求INVITE,邀请一个用户或者服务器参与会话,若得到的是肯定的响应的话,那么则会返回响应SUCCESS。要是再深入一点,我们可以将这样一个简单的分类进行细分: Client分为两类: 用户代理客户端User Agent Client :它是一个逻辑功能,它创建请求、并且使用这个功能实体的一些具体功能发送出请求。 代理Proxy :中文翻译过来还是代理,但是这个与上边的Agent不一样,它是一个中间设备,既作为Client,也作为Server ,可以解释、翻译、改写一个请求,并将请求转发给其他的服务器,完成路由功能。有时候有状态和无状态Proxy,所谓有状态就是Proxy根据不同的情形作出不同的处理,这些处理具有前后的相关性,比如三个人传数字,A要通过B给C传一个数字,一种情况是不管A说什么,B都说同一数字给C,这叫做无状态Proxy;另一种状态是A说1的话,B就传给C数字2,要是A说2的话,B就传给C数字3,这样就是一个有状态的Proxy。有些资料上有所为B2BUA,实质与Proxy很相似,只不过更加灵活。 Server分类三类: 用户代理服务器User Agent Server: 它是一个逻辑功能,它对一个请求产生应答。 重定向服务器Redirect Server: 一个将客户端的请求重定向去联系另一个服务器以完成请求的服务器。 注册服务器Registrar :一个接受REGISTER 注册请求,并将信息放置于位置服务器的服务器。 注意:我们在书上常常看到的UA是一个概括的说法,之所以区分UAS和UAC只是从逻辑上区分,实质上不一定是独立物理实体。 2.SIP该在哪,能干啥? 我们学习SIP就要知道它的地位,有个宏观的了解才能知道N多协议之间的关系: 既然根据RFC 3261,SIP是基于STMP和HTTP的,并且底层使用了IP、UDP和TCP,那么它就是一个应用层协议,也就是说,它能为End User提供服务,你能看得见摸得着。描述SIP应用服务的单位是会话,也就是英文中Session一词,意为在两个或多个参与者之间有顺序的交换信息,更深入一点,SIP必须先去扮演建立会话的角色,然后再在通信中管理会话。大家更关注的有三点: a.多于两个的参与者就意味着呼叫可能是多点的,而不仅仅是点对点的那样子。 b.End User可能总不是从相同的地点发起呼叫的,我们需要添加追踪这些End User的功能。 c.End User可能会使用文字、音频、视频等的混合媒体类型,这些在网路中对网络的带宽、最大传输延时等都有不同的要求和限制。SIP还需要对此进行有效处理。 针对以上的Concerns,RFC 3261主要定义了五个方面的SIP多媒体会话管理能力: · 用户位置管理:决定哪一个端系统用于这次通信。 · 用户可用性:决定被叫端是不是愿意参与这次通信。 · 用户容量:决定用于这次通信的媒体以及其参数。 · 会话建立:在被叫和主叫两端建立会话参数。 · 会话管理: 包含转接和终止会话、修改会话参数、调用会话业务。 3. SIP依靠怎么运作? 既然SIP是建立在SMTP和HTTP上的,那么其消息格式也有巨大的相似度,但是注意到一个SIP会话的资源是通信资源,而不是页面或者网页资源,这是与HTTP不同的地方。一个身份或者叫做一个寻址体制必须在请求/响应集有效建立之前建立。身份标识就是所谓的SIP URI(SIP Uniform Resource Indicator),其中包含了充足的信息来初始化一个会话。使用这个标识的资源的例子(RFC 3261中提供的)有:有在线业务的用户、在一个消息系统中的一个邮箱,在一个组织中的一组逻辑用户(例如销售部门),一个PSTN电话号码等等。SIP URI与电子邮件地址类似,这也是借用了SMTP协议中的规定:典型的包含两部分,第一部分为用户名,第二部分为主机名,sip:huangpc@bupt.cn, 这是RFC 2543所介绍的最通常的格式。 当然SIP URI还有其他的一些格式,比如在RFC 3261中引入的安全SIP URI:sips:huangpc@bupt.cn, 这个是在TCP上的TLS作为安全传输层的一种方式。 定义了用户标识后,我们就可以定义请求的标识了——SIP中称为方法(Method)。其他的扩展方法在后续的RFC中都有定义。 · REGISTER: 用于与SIP服务器进行注册。 · INVITE: 用于表明用户或者服务器被邀请参与这个会话。这个消息体中将包含一个对被叫端的会话描述。 · ACK: 仅用了INVITE请求,表明收到请求。 · CANCEL: 用于取消一个pending 的请求。 · BYE: User Agent Client用户代理客户端发送,来告诉服务器它希望结束通话。 · OPTIONS: 向服务器查询它的能力。 定义完请求,很自然我们需要回应的语言规范:包含状态码和描述性短语。分为六类: · 1xx: 暂时性回应,表明已经接收到,正在处理之中。 · 2xx: 成功回应,表明动作已经被接收,理解并且接受了。 · 3xx: 重定向回应,需要进一步的动作来处理处理这个请求。 · 4xx: 客户端错误回应,请求中语法不对,不能被服务器接受。 · 5xx: 服务器错误回应,服务器不能处理这个有效的请求。 · 6xx: 全局错误回应,这个请求不能被任何服务器接受。 你现在可能比较纳闷,这都是些关于SIP会话建立和拆除的部分,但关于这个会话中要传的文字、音视频等的格式等双方是怎么知道的呢?在INVITE中,就带有了这些信息,这个信息的格式则又引出了另一个RFC,RFC 2327,会话描述协议(Session Description Protocol (SDP))。 SIP和其他协议一样都有这样的一个要求:在会话开头时两端要有充分的信息交流。使用的两个协议就是定义在RFC 2974中的SAP(Session Announcement Protocol )和定义在RFC 2327的SDP (Session Description Protocol)。简单来说,SAP提供了一种定期宣传多媒体会话,向有意参与会话者传递相关会话信息的机制。使用它来支持Mbone(Internet Multicast Backbone),因此关兴趣的各方都会清楚的指导目前正在进行的一些会话。而SDP则定义了描述一个通信会话的格式,同样的,它也可以用于不同的传输协议,比如SAP、SIP、HTTP或其他等传输协议。学习时要注意SDP的载体是SIP。RFC 2327专门注明了一些SDP能提供的比较关键的信息: 会话名和目的。 会话激活的时间。 构成会话的媒体。 怎么样接收这些媒体(地址、端口号、格式等) 而另一些信息则是可选附带的,例如会议使用的带宽,负责这个会话的那个人的联系方式等等。 说到这些你可能觉得很抽象,我们赶紧那个例子RFC 2327中的例子来看看: v=0 o=mhandley 2890844526 2890842807 IN IP4 126.16.64.4 s=SDP Seminar i=A Seminar on the session description protocol u=http://www.cs.ucl.ac.uk/staff/M.Handley/sdp.03.ps e=mjh@isi.edu (Mark Handley) c=IN IP4 224.2.17.12/127 t=2873397496 2873404696 a=recvonly m=audio 49170 RTP/AVP 0 m=video 51372 RTP/AVP 31 m=application 32416 udp wb a=orient:portrait 我们看到SDP格式包含多行文本,都是以 = 的格式书写的,RFC中的星号*指的是选择项。我们主要有三类的会话描述:会话描述、时间描述、媒体描述,具体你可以参看RFC 2327。注意这个例子中,两个m开头的行,定义了音视频的概要,这些概要是在RFC 3550 Real Time Protocol (RTP)中的第13节和RFC 3551 RTP Profile for Audio and Video Conferences with Minimal Control 中的第6节,在编码最后的那个0和31,这是在后续RTP帧中要使用的负载类型值,用来确定媒体和编码类型。49170和51372都是接收者的端口,发送者端口分别加1,也就是说在这个例子中49171和51373是发送者的端口。 4.SIP到底怎么运作? 一个最简单的例子是在SIP呼叫建立两个直接相连的端对端的通话过程。发起者会发起一个INVITE消息给对端来发起会话,接着会收到Ringing和OK消息。被叫端返回ACK表明连接完成,可以进行信息交流了。当不需要这个连接时,任何一端发送BYE消息给对端,对端返回OK来终止呼叫。 注意,SIP消息和具体的媒体流并不是在一个层面运作的。例如,一个VoIP电话是先通过SIP信令完成交互后再开始具体媒体流的传输的,如下图,SIP的根本作用的完成点对点(或多点)的媒体流传输的前序工作。 在RFC 3261中描述了一个比较复杂的例子:使用了代理服务器作为通信通路。SIP代理服务器代表其他的Client发起请求,并且在许多时候作为路由模式,将SIP请求转发给另一个距离最终目的地(也就是被叫端)较近的设备。因此,SIP代理服务器扮演着两个角色——在接收请求时是server角色,在发送请求时是client角色。注意,代理服务器必须可以解释一个SIP消息,并且需要的时候转发这条消息前对其进行重写,大的网络中可能有多个代理服务器。在RFC3261中的第四节中有个比较有趣的例子,描述了两个SIP终端通过两个代理服务器建立呼叫的过程。在这个例子中,两个终端位于两个不同的城市:Atlanta and Biloxi,因此是在两个相互隔离的网络中。每个网络有它自己的代理服务器,分别称为atlanta.com 和 biloxi.com。 若在Atlanta的Alice想呼叫在Biloxi的Bob,那么Alice的电话就会发送以下的INVITE消息给它的代理服务器atlanta.com: Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds Max-Forwards: 70 To: Bob From: Alice ;tag=1928301774 Call-ID: a84b4c76e66710@pc33.atlanta.com CSeq: 314159 INVITE Contact: Content-Type: application/sdp Content-Length: 142 当这个消息通过网络转到Bob后Bob要是愿意接受这个呼叫那么它就会返回一个OK,这个消息会先到biloxi.com 代理: SIP/2.0 200 OK Via: SIP/2.0/UDP server10.biloxi.com ;branch=z9hG4bKnashds8;received=192.0.2.3 Via: SIP/2.0/UDP bigbox3.site3.atlanta.com ;branch=z9hG4bK77ef4c2312983.1;received=192.0.2.2 Via: SIP/2.0/UDP pc33.atlanta.com ;branch=z9hG4bK776asdhds ;received=192.0.2.1 To: Bob ;tag=a6c85cf From: Alice ;tag=1928301774 Call-ID: a84b4c76e66710@pc33.atlanta.com CSeq: 314159 INVITE Contact: Content-Type: application/sdp Content-Length: 131 我们注意到有相同的Call-ID来保证这个会话的单一性。更多的细节参看RFC 3261里的这个例子的具体解释。 5.SIP中的信令和媒体之间的关系: SIP等于为媒体的建立进行实现的沟通,打个比喻,只有你知道你要说话的那个人在那,并且两个人都要找到彼此畅通的语言,这样才能更有效的沟通。 而真正开始两人滔滔不绝的倾心交谈了,就与前边这些对话前的相互了解和基本沟通没有关系了。 6.几个重要的概念: 呼叫(call): 呼叫是一个非正式的术语,用来表示一个多媒体会话,用Call-ID来标识;不论两方通话还是在多方通话中,在每个UA中是使用同一个Call-ID; 事务(transaction): 请求(UAC)+最终响应(相邻的UAS),SIP基于事务。所谓相邻就是说transaction存在于相邻的SIP实体,而不是存在于两个UA之间。CSeq标识。一个事务中包含一个请求消息、0个或多个临时响应消息、1个或多个最终响应消息(2xx~6xx)。SIP是事务性的协议。事务的区分通过Via字段栈顶的Branch的值来确定,这是由于对于请求消息每经过一个有事务状态的Proxy的时候,该Proxy需要为这个事务创建一个服务器端事务和一个客户端事务,并且将自己的URI添加到Via的栈顶,并生成一个Global ID做为Branch的值,以此值来表示一个与之相对应的事务。SIP在事务层面定义了状态机和定时器来实现重传。 下图是一个回复200 OK的成功的INVITE事务:是不是INVITE事务区别在于 UAC需要为每个INVITE最终请求(2xx~6xx)生成ACK响应,而其他的请求消息(INFO,OPTION,etc)则不必如此。因为INVITE的地位比较重要, 所以需要这样一个三次握手的机制来保证会话的双方都能够确保事务的完整性,这一点和TCP连接建立的三次握手比较像。 注意在上图这两个UA中,每一个代理服务器都将自己的地址加入返回的ACK的Via头域中,而非成功的transaction则不会加入,见RFC 3261 (p.24)。CSeq头域的值必须与INVITE相同,并且CSeq的方法必须是ACK。中间响应消息 1xx 的使用则是为了节省网络开销设计的,一旦 UC 收到任何一个中间响应消息,则 UC 必须停止消息重发定时器,不再从发这个请求消息,反之则直到收到最终响应消息或重发定时器超时。一旦客户端UAC的事务在Calling状态收到任何中间响应消息1xx,事务则自动切换到Processing状态,停止请求消息的重发。并且需要将中间响应消息传送给TU事务用户。在呼叫业务中,TU以及上层应用可以根据中间响应消息在用户界面上提示用户。一旦事务切换到Processing状态,任何其他中间响应消息也都要传送给TU。 而非INVITE事务则如下: 当UAC发出非INVITE请求时,它就会在事务管理子层上开启定时器F(TCP)或者是E(UDP),确保超时的时候进行重传。这适用于除了 ACK请求外的其他非INVITE请求。每次超时重传时E的时间都被翻倍,直到最大的4秒。而F超时时,UAC就会认为是Timeout,这个事务将被删除。 对话(dialog/leg): 代表着两个SIP UA之间持续一段时间的端到端的联系(如:一段通话)。也就说仅仅存在于端到端的信令关系。当一个UAS发出对于INVITE(或者REFER)的非失败最终响应<=>200OK(BYE),则Dialog建立,同时这也是session的开始。UA和SIP代理服务器之间不会有对话。在SIP中呼叫中包含一个或多个Dialog(这仅仅存在于多方通话中)。Dialog终结于任意一端发出 BYE。Early Dialog可以通过UAC发出的CANCEL进行终结,更确切的说,所有早期对话在接收到非2XX最终响应时就被终结了。 Call-ID-value、To、From进行标识。Forking时体现明显。 在这个Forking的例子中,这个用户注册了三个设备,在用户被呼叫时,INVITE的Contact头域就被转换为三个INVITE发往三个设备。后边的q指的是优先级,q越小,优先级越高。其中的SIP注册服务器相当于一个Forking代理,尽管这个实体接收到两个ACK,但是除了这些ACK外,它与主叫方的信令交互都是属于一个transaction的,而与被叫方则分别建立了Transaction。另外,被叫方收到的两个ACK由分别建立了Transaction。注意Device3返回了488这样的非成功响应,SIP注册服务器(Forking代理服务器)没有将该响应发回主叫方,这是SIP代理一个重要的特征,SIP代理还能自行发出Request:CANCEL消息。 UAS对话层接收到一个新的对话请求INVITE消息后,在建立会话的响应消息2xx中,将请求消息里面的所有Route-Record字段拷贝到2xx消息中,并且UAS的对话层必须添加一个Contact字段使得对话中后续的响应(INVITE在2xx响应的情况下也包括ACK消息)、请求消息可以直接和本UA联系。当UAC收到UAS的INVITE的2xx响应消息后,如果2xx中不包含任何Route-Record字段的,则UAC可以选择直接发送ACK到Contact中地址&端口。 会话(session): 多方用户的媒体关系,在对话的控制下建立。 下图是Early dialog、Session、Dialog、Transaction等的在一个UA-UA的呼叫中的体现: 在这个例子中,通过INVITE事务而成功建立起来的dialog必须有一个ACK进行回应,这是第二个transaction的开始,尽管ACK并没有回复,但是由于新的 branch-value被填入,所以这个ACK代表了一个新的Transaction的开始。注意,此时 transaction number (CSeq) 并没有根据INVITE而增加--也就是说若收到的最终响应不是2XX(是3XX--6XX),则该transaction中包含ACK,若最终响应是2XX,则ACK属于一个新的transaction(此处存疑,国外有资料将其视为一个新的transaction,但是RFC3261中的意思却是ACK不属于INVITE Transaction,也不创建新的Transaction,但会重新计算Transaction参数--branchID)。早期对话是UAS以一个1XX响应作为回应时建立的。这样做的好处是在UAC可能在早期对话中发出诸如UPDATE这样的SIP请求。 7.在线状态(Presence) 有人译为“呈现”,个人觉得译为在线状态比较贴切,这是一种激动人心的SIP应用,它使您能够确定用户位置,并判断是否能够通过电话、电子邮件/文本或视频与其进行通信。人员和应用都可以利用状态信息,从而使企业有机会将通信整合到业务流程之中。IETF指定了许许多多的SIP扩展来支持在线状态这个功能,我们列举如下: · RFC 2778: A Model for Presence and Instant Messaging · RFC 2779: Instant Messaging/Presence Protocol Requirements · RFC 3261 SIP: Session Initiation Protocol · RFC 3856: A Presence Event Package for the Session Initiation Protocol · RFC 3859: Common Profile for Presence 主要的组成有: Presence Agent(PA):PA为SIP使用者的代理人,能够接收和处理Presence的消息。它也能够回应和重新整理其它的消息(如公开的消息或SIP以外的任何消息)。当一个用户改变其状态时,它还能给订阅者发送通知。其可以与 SIP proxy server放在一起实现,也可以作为一个独立实体存在。 Presence User Agent (PUA) :查询更新PA。 8.全网看SIP 在非IMS网络中,拓扑结构如下: 在这个结构中,有三个主要的部分: 公网与业务定制者节点:这是PSTN网络以及在用户层面的设备。 DMZ区域:对接外网的一些网络元素,用于安全方面。 核心网:网络消息处理的核心区域。 需要的注意是: 1.在核心网部分的媒体服务器有时候也可以扮演UA的角色,比如你定制语音留言这个业务,那么这个媒体服务器就负责播放提示音和录音。网关在某个层面上也是扮演了UA的角色。 2.IP PBX是一种B2BUA,另外,SBC也是一种B2BUA,负责隐藏内网拓扑结构。应用服务器也是一种B2BUA,供修改业务参数等操作使用。 9.NAT问题 下图所示SIP可能会出现的NAT问题: 目前商用的方法是使用Session Border Controller (SBC),也就是说在应用层提供NAT服务,SBC监听SIP请求,当得到一个请求时,它不仅检查IP头以便路由这个包,它也查看SIP消息内部的contract地址,并且在将其路由到下一跳之前将该地址改为一个可路由的地址,这个可路由的地址不一定是公网地址,只要下一个节点可以路由即可,如下图所示: 本文转自gnuhpc博客园博客,原文链接:http://www.cnblogs.com/gnuhpc/archive/2012/01/16/2323637.html,如需转载请自行联系原作者

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

Android笔记:Fragment相关问题

这两天在使用Fragment做播放器里的播放列表和歌词显示两个界面的替换与更新时发现了很多问题,在此记录下问题及解决方法: 1.多个Fragment在replace后(并且都加入了后退栈ft.addToBackStack(null)),通过点击按钮事件移除顶层的fragment(使用remove方法),返回后的fragment的oncreatview方法有执行,但是页面仍然没法自行更新数据,页面空白,UI控件都消失了。 解决:不用remove方法,改用通过popBackStack()方法直接将栈顶的fragment弹出,然后直接恢复到要返回的那个fragment。 1 getSupportFragmentManager().popBackStack(); 2.使用popBackStack()方法后,页面控件恢复了,但是数据并没有同步更新。 解决:这个问题困扰了很久,后来讲replace方法改成了add方法,并且在add之前将原先的fragment隐藏掉hide。这样在点击按钮收回播放列表的fragment后,返回的歌词fragment的显示进度是同步的了。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // 打开播放列表 private void btnClick_playinglist() { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); Fragment fragment = new PlayingListFragment(); if (isOpenPlayingList) //播放类表是否已打开 { getSupportFragmentManager().popBackStack(); mPlaying_img_openlist.setImageResource(R.drawable.icon_playing_img_openlist); isOpenPlayingList = false ; } else { ft.hide(mFragment); ft.add(R.id.playing_fragment_layout, fragment); ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN); ft.addToBackStack( null ); mFragment = fragment; mPlaying_img_openlist.setImageResource(R.drawable.icon_playing_img_openlist_press); isOpenPlayingList = true ; } ft.commit(); } 3.通过按钮点击可以正常弹出顶层的播放列表fragment了,同时歌词界面的fragment仍然同步更新。但是用按钮点击打开播放列表fragment,然后用back键返回,第一次正常,多次后歌词fragment就开始变成空白。将fragment的背景颜色修改成红色,异常界面就是红色。由此可见,通过back键返回的fragment仍然没有恢复和更新。 解决:这个不清楚具体原因,应该是使用back返回键和通过调用popBackStack()方法来移除fragment的机制不一样所导致的。这个找不到具体的解决办法,只能先采用规避方法,通过重写back监听方法,进而调用popBackStack()解决了这个问题。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 //重写监听back键按钮 @Override public void onBackPressed() { getSupportFragmentManager().popBackStack(); if (isOpenPlayingList) //判断播放列表是否打开 { mPlaying_img_openlist.setImageResource(R.drawable.icon_playing_img_openlist); isOpenPlayingList = false ; } else { super .onBackPressed(); } } 本文转自 glblong 51CTO博客,原文链接:http://blog.51cto.com/glblong/1252393,如需转载请自行联系原作者

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

Appium命令笔记之一

查看APK包名与其他信息命令: aapt l <你的apk文件>,这个命令就是查看apk内容 下面详细说下 aapt dump 这个查询命令 基本格式为 aapt dump [] <apk文件> 这里[ ]选择可以有以下几种: badging Print the label and icon for the app declared in APK permissions Print the permissions from the APK. resources Print the resource table from the APK. configurations Print the configurations in the APK. xmltree Print the compiled xmls in the given assets. xmlstrings Print the strings of the given compiled xml assets. 例如: C:\Users\lw>aapt d badging Desktop\zhihu.apk |findstr "package launchable-activity" package: name='com.zhihu.android' versionCode='507' versionName='4.54.1' platformBuildVersionName='7.1.1' launchable-activity: name='com.zhihu.android.app.ui.activity.MainActivity' label='鐭ヤ箮' icon='' //启动另外一个APP public void startapp() { //启动该apt driver.startActivity("com.zhihu.android","'com.zhihu.android.app.ui.activity.MainActivity"); } 使用场景: 1、用例之前的切换 2、场景切换使用 本文转自 知止内明 51CTO博客,原文链接:http://blog.51cto.com/357712148/1957817,如需转载请自行联系原作者

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

ElasticSearch API for JAVA 学习笔记

Client Client是一个类,通过这个类可以实现对ES集群的各种操作:Index, Get, Delete , Search,以及对ES集群的管理任务。 Client的构造需要基于TransportClient TransportClient TransportClient可以远程连接ES集群,通过一个传输模块,但是它不真正的连接到集群,只是获取集群的一个或多个初始传输地址,在每次请求动作时,才真正连接到ES集群。 Settings Settings类主要是在启动Client之前,配置一些属性参数,主要配置集群名称cluster.name,还有其他参数: client.transport.sniff 是否为传输client添加嗅探功能 client.transport.ignore_cluster_name 设为true,忽略连接节点的集群名称验证 client.transport.ping_timeout 设置ping节点时的时间限,默认5s client.transport.nodes_sampler_interval 设置sample/ping nodes listed 间隔时间,默认5s 1 2 3 4 5 6 7 8 9 10 11 12 13 //通过Settings类设置属性参数 Settingssettings=Settings.settingsBuilder().put( "cluster.name" , "index-name" ).build(); //启动Client Clientclient=TransportClient.builder().settings(settings).build(). addTransportAddress( new InetSocketTransportAddress(InetAddress.getByName( "192.168.xxx.xxx" ), 9300 )); //如果不需要设置参数,直接如下 /*Clientclient=TransportClient.builder().build(). addTransportAddress(newInetSocketTransportAddress(InetAddress.getByName("192.168.xxx.xxx"),9300));*/ //关闭Clinet client.close(); Document API 主要分为以下类:Index API , Get API , Delete API , Update API, Multi Get API, Bulk API es中的增删改查 Index API可以索引一个典型的JSON文档到指定的索引中,并且可以使它可以检索。 产生JSON JSON产生可以有以下几种方式: 手动拼接一个JSON字符串 使用Map 使用第三方库,比如Jackson 使用内置的XContentFactory.jsonBuilder() 每种类型都会转换为byte[],因此如果对象已经是这种形式,可以直接使用,jsonBuilder是一个高度优化了的JSON产生器,它直接构造byte[] 通过下边的代码讲解四种方法:index-api, get-api, delete-api, update-api 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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 /** *es-api的方法学习: *1.prepareIndex方法:索引数据到ElasticSearch *2.prepareGet方法:获取信息 *3.prepareDelete方法:删除信息 *4.update方法:更新信息 *4.1upsert:在使用update方法时: *a:针对文档不存在的情况时,做出index数据的操作,update无效; *b:如果文档存在,那么index数据操作无效,update有效; */ public static void main(String[]args) throws IOException,InterruptedException,ExecutionException{ //通过Settings类设置属性参数 Settingssettings=Settings.settingsBuilder().put( "cluster.name" , "myApp" ).build(); //启动Client Clientclient= null ; try { client=TransportClient.builder().settings(settings).build(). addTransportAddress( new InetSocketTransportAddress(InetAddress.getByName( "101.200.124.27" ), 9300 )); } catch (UnknownHostExceptione){ e.printStackTrace(); } //执行操作 SimpleDateFormatdf= new SimpleDateFormat( "yyyy-MM-dd" ); XContentBuilderjsonBuilder=XContentFactory.jsonBuilder() .startObject() .field( "user" , "yuchen" ) .field( "interest" , "readingbook" ) .field( "insert_time" ,df.format( new Date())) .endObject(); //1.prepareIndex方法:索引数据到ElasticSearch IndexResponseresponse=client.prepareIndex( "index-test" , "weibo" , "4" ) .setSource(jsonBuilder) .get(); String_index=response.getIndex(); String_type=response.getType(); String_id=response.getId(); long _version=response.getVersion(); boolean created=response.isCreated(); System.out.println(_index+ "" +_type+ "" +_id+ "" +_version+ "" +created); //2.prepareGet方法:获取信息 GetResponsegetResponse=client.prepareGet( "index-test" , "weibo" , "1" ).get(); System.out.println(getResponse.getSourceAsString()); //3.prepareDelete方法:删除信息 DeleteResponsedeleteResponse=client.prepareDelete( "index-test" , "weibo" , "4" ).get(); System.out.println(deleteResponse.isFound()); //4.update方法:更新信息 UpdateRequestupdateRequest= new UpdateRequest(); updateRequest.index( "index-test" ); updateRequest.type( "weibo" ); updateRequest.id( "1" ); updateRequest.doc(XContentFactory.jsonBuilder().startObject().field( "interest" , "music" ).endObject()); UpdateResponseupdateResponse=client.update(updateRequest).get(); System.out.println(updateResponse.isCreated()); //update方法:可以为已有的文档添加新的字段 UpdateResponseupdateResponse2=client.prepareUpdate( "index-test" , "weibo" , "1" ) .setDoc(XContentFactory.jsonBuilder() .startObject() .field( "interest2" , "reading" ) .endObject()).get(); System.out.println(updateResponse2.isCreated()); //4.1upsert:在使用update方法时,a:针对文档不存在的情况时,做出index数据的操作,update无效; //b:如果文档存在,那么index数据操作无效,update有效; //先构建一个IndexRequest IndexRequestindexRequest= new IndexRequest( "index-test" , "weibo" , "14" ); indexRequest.source(XContentFactory.jsonBuilder() .startObject() .field( "user" , "yuchen2" ) .field( "interest" , "eating" ) .field( "insert_time" ,df.format( new Date())) .endObject()); //再构建一个UpdateRequest,并用IndexRequest关联 UpdateRequestupdateRequest3= new UpdateRequest( "index-test" , "weibo" , "14" ); updateRequest3.doc(XContentFactory.jsonBuilder() .startObject() .field( "interest2" , "love" ) .endObject() ).upsert(indexRequest); client.update(updateRequest3).get(); if (client!= null ){ client.close(); } } 批量操作 Multi Get Api 和 Bulk Api可进行批量的增删改查 使用Multi Get Api 批量获取: 1 2 3 4 5 6 7 8 9 10 //1.Muti-getApi //可以指定单个id,也在index,type下指定一个id-list;也可以指定别的index/type MultiGetResponsemultiGetResponse=client.prepareMultiGet() .add( "index-test" , "weibo" , "1" ) //指定单个id .add( "index-test" , "weibo" , "11" , "13" , "14" ) //指定一个id-list .add( "index-other" , "news" , "1" , "3" ).get(); //指定别的index/type for (MultiGetItemResponseitem:multiGetResponse){ GetResponseresponse=item.getResponse(); System.out.println(response.getSourceAsString()); } Bulk Api批量增加: 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 //2.BulkApi:可以进行批量index和批量删除操作 //2.1批量增加 BulkRequestBuilderbulkRequest=client.prepareBulk(); bulkRequest.add(client.prepareIndex( "index-test" , "weibo" , "20" ) .setSource(XContentFactory.jsonBuilder() .startObject() .field( "user" , "yuchen20" ) .field( "postDate" , new Date()) .field( "message" , "tryingoutElasticsearch" ) .endObject() ) ); bulkRequest.add(client.prepareIndex( "index-test" , "weibo" , "21" ) .setSource(XContentFactory.jsonBuilder() .startObject() .field( "user" , "yuchen21" ) .field( "postDate" , new Date()) .field( "message" , "tryingoutElasticsearch" ) .endObject() ) ); BulkResponsebulkResponse=bulkRequest.get(); if (bulkResponse.hasFailures()){ //... } Bulk Api批量删除: 1 2 3 4 5 6 7 8 9 10 11 //2.2批量删除 BulkRequestBuilderbulkRequest=client.prepareBulk(); bulkRequest.add(client.prepareDelete( "index-test" , "weibo" , "20" ) ); bulkRequest.add(client.prepareDelete( "index-test" , "weibo" , "21" ) ); BulkResponsebulkResponse=bulkRequest.get(); if (bulkResponse.hasFailures()){ System.out.println( "bulkerror:" +bulkResponse.buildFailureMessage()); } Bulk Api 批量更新 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 //2.3批量更新 BulkRequestBuilderbulkRequest=client.prepareBulk(); bulkRequest.add(client.prepareUpdate( "index-test" , "weibo" , "11" ).setDoc(XContentFactory .jsonBuilder().startObject() .field( "country" , "China" ) //新添加字段 .endObject() ) ); bulkRequest.add(client.prepareUpdate( "index-test" , "weibo" , "13" ).setDoc(XContentFactory .jsonBuilder().startObject() .field( "user" , "yuchen13" ) //更新字段 .endObject() ) ); BulkResponsebulkResponse=bulkRequest.get(); if (bulkResponse.hasFailures()){ System.out.println( "bulkerror:" +bulkResponse.buildFailureMessage()); } BulkProcessor设置批量请求的属性 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 32 33 34 35 36 //BulkProcessor BulkProcessorbulkProcessor=BulkProcessor.builder(client, new BulkProcessor.Listener(){ @Override public void beforeBulk( long arg0,BulkRequestarg1){ //批量执行前做的事情 System.out.println( "bulkapiactionstarting..." ); } @Override public void afterBulk( long arg0,BulkRequestarg1,Throwablearg2){ System.out.println( "exception:buklapiactionending...:" +arg2.getMessage()); } @Override public void afterBulk( long arg0,BulkRequestarg1,BulkResponsearg2){ //正常执行完毕后... System.out.println( "normal:buklapiactionending..." ); } }) //设置多种条件,对批量操作进行限制,达到限制中的任何一种触发请求的批量提交 .setBulkActions( 1000 ) //设置批量操作一次性执行的action个数,根据请求个数批量提交 //.setBulkSize(newByteSizeValue(1,ByteSizeUnit.KB))//设置批量提交请求的大小允许的最大值 //.setFlushInterval(TimeValue.timeValueMillis(100))//根据时间周期批量提交请求 //.setConcurrentRequests(1)//设置允许并发请求的数量 //设置请求失败时的补偿措施,重复请求3次 //.setBackoffPolicy(BackoffPolicy.exponentialBackoff(TimeValue.timeValueMillis(100),3)) .build(); for ( int i= 0 ;i< 100000 ;i++){ bulkProcessor.add( new IndexRequest( "index-test" , "weibo2" , "" +i).source( XContentFactory .jsonBuilder() .startObject() .field( "name" , "yuchen" +i) .field( "interest" , "love" +i) .endObject())); } bulkProcessor.awaitClose( 5 ,TimeUnit.MINUTES); //释放bulkProcessor资源 System.out.println( "loadsucceed!" ); 默认的参数: sets bulkActions to1000 sets bulkSize to5mb does not set flushInterval sets concurrentRequests to 1 sets backoffPolicy to an exponential backoff with 8 retries and a start delay of 50ms. The total wait time is roughly 5.1 seconds. 参考地址: http://blog.csdn.net/wuyzhen_csdn/article/details/52381697 本文转自yunlielai51CTO博客,原文链接:http://blog.51cto.com/4925054/2084251,如需转载请自行联系原作者

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

Android笔记:代码编写布局

自己在shareSdk原有布局中添加一个加载过程的布局: 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 32 33 34 35 36 37 38 39 40 41 42 43 44 /** 新增:分享发送进度 **/ private void setLoadingUI() { // 页面父布局 pageLayout = new RelativeLayout(getContext()); pageLayout.setLayoutParams( new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); // 填充编辑页布局 RelativeLayout.LayoutParams llPageLp = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); llPage.setLayoutParams(llPageLp); pageLayout.addView(llPage); // 加载过程布局 loadReLayout = new RelativeLayout(getContext()); loadReLayout.setLayoutParams( new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); loadReLayout.setClickable( true ); loadReLayout.setBackgroundColor( 0x50000000 ); loadReLayout.setVisibility(View.GONE); pageLayout.addView(loadReLayout); // 加载过程中间布局 LinearLayout loadCenterLayout = new LinearLayout(getContext()); RelativeLayout.LayoutParams lcLp = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); lcLp.addRule(RelativeLayout.CENTER_IN_PARENT); loadCenterLayout.setPadding( 8 , 8 , 8 , 8 ); loadCenterLayout.setBackgroundColor( 0xa5000000 ); loadCenterLayout.setOrientation(LinearLayout.HORIZONTAL); loadReLayout.addView(loadCenterLayout, lcLp); // 进度条和加载中说明 ProgressBar pb = new ProgressBar(getContext()); pb.setLayoutParams( new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); loadCenterLayout.addView(pb); TextView loadText = new TextView(getContext()); LayoutParams ltlp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); ltlp.setMargins( 8 , 0 , 0 , 0 ); ltlp.gravity = Gravity.CENTER_VERTICAL; loadText.setLayoutParams(ltlp); loadText.setText( "正在转发分享..." ); loadText.setTextSize( 16 ); loadText.setTextColor(Color.WHITE); loadCenterLayout.addView(loadText); } 原布局部分代码: 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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 private void initPageView() { // 编辑页父布局 llPage = new LinearLayout(getContext()); llPage.setBackgroundColor( 0xff323232 ); llPage.setOrientation(LinearLayout.VERTICAL); // 新增:分享发送过程 setLoadingUI(); // 标题栏 llTitle = new TitleLayout(getContext()); llTitle.setBackgroundResource(R.drawable.title_back); llTitle.getBtnBack().setOnClickListener( this ); llTitle.getTvTitle().setText(R.string.multi_share); llTitle.getBtnRight().setVisibility(View.VISIBLE); llTitle.getBtnRight().setText(R.string.share); llTitle.getBtnRight().setOnClickListener( this ); llTitle.setLayoutParams( new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); llPage.addView(llTitle); FrameLayout flPage = new FrameLayout(getContext()); LinearLayout.LayoutParams lpFl = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); lpFl.weight = 1 ; flPage.setLayoutParams(lpFl); llPage.addView(flPage); // 页面主体 LinearLayout llBody = new LinearLayout(getContext()); llBody.setOrientation(LinearLayout.VERTICAL); FrameLayout.LayoutParams lpLl = new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); lpLl.gravity = Gravity.LEFT | Gravity.TOP; llBody.setLayoutParams(lpLl); flPage.addView(llBody); // 别针图片 ivPin = new ImageView(getContext()); ivPin.setImageResource(R.drawable.pin); int dp_80 = cn.sharesdk.framework.utils.R.dipToPx(getContext(), 80 ); int dp_36 = cn.sharesdk.framework.utils.R.dipToPx(getContext(), 36 ); FrameLayout.LayoutParams lpPin = new FrameLayout.LayoutParams(dp_80, dp_36); lpPin.topMargin = cn.sharesdk.framework.utils.R.dipToPx(getContext(), 6 ); lpPin.gravity = Gravity.RIGHT | Gravity.TOP; ivPin.setLayoutParams(lpPin); flPage.addView(ivPin); ImageView ivShadow = new ImageView(getContext()); ivShadow.setBackgroundResource(R.drawable.title_shadow); ivShadow.setImageResource(R.drawable.title_shadow); FrameLayout.LayoutParams lpSd = new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); ivShadow.setLayoutParams(lpSd); flPage.addView(ivShadow); LinearLayout llInput = new LinearLayout(getContext()); llInput.setMinimumHeight(cn.sharesdk.framework.utils.R.dipToPx(getContext(), 150 )); llInput.setBackgroundResource(R.drawable.edittext_back); LinearLayout.LayoutParams lpInput = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); int dp_3 = cn.sharesdk.framework.utils.R.dipToPx(getContext(), 3 ); lpInput.setMargins(dp_3, dp_3, dp_3, dp_3); lpInput.weight = 1 ; llInput.setLayoutParams(lpInput); llBody.addView(llInput); //... } 效果图: 本文转自 glblong 51CTO博客,原文链接:http://blog.51cto.com/glblong/1370018,如需转载请自行联系原作者

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

Android笔记:图片倒影、ReflectionImage

ReflectionImage类代码: 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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PorterDuff.Mode; import android.graphics.PorterDuffXfermode; import android.graphics.Shader.TileMode; import android.graphics.drawable.BitmapDrawable; import android.util.AttributeSet; import android.widget.ImageView; //图片倒影 public class ReflectionImage extends ImageView { // 是否为Reflection模式 private boolean mReflectionMode = true ; public ReflectionImage(Context context) { super (context); } public ReflectionImage(Context context, AttributeSet attrs) { super (context, attrs); // 取得原始图片的bitmap并重画 BitmapDrawable bd = (BitmapDrawable) this .getDrawable(); Bitmap originalImage = bd.getBitmap(); DoReflection(originalImage); } public ReflectionImage(Context context, AttributeSet attrs, int defStyle) { super (context, attrs, defStyle); Bitmap originalImage = ((BitmapDrawable) this .getDrawable()).getBitmap(); DoReflection(originalImage); } public void setReflectionMode( boolean isRef) { mReflectionMode = isRef; } public boolean getReflectionMode() { return mReflectionMode; } // 只重写了setImageResource,和构造函数里面干了同样的事情 @Override public void setImageResource( int resId) { Bitmap originalImage = BitmapFactory.decodeResource(getResources(), resId); DoReflection(originalImage); // super.setImageResource(resId); } private void DoReflection(Bitmap originalImage) { final int reflectionGap = 4 ; // 原始图片和反射图片中间的间距 int width = originalImage.getWidth(); int height = originalImage.getHeight(); // 反转 Matrix matrix = new Matrix(); matrix.preScale( 1 , - 1 ); // reflectionImage就是下面透明的那部分,可以设置它的高度为原始的3/4,这样效果会更好些 Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0 , 0 , width, height, matrix, false ); // 创建一个新的bitmap,高度为原来的两倍 Bitmap bitmapWithReflection = Bitmap.createBitmap(width, (height + height), Config.ARGB_8888); Canvas canvasRef = new Canvas(bitmapWithReflection); // 先画原始的图片 canvasRef.drawBitmap(originalImage, 0 , 0 , null ); // 画间距 Paint deafaultPaint = new Paint(); canvasRef.drawRect( 0 , height, width, height + reflectionGap, deafaultPaint); // 画被反转以后的图片 canvasRef.drawBitmap(reflectionImage, 0 , height + reflectionGap, null ); // 创建一个渐变的蒙版放在下面被反转的图片上面 Paint paint = new Paint(); LinearGradient shader = new LinearGradient( 0 , originalImage.getHeight(), 0 , bitmapWithReflection.getHeight() + reflectionGap, 0x80ffffff , 0x00ffffff , TileMode.CLAMP); // Set the paint to use this shader (linear gradient) paint.setShader(shader); // Set the Transfer mode to be porter duff and destination in paint.setXfermode( new PorterDuffXfermode(Mode.DST_IN)); // Draw a rectangle using the paint with our linear gradient canvasRef.drawRect( 0 , height, width, bitmapWithReflection.getHeight() + reflectionGap, paint); // 调用ImageView中的setImageBitmap this .setImageBitmap(bitmapWithReflection); } } 本文转自 glblong 51CTO博客,原文链接:http://blog.51cto.com/glblong/1290667,如需转载请自行联系原作者

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

ios ionic 装平台 笔记

1.安装cnpm : npm install -g cnpm --registry=https://registry.npm.taobao.org 2.An error occurred when I was running ” ionic cordova platform add ios “.It noticed me with the information : Using cordova-fetch for cordova-ios@^4.4.0 This problem had been resolved by using commands: cordova platform rm ios cordova platform add ios --nofetch ionic build ios / sudo ionic cordova build ios sudo ionic cordova run ios 安装模拟器: sudo npm install -g ios-sim //代表模拟器运行环境, sudo npm install -g ios-deploy //代表真机运行环境。 ionic emulate –list ionic emulate ios ionic emulate ios –target=”iPhone-6, 10.0” 3. 在mac 系统下安装cordova和ionic的命令 sudo npm install -g cordova ionic 如果您已经安装,要确保已经更新到最新的版本,使用下面的命令 sudo npm update -g cordova ionic 使用ionic创建一个应用名为 myApp以tabbar为基础(除了tabs,还包括slidemenu等) $ ionic start myApp tabs 5.设置ionic的编译的平台 $ ionic login $ cd myApp Sudo cordova platform add ios --nofetch $ ionic build android $ ionic run android —————————————— cd demo_1 isudo cordova build ios : 不要ionic sudo ionic cordova emulate ios //模拟器运行 右击button:Touch Up inside是点击事件,可以看见绑定的代码。 一个按钮可以连接多个方法,一个文本框可以连接多个属性。 判断一个对象是否能连线方法:看该对象是否继承UIControl, UIControl类是用来做控制的。 连线:control+控件,拖到代码处,写方法名,id是控件本身。 /* 判断一个对象是否能连线方法: 看该对象的类是否继承于UIControl 经典的错误:看控制台的reason, 1. 错误一 描述: reason: '[<MainViewController 0x7ffebbc1a880> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key testLabel.' 原因: 有多余的连线 解决: 删除多余的连线 2.错误二 描述: reason: '-[MainViewController clickBtn:]: unrecognized selector sent to instance 0x7feb69418640' 原因:找不到对应的方法 解决:1.添加对应的方法 2.删除多余的连线 */ 右边的面板:Placehoider(默认显示值),Keyboard Type(键盘类型), http://www.easyicon.net 图标资源。 按钮跳到下一个控制器:点击按钮————拖着指向下一个控制器———点击show 跳转的控制器有返回键:Editor———Embed in ——Navigation Control 将拖过去的StoryBoard保存成左边文件夹里面去:点击故事板的圆圈————editor———refacter to StoryBoard——选择他所对应的控制器的类所在的文件夹. 本文转自农夫山泉别墅博客园博客,原文链接:http://www.cnblogs.com/yaowen/p/7462882.html,如需转载请自行联系原作者

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

android152 笔记 4

42. Android中Task任务栈的分配。 首先我们来看下Task的定义,Google是这样定义Task的:a task is what the user experiences as an "application." It's a group of related activities, arranged in a stack. A task is a stack of activities, not a class or an element in the manifest file. 这意思就是说Task实际上是一个Activity栈,通常用户感受的一个Application就是一个Task。从这个定义来看,Task跟Service或者其他Components是没有任何联系的,它只是针对Activity而言的。 Activity有不同的启动模式, 可以影响到task的分配 Task,简单的说,就是一组以栈的模式聚集在一起的Activity组件集合。它们有潜在的前后驱关联,新加入的Activity组件,位于栈顶,并仅有在栈顶的Activity,才会有机会与用户进行交互。而当栈顶的Activity完成使命退出的时候,Task会将其退栈,并让下一个将跑到栈顶的Activity来于用户面对面,直至栈中再无更多Activity,Task结束。 事件 Task栈(粗体为栈顶组件) 点开Email应用,进入收件箱(ActivityA) A 选中一封邮件,点击查看详情(ActivityB) AB 点击回复,开始写新邮件(ActivityC) ABC 写了几行字,点击选择联系人,进入选择联系人界面(ActivityD) ABCD 选择好了联系人,继续写邮件 ABC 写好邮件,发送完成,回到原始邮件 AB 点击返回,回到收件箱 A 退出Email程序 null 如上表所示,是一个实例。从用户从进入邮箱开始,到回复完成,退出应用整个过程的Task栈变化。这是一个标准的栈模式,对于大部分的状况,这样的Task模型,足以应付,但是,涉及到实际的性能、开销等问题,就会变得残酷许多。 比如,启动一个浏览器,在Android中是一个比较沉重的过程,它需要做很多初始化的工作,并且会有不小的内存开销。但与此同时,用浏览器打开一些内容,又是一般应用都会有的一个需求。设想一下,如果同时有十个运行着的应用(就会对应着是多个Task),都需要启动浏览器,这将是一个多么残酷的场面,十个Task栈都堆积着很雷同的浏览器Activity, 是多么华丽的一种浪费啊。 于是你会有这样一种设想,浏览器Activity,可不可以作为一个单独的Task而存在,不管是来自那个Task的请求,浏览器的Task,都不会归并过去。这样,虽然浏览器Activity本身需要维系的状态更多了,但整体的开销将大大的减少,这种舍小家为大家的行为,还是很值得歌颂的 standard", "singleTop", "singleTask", "singleInstance"。 standard模式, 是默认的也是标准的Task模式,在没有其他因素的影响下,使用此模式的Activity,会构造一个Activity的实例,加入到调用者的Task栈中去,对于使用频度一般开销一般什么都一般的Activity而言,standard模式无疑是最合适的,因为它逻辑简单条理清晰,所以是默认的选择。 而singleTop模式,基本上于standard一致,仅在请求的Activity正好位于栈顶时,有所区别。此时,配置成singleTop的Activity,不再会构造新的实例加入到Task栈中,而是将新来的Intent发送到栈顶Activity中,栈顶的Activity可以通过重载onNewIntent来处理新的Intent(当然,也可以无视...)。这个模式,降低了位于栈顶时的一些重复开销,更避免了一些奇异的行为(想象一下,如果在栈顶连续几个都是同样的Activity,再一级级退出的时候,这是怎么样的用户体验...),很适合一些会有更新的列表Activity展示。一个活生生的实例是,在Android默认提供的应用中,浏览器(Browser)的书签Activity(BrowserBookmarkPage),就用的是singleTop。 singleTask,和singleInstance,则都采取的另辟Task的蹊径。 标志为singleTask的Activity,最多仅有一个实例存在,并且,位于以它为根的Task中。所有对该Activity的请求,都会跳到该Activity的Task中展开进行。singleTask,很象概念中的单件模式,所有的修改都是基于一个实例,这通常用在构造成本很大,但切换成本较小的Activity中。最典型的例子,还是浏览器应用的主Activity(名为Browser...),它是展示当前tab,当前页面内容的窗口。它的构造成本大,但页面的切换还是较快的,于singleTask相配,还是挺天作之合的。 singleInstance显得更为极端一些。在大部分时候singleInstance与singleTask完全一致,唯一的不同在于,singleInstance的Activity,是它所在栈中仅有的一个Activity,如果涉及到的其他Activity,都移交到其他Task中进行。这使得singleInstance的Activity,像一座孤岛,彻底的黑盒,它不关注请求来自何方,也不计较后续由谁执行。在Android默认的各个应用中,很少有这样的Activity,在我个人的工程实践中,曾尝试在有道词典的快速取词Activity中采用过, 是因为我觉得快速取词入口足够方便(从notification中点选进入),并且会在各个场合使用,应该做得完全独立。 大的apk 拆成 很多小的apk ●Activity的android:affinity属性 1.配置后 当启动这个activity时就先去找有没有activity的亲和力属性相同 有就加入这个 activity所在的任务中没有就新开任务(照相和图库就是有亲缘关系的,在照相里面可以点击进去图库。) 2.affinity起作用需要的条件二者具备一个: 1.intent包含FLAG_ACTIVITY_NEW_TASK标记 2.activity元素启用了allowTaskReparenting属性. 43. 在Android中,怎么节省内存的使用,怎么主动回收内存? 回收已经使用的资源,置为null. 合理的使用缓存 合理设置变量的作用范围… application 对象 //未来的某一段时间执行 System.gc(); 44. 不同工程中的方法是否可以相互调用? 可以,列举aidl访问远程服务的例子. 45. 在Android中是如何实现判断区分电话的状态,去电,来电、未接来电? Day8 showAddressService.java 46. dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念 Dvm的进程是dalivk虚拟机进程运行在linux里面,每个android程序都会开启一个Dvm的进程,都运行在自己的进程里面, 每个android程序系统都会给他分配一个单独的liunx uid(user id), 每个dvm都是linux里面的一个进程.所以说这两个进程是一个进程. 47. sim卡的EF 文件有何作用 Sim卡相关的东西,没接触过,sim的存储空间。 48. 如何判断是否有SD卡? 配置文件中有sd卡的权限, 通过environment的静态方法, if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 49. 嵌入式操作系统内存管理有哪几种, 各有何特性。 页式,段式,段页,等 … 50. 什么是嵌入式(对CPU和内存要求比较低,单片机就是嵌入式操作系统)实时操作系统, Android 操作系统属于实时操作系统吗? 实时操作系统是指当外界事件或数据产生时,能够接受并以足够快的速度予以处理,其处理的结果又能在规定的时间之内来控制生产过程或对处理系统作出快速响应,并控制所有实时任务协调一致运行的嵌入式操作系统。主要用于工业控制、军事设备、航空航天等领域对系统的响应时间有苛刻的要求,这就需要使用实时系统。又可分为软实时和硬实时两种,而android是基于linux内核的,因此属于软实时。 51. 一条最长的短信息约占多少byte? 中文70(包括标点),英文160,160个字节 这个说法不准确, 要跟手机制式运营商等信息有关. 做实验,看源码 ArrayList<String> msgs = sms.divideMessage(message); for (String msg : msgs) { sms.sendTextMessage(phoneNumber, null, msg, pi, null); } 本文转自农夫山泉别墅博客园博客,原文链接:http://www.cnblogs.com/yaowen/p/5170778.html,如需转载请自行联系原作者

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

openstack学习笔记十一 Nova

计算节点 跑虚拟机 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 32 33 34 35 36 37 38 39 [root@hequan~] #yuminstallopenstack-nova.noarchopenstack-nova-api.noarchopenstack-nova-conductor.noarch openstack-nova-novncproxy.noarchopenstack-nova-scheduler.noarchopenstack-nova-console.noarch ##控制节点 [root@hequan~] #yuminstallopenstack-nova-compute.noarch##计算节点 keystoneuser-create--namenova--passhequan keystoneuser-role-add--usernova--roleadmin--tenantservices keystoneservice-create--namenova-- type compute--descriptionnova |7708b5c40aec4cf3b59d6d84596a5f6b|nova|compute|OpenstackComputeService| |017bdbf9f335436cbd7f65fe74089b28|nova_ec2|ec2|EC2Service| |4f7b60427d304fd89658f4f8c23dd708|novav3|computev3|OpenstackComputeServicev3| +----------------------------------+-----------+-------------------------------------------------+-------------------------------------------------+--------------------------------------------+----------------------------------+ | id |region|publicurl|internalurl|adminurl|service_id| +----------------------------------+-----------+-------------------------------------------------+-------------------------------------------------+--------------------------------------------+----------------------------------+ |0bda7145ebc944a99112c53e97362fa1|RegionOne|http: //115 .29.107.17:8774 /v2/ %(tenant_id)s|http: //115 .29.107.17:8774 /v2/ %(tenant_id)s|http: //115 .29.107.17:8774 /v2/ %(tenant_id)s|7708b5c40aec4cf3b59d6d84596a5f6b| |731be711c3be4497b57c8751ce111986|RegionOne|http: //115 .29.107.17:8773 /services/Cloud |http: //115 .29.107.17:8773 /services/Cloud |http: //115 .29.107.17:8773 /services/Admin |017bdbf9f335436cbd7f65fe74089b28| |7ec9cb12959f4bedb7e0757c79b636fd|RegionOne|http: //127 .0.0.1:8774 /v3 |http: //127 .0.0.1:8774 /v3 |http: //127 .0.0.1:8774 /v3 |4f7b60427d304fd89658f4f8c23dd708| keystoneendpoint-create--service- id --publicul '' --internalurl '' --adminurl '' openstack-db--init--servicenova--passwordhequan--root123456 [root@hequan~] #ls-ld/var/log/nova/ drwxr-x---2novaroot40967月2300:08 /var/log/nova/ [root@hequan~] #chownnova.nova/var/log/nova/-R [root@hequannova(keystone_admin)] #mvnova.confnova.conf.bak [root@hequannova(keystone_admin)] #systemctllist-unit-files|grepnova openstack-nova-api.serviceenabled openstack-nova-cert.serviceenabled openstack-nova-compute.serviceenabled openstack-nova-conductor.serviceenabled openstack-nova-console.servicedisabled openstack-nova-consoleauth.serviceenabled openstack-nova-metadata-api.servicedisabled openstack-nova-novncproxy.serviceenabled openstack-nova-scheduler.serviceenabled openstack-nova-xvpvncproxy.servicedisabled vncserver_proxyclient_address=115.29.107.17 ##改成本机的IP vim nova.conf 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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 [DEFAULT] internal_service_availability_zone=internal default_availability_zone=nova novncproxy_host=0.0.0.0 novncproxy_port=6080 notify_api_faults=False state_path= /var/lib/nova report_interval=10 enabled_apis=ec2,osapi_compute,metadata ec2_listen=0.0.0.0 ec2_listen_port=8773 ec2_workers=1 osapi_compute_listen=0.0.0.0 osapi_compute_listen_port=8774 osapi_compute_workers=1 metadata_listen=0.0.0.0 metadata_listen_port=8775 metadata_workers=1 compute_manager=nova.compute.manager.ComputeManager service_down_time=60 rootwrap_config= /etc/nova/rootwrap .conf volume_api_class=nova.volume.cinder.API auth_strategy=keystone use_forwarded_for=False heal_instance_info_cache_interval=60 reserved_host_memory_mb=512 cpu_allocation_ratio=16.0 ram_allocation_ratio=1.5 network_api_class=nova.network.neutronv2.api.API default_floating_pool=public force_snat_range=0.0.0.0 /0 metadata_host=115.29.107.17 dhcp_domain=novalocal security_group_api=neutron scheduler_default_filters=RetryFilter,AvailabilityZoneFilter,RamFilter,ComputeFilter,ComputeCapabilitiesFilter,ImagePropertiesFilter,CoreFilter scheduler_driver=nova.scheduler.filter_scheduler.FilterScheduler compute_driver=libvirt.LibvirtDriver vif_plugging_is_fatal=True ##修改False如果有报错实例执行请求失败 vif_plugging_timeout=300 ##修改为0 firewall_driver=nova.virt.firewall.NoopFirewallDriver force_raw_images=True debug=False verbose=True log_dir= /var/log/nova use_syslog=False syslog_log_facility=LOG_USER use_stderr=True notification_topics=notifications rpc_backend=rabbit amqp_durable_queues=False sql_connection=mysql: //nova :hequan@115.29.107.17 /nova image_service=nova.image.glance.GlanceImageService lock_path= /var/lib/nova/tmp osapi_volume_listen=0.0.0.0 vncserver_proxyclient_address=115.29.107.17 ##修改本机地址 vnc_keymap=en-us vnc_enabled=True vncserver_listen=0.0.0.0 novncproxy_base_url=http: //115 .29.107.17:6080 /vnc_auto .html [api_database] [barbican] [cells] [cinder] catalog_info=volumev2:cinderv2:publicURL [conductor] [cors] [cors.subdomain] [database] [ephemeral_storage_encryption] [glance] api_servers=115.29.107.17:9292 [guestfs] [hyperv] [image_file_url] [ironic] [keymgr] [keystone_authtoken] auth_uri=http: //115 .29.107.17:5000 /v2 .0 identity_uri=http: //115 .29.107.17:35357 admin_user=nova admin_password=hequan admin_tenant_name=services [libvirt] virt_type=qemu inject_password=False inject_key=False inject_partition=-1 live_migration_uri=qemu+tcp: //nova @%s /system cpu_mode=none vif_driver=nova.virt.libvirt.vif.LibvirtGenericVIFDriver [matchmaker_redis] [matchmaker_ring] [metrics] [neutron] service_metadata_proxy=True metadata_proxy_shared_secret=hequan url=http: //115 .29.107.17:9696 admin_username=neutron admin_password=hequan admin_tenant_name=services region_name=RegionOne admin_auth_url=http: //115 .29.107.17:5000 /v2 .0 auth_strategy=keystone ovs_bridge=br-int extension_sync_interval=600 timeout=30 default_tenant_id=default [osapi_v21] [oslo_concurrency] [oslo_messaging_amqp] [oslo_messaging_qpid] [oslo_messaging_rabbit] kombu_reconnect_delay=1.0 rabbit_host=115.29.107.17 rabbit_port=5672 rabbit_hosts=115.29.107.17:5672 rabbit_use_ssl=False rabbit_userid=guest rabbit_password=guest rabbit_virtual_host=/ rabbit_ha_queues=False heartbeat_timeout_threshold=0 heartbeat_rate=2 [oslo_middleware] [rdp] [serial_console] [spice] [ssl] [trusted_computing] [upgrade_levels] [vmware] [vnc] [workarounds] [xenserver] [zookeeper] [osapi_v3] enabled=False 1 2 3 4 5 6 7 8 9 10 11 12 [root@hequan~] #nova-manageservicelist [root@hequan~(keystone_admin)] #novahost-list +---------------+-------------+----------+ |host_name|service|zone| +---------------+-------------+----------+ |hequan.lol|consoleauth|internal| |hequan.lol|scheduler|internal| |hequan.lol|conductor|internal| |hequan.lol|compute|nova| |hequan.lol|cert|internal| [root@hequan~] #systemctlis-activelibvirtd.service active 本文转自 295631788 51CTO博客,原文链接:http://blog.51cto.com/hequan/1832697,如需转载请自行联系原作者

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

RHCE 学习笔记(15)- KVM

这一节和老师简单的学习了下KVM的入门知识,主要包括了如何通过图形界面安装VM,基本的配置以及最基本的几个命令。 豆子对其他平台的虚拟机比较熟悉,ESXi,Hyper-V,XenServer 等等,KVM和这3大平台比较起来,知名度要低一些,豆子搜索了一下网上的对比评价,Flexiant发布了一份白皮书,结论让我有点小意外,作为企业级的龙头产品,肯定还是ESXi,但是考虑到性价比,KVM的排名居然还在Hyper-V和Xen之上。 KVM(Kernel-based VM),意思是基于内核的虚拟机。具体的原理和架构豆子不过多阐述,因为我现在也是菜鸟这里有个博客解释的还是比较清楚 https://www.linuxwind.org/html/learning-the-kvm-01.html 下面演示记录一下实验的步骤,实际是在我现有的一个ESXi的RHEL虚拟机上做一个嵌套的操作。 首先RHEL的CPU需要设置支持虚拟化 查看一下配置文件,确认vmx已经添加 配置Yum 源 ,查看组 安装组 装完以后看看服务是否启动 如果没装virt-manager,安装一下 装好之后后台打开 virt-manger & 就可以创建虚拟机了 一路点下去,根据自己需求酌情修改 豆子安装了一个Ubuntu12的虚拟机 大概20分钟装完了,打开虚拟机,点击灯泡图案,可以查看配置 默认的网络配置是NAT 在宿主机上看看,会多了一个虚拟的网卡出来,这个虚拟网卡对于虚拟机来说,相当于一个交换机 他是可以从宿主机Ping 通 虚拟机的,甚至虚拟机可以直接ping 通我的物理机,相当于虚拟机的eth0网卡连接到了virbr0,然后virbr0又连接到了RHEL的eno网卡,这样一层层的转发出来 切换到root 用户,可以执行命令行来进行操作,virsh有上百个选项,最简单的比如查看,启动,关闭 注意virsh shutdown 和 virsh destroy 的区别,前者是正常关闭,后面那个相当于poweroff(直接断电) 对于宿主机,我们也可以进行配置,比如添加新的网络,这个和vmware workstation很像。 随便添加一个 Host的修改完毕之后,在VM上就能看见新的网络选项了,相当于多了一个交换机的选择出来 重启以后进去就能看见两个网卡都配置好了 最后说说存储池,这个是默认的VM文件存放点 查看一下 本文转自 beanxyz 51CTO博客,原文链接:http://blog.51cto.com/beanxyz/1600499,如需转载请自行联系原作者

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

Android笔记:关于so文件

项目里包含了多个带有so文件的第三方库,支持的平台数不一样。当应用跑在5.0系统上便会崩溃,后发现是有些第三方库的x86-64的so文件没有安装。 查看了官网的ABIManager,似乎写得并不够清晰。处理过程中,发现信鸽sdk附带的一份说明倒是让人很容易的理解so文件的安装机制。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 1 .信鸽的.so支持所有的android平台,但考虑到平时接入一般只需要armeabi平台,因此libs目录只提供该平台的.so,其它平台可在上层目录的All-Platform-SO找到。 2 .嵌入.so可能存在的问题: a.so文件与jar包不匹配。 解决办法:在更新jar时同时更新对应的so文件; b.当前工程已有某些平台的so,如只有armeabi平台,却添加信鸽所有平台导致打包时异常。 解决办法:只添加当前工程已有的平台的信鸽so文件。具体可参考网上或以下示例: armeabi !此平台既有当前存在so又有信鸽,正常! --libCurrent.so 当前工程已有so --libtpnsSecurity.so 信鸽 --libtpnsWatchdog.so 信鸽 armeabi-v7a !此平台既有当前存在so又有信鸽,正常! --libCurrent.so 当前工程已有so --libtpnsSecurity.so 信鸽 --libtpnsWatchdog.so 信鸽 mips !!!错误,由于此平台只有信鸽,必须删掉mips目录!!! --libtpnsSecurity.so 信鸽 --libtpnsWatchdog.so 信鸽 x86 !!!错误,由于此平台只有信鸽,必须删掉x86目录!!! --libtpnsSecurity.so 信鸽 --libtpnsWatchdog.so 信鸽 c.若当前工程不存在so文件。 解决办法:可复制所有信鸽平台或只复制armeabi平台 再结合其他参考文章,应该可以大概总结如下: 至少包含armeabi平台 多个不同库都有so文件时 就以包含支持最少平台的那个为准 其他参考: 1.http://www.open-open.com/lib/view/open1440421271716.html 2.http://stackoverflow.com/questions/30782848/how-to-use-32-bit-native-libaries-on-64-bit-android-device 本文转自 glblong 51CTO博客,原文链接:http://blog.51cto.com/glblong/1698839,如需转载请自行联系原作者

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

Android开发问题笔记

1、Toolbar问题:最低版本15,必须使用support,才能使用Toolbar,Toobar是5.0引入的 2、BottomTab:这个用TabLayout解决了 3、后端API最好采用一个成熟的框架来做,比如Restful的Django-Rest-Framework,既可以简化IT设施层、又可以复用成熟的设计: 4、最后还是用Android Studio生成向导的TabLayout+ViewPager+PlaceFragment解决问题。 5、官网的Best Practice值得参考借鉴 6、采用OkHTTP做网络访问 7、采用Picasso做图片加载 8、采用ExpandListView做According:http://www.cnblogs.com/eyu8874521/archive/2012/08/16/2642605.htmlhttp://my.oschina.net/amigos/blog/62614 9、非动态调整的信息尽量在layout里面指明 10、代码Copy+粗心大意坑死人:出现问题应该先自己定位。 11、Android的UI设计思路不是做好UI套数据,而是由数据结构出UI结构,UI和数据通过Adapter在结构上匹配生成。所以本质上android不是拖拽式开发的界面设计,而是官方所宣称的MCV结构,类似于网页的MVT架构。 12、Android设计开发第一坑:布局 13、ListView子项的margin可以用devider来设置 14、调效果用手机,比模拟器快,调代码用模拟器,跟踪比真机方便。 15、要努力拉长App代码调试的时间周期,因为run一次的时间消耗不短。 16、通过沟通提高前后端联调效率的一个方法:对领域模型的设计要有专门的沟通通气会议。 17、AndroidSDK的本地安装文档,因为引用了远程文件的原因,可用性不是很好。 18、关键设计一定要有相关方审查步骤,比如数据模型、比如移动后端的API。 19、ListView里面不应该出现布局不一致的ListItem,这样就会导致ItemView的复用出现问题 20、Button可以用text显示,tag传值。 21、给RxJava传递的final参数可能需要copy复制才可以保证多线程读写问题,一般只有UI主线程和后台线程的情境下不需要 22、资源状态列表,这个信息可以从官方API指南找到: [html] view plain copyprint? <selectorxmlns:android="http://schemas.android.com/apk/res/android";> <item android:color="hex_color" android:state_pressed=["true"|"false"] android:state_focused=["true"|"false"] android:state_selected=["true"|"false"] android:state_active=["true"|"false"] android:state_checkable=["true"|"false"] android:state_checked=["true"|"false"] android:state_enabled=["true"|"false"] android:state_window_focused=["true"|"false"]/> </selector> 23、Fragment的onCreate用来初始化数据,onCreateView用来初始化界面,前者一般只执行一次,后者随界面切换多次执行,所以后者里面最好不要做数据加载,如果某些数据加载必须在界面初始化以后做,要加上首次执行条件判断。 24、TextView里可用的HTML标签,注意标签不能String资源里面直接写,直接写就被过滤掉了,但是写在代码的String变量里面可以,虽然不太符合Android开发规范,但是避免了字符转换,算是比较nice的解决方式。 [html] view plain copyprint? <ahref="..."> <b> <big> <blockquote> <br> <cite> <dfn> <divalign="..."> <em> <fontsize="..."color="..."face="..."> <h1> <h2> <h3> <h4> <h5> <h6> <i> <imgsrc="..."> <p> <small> <strike> <strong> <sub> <sup> <tt> <u> 25、onCreate、onStart里面对View做操作,View都可能还没有渲染成功,所以比如getHeight得到的可能是0,要确保view渲染以后代码执行,可以用view.post(runnable) 26、ListView显示不全,原因是AppbarLayout占了两行空间。把TabLayout移出AppbarLayout 27、为什么要用接口:没有基类的实现负担,实现基类的不同子类对象实例的灵活可换。丛某种角度讲:接口是静态类型语言非鸭式辨型导致的累赘。 28、Fragment的的资源新建初始化必须放在onCreate,放在onCreateView里面会导致重复调用,从而资源泄露。 29、has leaked window com.android.internal.policy.impl.PhoneWindow$ that was originally added here 这个问题的交互诱因是Activity退出的时候,其界面上的dialog还在显示,解决方法,覆盖相关组件的onDestroy方法,把dialog释放掉: [java] view plain copyprint? @Override publicvoidonDestroy(){ super.onDestroy(); if(mLoadingDialog!=null&&mLoadingDialog.isShowing()){ mLoadingDialog.dismiss(); } } 另外多说一句话,静态对象不能引用组件资源,否则会导致被引用的组件资源无法正常地被系统框架释放掉。 30、Android Studio 主题资源站:http://www.androidstudiothemes.com/ 31、一般来讲带反向应用的组件实例对象变量要在组件onDestroy的时候把这些变量都要释放掉(=null),至于静态变量最好不要有对组件的引用,也就是说有对组件有反向应用的对象变量最好不要做成静态的。一般有队组件有反向引用的对象主要是系统组件对象。 32、AVD虚拟机启动错误提示: [plain] view plain copyprint? emulator:WARNING:.//android/metrics/metrics_reporter_ga.c:138:curl_easy_perform()failedwithcode7(Error) emulator:WARNING:.//android/metrics/metrics_reporter_ga.c:145:GotHTTPresponsecode0 修改方法:Open the Android Studio->Preferences, go to Appearance & Behavior->System Settings->Usage Statistics, and uncheck "Send usage statistics to Google". Now the matrics_reporter will be disabled during emulator starting. 推荐出不出错误,都做此修改,不然虚拟机启动以后,Log老报这方面的连接错误。 33、Fragment的getView()在onCreateView这个函数执行之前是空的,所以onCreateView函数里面只能用自己inflate的view来做findViewbyID操作。 34、RxAndroid导致的空指针问题:一般网络数据爬取完,要操作Activity或者Fragment的资源来完成数据显示更新,但是由于网络访问和用户切换界面操作的时间差,当你做数据显示更新的时候,也许Activtiy或者fragment的资源已经不复存在由此导致NullPointer Error问题,可以通过操作这些资源之前做个空指针判断来解决这个问题。 35、Fragment的Context Activity空指针问题,由于API不同版本之间的不一致性,在Fragment的生存生命周期内,可能存在其Context Activity其实不存在或者被销毁,在这种情况下,如果要使用这个Actiity对象,也要做空指针判断。 36、对于Fragment的使用,《Android权威编程指南》曾经推荐尽量使用标准库里的Fragment,并且放弃使用FragmentActivity,转而使用标准库中的Activity类,放弃使用support.v4.app.fragment,转而使用app.fragment,放弃使用getSupportFragmentManager().转而使用getFragmentManager()方法 37、对于所有View的取其界面属性值的处理,比如getHeight,getWidth,都要用post异步化,因为做成同步,很容易是界面未正确渲染时的结果。 本文转自莫水千流博客园博客,原文链接:http://www.cnblogs.com/zhoug2020/p/5874621.html,如需转载请自行联系原作者

资源下载

更多资源
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文件系统,支持十年生命周期更新。

用户登录
用户注册