Login
升级VIP 登录 注册 安全退出
当前位置: 首页 > word文档 > 其他文档 > PeerSim中文教程

PeerSim中文教程

收藏

本作品内容为PeerSim中文教程,格式为 doc ,大小 1156608 KB ,页数为 45页

PeerSim中文教程


('PeerSim中文教程(1):解析Cycle-based模式仿真本文介绍了PeerSim的基本概念,并解析了两个示例以更清晰地说明PeeSim的仿真流程。Peersim支持两种仿真模式,即Cycle-based的模型和传统的event-based的模型,本文专注于前者,Cycle-based模型是一个简化的模型,拥有更好的伸缩性及性能,在拥有4GB内存的情况下,event-driven模式目前最多支持十万节点级别,而cycle-based模式则支持千万个节点级别。但是Cycle-based模型缺少对传输层的仿真和并行处理,节点之间是直接通信的,仿真核心以一定的顺序周期性地给以节点控制。在运行时,可以进行任意的操作,如调用其它对象的方法并执行一些计算。Cycle-based模型损失了一些真实性,虽然一些简单的协议可以忽略这些差别,但是在选择使用这个模型时,需要注意这些区别。我们可以相对简单地将Cycle-based的仿真移植到Event-driven引擎上,但在本文中不讨论这个话题。一.基本介绍PeerSim鼓励基于接口的模块化编程,每一个组件都能被其它实现了相同接口的组件代替,一般的仿真过程如下:1.选择网络大小(即节点数量)。2.选择要实验的一个或多个协议并进行初始化。3.选择一个或多个Control对象来监视感兴趣的属性,并在仿真时修改一些参数(比如,网络大小,协议的内部状态,等等)。4.根据配置文件,调用Simulator类运行仿真。在仿真时创建的对象都是实现了一个或多个接口的类的实例,主要的接口如下所示:NodeP2P网络是由节点组成的,节点是协议的容器。Node接口提供了对节点所包含的协议的访问方法,并为节点提供了固定的ID。CDProtocol这是一个特定的协议,被设计用来在Cycle-based模型中运行,它只定义了在每一个周期中要运行的操作。Linkable一般都由协议来实现,这个接口为其它协议提供了访问邻居节点集合的服务,节点间相同的linkable协议类的实例定义了一个覆盖网络。Control实现了这个接口的类可以在仿真期间的某个时间点调度执行,这些类一般用于观察或修改仿真过程。Cycle-based仿真的生命周期是这样的:1.读取配置文件(通过命令行参数传递进来),然后仿真器初始化网络中的节点和节点中的协议,每个节点都拥有相同的协议栈。节点和协议的实例是通过克隆来创建的,只有一个原型是通过构造方法创建,其它的节点和协议都是从这个原型中克隆而来。基于这个原因,协议类中clone方法的实现是很重要的。2.初始化操作,设置每个协议的初始状态。初始化阶段是由Control对象控制运行的,仅在实验开始时运行一次。在配置文件中,初始化的组件可以由init前缀识别,在下面讨论的initializer对象也是controls,但为了标记其功能以区别于一般的Control对象,它被配置用来在初始阶段运行。3.在初始化完成后,Cycle-based引擎在每一个周期中调用所有组件(protocols和controls)一次,直到完成了指定的周期数,或者某个组件决定终止仿真为止。在PeerSim中每一个对象(controls和protocols)都被赋以一个Scheduler对象,它定义了什么时候本组件将会被执行。在默认情况下,所有对象都会在每个周期中运行。但我们也可以配置一个protocol或control只在某些特定的周期中运行,也可以在每一个周期中指定组件的执行顺序。下图展示了对controls和protocols的调度,其中C代表Control而P代表一个协议。图下方的数字代表PeerSim的周期,在最后一个周期后,可以运行一个control来获取最后的快照(snapshot)。peersim-schedule在一个Control收集数据时,数据将会被格式化并发送到标准输出或重定向到一个文件以进行后续的处理。配置文件只是一个普通的ASCII文本,本质上就是java.util.Properties,以#开头的行代表注释。用以下的方式在命令行的模式下运行,比如:1java-cppeersim.Simulatorconfig-edexample.txt具体来说,可能是:1java-cpD:\\library\\peersim-1.0.5\\jep-2.3.0.jar;D:\\library\\peersim-1.0.5\\djep-1.0.0.jar;D:\\library\\peersim-1.0.5\\peersim-1.0.5.jar;D:\\library\\peersim-1.0.5\\peersim-doclet.jarpeersim.SimulatorD:\\library\\peersim-1.0.5\\example\\config-edexample.txt当然你的jar包和配置文件的位置可能有所不同,也可以将这个jar包直接加到classpath上,就不必使用-cp参数来显示指定classpath。二.配置文件示例一Gossip-basedAggregation协议,Aggregation是聚集的意思,这里是指对一个分布于网络中的数值集合运行一个特定的函数进行计算(如求平均数,最大值,最小值等等),每个节点周期性地选择一个邻居节点进行通讯(基于覆盖网),并且在每次通讯时,基于前一个取得的近似值,相互更新它们下次计算的近似值。本例将创建一个由50000个节点组成的固定P2P随机拓扑,选定的协议是使用average函数的Aggregation协议,每个节点中用于求平均的值使用一个区间在(0,100)的线性分布来初始化,最后再定义一个Control监视平均值。01#PEERSIMEXAMPLE10203random.seed123456789004simulation.cycles300506control.shfShuffle0708network.size500000910protocol.lnkIdleProtocol1112protocol.avgexample.aggregation.AverageFunction13protocol.avg.linkablelnk1415init.rndWireKOut16init.rnd.protocollnk17init.rnd.k201819init.peakexample.aggregation.PeakDistributionInitializer20init.peak.value1000021init.peak.protocolavg2223init.linLinearDistribution24init.lin.protocolavg25init.lin.max10026init.lin.min12728#youcanchangethistoselectthepeakinitializerinstead29include.initrndlin3031control.avgoexample.aggregation.AverageObserver32control.avgo.protocolavg上面的配置中,一部份是全局属性,另一部分对应单个组件的实例。如simulation.cycles是全局属性,而protocol.lnk.xxx则定义了lnk协议的xxx参数。第6行的control.shfShuffle,Shuffle类是用来重新洗牌,在每次重新洗牌后,在一个Cycle-based类型的仿真周期中,节点迭代的次序将会变成随机的,这个类只对Cycle-based类型的仿真起作用。每个组件都有一个名字,比如lnk。对于协议,这个名字将会被映射到一个在PeerSim引擎中称为protocolID的数值型索引,虽然这个索引不出现在配置文件中,但在仿真时需要使用它来访问协议,这在后面将进一步解释。一个组件,即protocol或control由下面的语法来声明:1[protocolinitcontrol].string_id[full_path_]classname注意到类的全路径是可选的,事实上PeerSim可以在类路径中搜索类名,只有在多个类拥有相同的名称时必须使用全路径。init前缀定义了一个Initializer对象,它实现了Control接口。组件的参数(如果有的话)则以下面的语法定义:1[protocolinitcontrol].string_id.parameter_name第10行定义了第一个协议,键部份包含了它的类型,而值则是组件的类名,由于IdleProtocol类在peersim包中,所以不必使用全路径。可以为每一个组件声明参数,如第13行;而从第3行到第8行一些全局的仿真属性被引入,如仿真的总周期数和覆盖网的大小。Shufflecontrol对每一个周期中节点的访问顺序进行重新洗牌。从第10行到第13行,引入了两个协议:\uf0b7IdleProtocol是存储邻居节点链路的一个静态容器,在进行静态拓扑建模的时候尤其有用,这个协议的唯一功能是作为其它协议的邻居信息的源,它没有实现CDProtocol接口但实现了Linkable接口,Linkable接口提供了到邻居节点的链路。\uf0b7AverageFunction是聚集协议的求平均数版本。它的参数(linkable)是很重要的,aggregation协议需要与邻居节点交流但是本身没有邻居节点列表。在模块化的方式中,它能应用于任何覆盖网络;定义覆盖网的协议栈应当在这里指定,参数linkable的值是实现了Linkable接口的协议的类名(在这里是IdleProtocol)。从15行到26行用于初始化之前声明的所有组件。前面声明了3个初始化组件,但只有其中的2个被使用了(见29行)。第一个初始化器,peersim.init.WireKOut,进行的是对静态覆盖网的布线,特别的,节点以度数k随机地与其它节点相连接。第2个和第3个初始化器是初始化aggregation协议的可选方案,在这里是指需要求平均的初值。初始化器设置初始值遵循peak分布或线性分布。Peak的意思是只有一个节点拥有与0不同的值。而线性则代表节点被拥有一个线性增加的值。两个初始化都需要一个指定了协议来进行初始化(协议参数)的协议名。额外的参数是PeakDistributionInitializer的range(max,min参数)。使用peak还是linear分布是由include.init属性来决定的(29行),它指定了选择哪个初始化器。这个属性也定义了组件运行的顺序,注意到默认的顺序(即如果没有include属性),是根据字母排序的,对于protocol和control的include属性也是如此。最后,31行和32行声明了最后一个组件:aggregation.AverageObserver。它使用的唯一参数是protocol,它引用了aggregation.AverageFunction协议类型,所以这个参数的值是avg。在命令行下,注释掉第3行的seed,运行这个仿真,得到的结果将是:01control.avgo:01.0100.05000050.49999999999998816.79900663354681102control.avgo:11.297005940118802399.385197703954085000050.50000000000005249.406732876865451103control.avgo:29.57357147142942884.388749024980485000050.50000000000008577.893858778951821104control.avgo:323.86036158223164771.936272241069825000050.4999999999996724.1313667072284021105control.avgo:434.92091596714746568.928284821189585000050.499999999999947.7020829054142731106control.avgo:542.3722819840994659.945110048708235000050.499999999999872.4313562110887751107control.avgo:645.1962191215179454.8555161630707465000050.4999999999998440.77414517067548771108control.avgo:747.6871627452809253.114339347456465000050.499999999999490.245153657290698571109control.avgo:848.9770627131815852.389162380212765000050.500000000000260.077465233847312691110control.avgo:949.5967444019466851.469634726374515000050.499999999999370.0246893488170118231111control.avgo:1049.94649041721526651.133437503849345000050.500000000000480.0078070225779284142112control.avgo:1150.1814347239533350.8583372678695655000050.499999999999820.0024935012562968982113control.avgo:1250.3045497810149250.672034548272765000050.5000000000002067.90551008686205E-41114control.avgo:1350.398139483478350.600938986890355000050.499999999999672.518940347803474E-41115control.avgo:1450.44934731483212450.549629899517355000050.50000000000038.071623184942779E-51116control.avgo:1550.4736819550641550.526088173434595000050.499999999999992.566284350168338E-51117control.avgo:1650.4851047537443550.5188710217568945000050.500000000000128.191527862075119E-61118control.avgo:1750.4908242676411250.510006816411425000050.499999999999452.570199757692886E-61119control.avgo:1850.49481050576504550.505562213030885000050.50000000000038.197012224814065E-71120control.avgo:1950.49687636784203450.502964449510855000050.4999999999995242.640584231868471E-71121control.avgo:2050.49845790655890550.501820621462545000050.5000000000003348.565428611988968E-81122control.avgo:2150.4990554163528350.500964663746385000050.499999999999742.721171621666857E-81123control.avgo:2250.4994606147334750.5005536282529455000050.499999999999758.590349265230611E-91124control.avgo:2350.4997260227237650.5003155713704155000050.50000000000042.6248542064007986E-92125control.avgo:2450.499845060681650.500180533118785000050.500000000000058.845012874999227E-101126control.avgo:2550.49989479387425550.5000969239652165000050.500000000000791.864501428663076E-101227control.avgo:2650.499926798451250.5000561267856945000050.50000000000038.594896829690765E-111128control.avgo:2750.4999661317055250.500031986087625000050.500000000000171.9554527178661528E-111129control.avgo:2850.4999790306833350.5000191721642865000050.4999999999997663.274246411310768E-111130control.avgo:2950.4999895865393550.50000994096455000050.500000000000450.011Observer组件产生了很多数字,从第3列和第4列的数据(网络中的最大值和最小值),可以很容易地看到方差衰减得非常快,从第12个周期开始,几乎所有的节点都近似于真实的平均值50。可以用不同的数字或改变初始的分布(例如,使用aggregation.PeakDistributionInitializer)。同时,也可以替换覆盖网,比如你可以用Newscast来代替IdleProtocol。三.配置文件二第二个例子是前面例子的改进版本。现在aggregation协议将运行于Newscast并添加了一些扩展。例如,有一个Control对象用来改变网络的大小:在第5个周期至第10个周期间,每次调用时删除500个节点。01#PEERSIMEXAMPLE20203random.seed12345678900405simulation.cycles300607control.shfShuffle0809network.size500001011protocol.lnkexample.newscast.SimpleNewscast12protocol.lnk.cache201314protocol.avgexample.aggregation.AverageFunction15protocol.avg.linkablelnk1617init.rndWireKOut18init.rnd.protocollnk19init.rnd.k202021init.pkexample.aggregation.PeakDistributionInitializer22init.pk.value1000023init.pk.protocolavg2425init.ldLinearDistribution26init.ld.protocol127init.ld.max10028init.ld.min12930#youcanchangethistoincludethelinearinitializerinstead31include.initrndpk3233control.aoexample.aggregation.AverageObserver34control.ao.protocolavg3536control.dnetDynamicNetwork37control.dnet.add-50038#control.dnet.minsize400039control.dnet.from540control.dnet.until10在这里,全局参数与前面的例子相同,现在只讨论添加的扩展。11行到12行选择了Newscast协议,它唯一的参数是缓存的大小。Newscast是一个流行性的内容分布和拓扑管理协议,系统中的每个peer都有一个部份的节点信息(事实上是一个固定大小的的节点描述符(nodedescriptor)的集合),每个描述符是由peer地址和一个创建描述符的时间戳组成的元组。每个节点通过选择一个随机的邻居并交换信息来更新自身的状态,在交换信息时,两个peer归并信息并且只留下最新的项。在这种方式中,陈旧的信息(描述符)从系统中删除。这个过程允许协议修复覆盖网拓扑,用最小的代价删除死链,这种特性在一个节点频繁加入退出的动态系统中是很有用的。17到28行是初始化部分,与前面的例子相同,然而这里选择使用peak分布。为了将其转换为线性分布,在31行改变includeinit的属性。peak分布将用0初始化所有节点的值,除了取得value参数的那个节点除外。在36到40行,DynamicNetwork是定义的最后一个组件,如前所述,一个Control对象可以用来修改仿真中的一些参数,这种改变可以在每个仿真周期中进行(默认的行为),或者使用一种更好的途径。示例中选择的对象每次在control执行时删除500个节点。参数add指定了要添加的节点的数量,它可以是负值。而参数size则为网络大小设定了一个下限值,如果达到了下限,那不会再删除节点;参数from和until是一个可以为每个组件指定的一般化参数,它们指定了组件所要执行的周期,还有一个未使用的参数是step,如果是2,则表示每两个周期才执行一次。至于其它的参数则可以参考PeerSim的文档。四.高级配置特性高级配置特性由JavaExpressionParser提供,用于处理一些表达式。例如:01MAG202SIZE2^MAG0304AB+C05BD+E06CE+F07D108EF09F21011#等价于A=7,B=3,C=4,D=1,E=2andF=2.但是注意不允许递归定义。对于组件的集合,可以指定执行的顺序,默认是根据组件名的字母顺序来排序的,但也可以显式地覆写为:1control.connConnectivityObserver2control.myClassClass13control.1Class24order.observermyClassconn1如果不是所有的名字都出现在这个列表中,那些缺失的对象会按字母顺序执行,例如:1order.observermyClass会导致下面的运行顺序:observer.myClass,observer.1,observer.conn.另外一个特性是告知仿真器哪些项是允许执行的:1include.controlconnmyClass这样可以让control.conn和control.myClass以这种顺序执行,但如果这个列表为空,则什么都不会执行。PeerSim中文教程(2):编写一个新协议本文的目的是在PeerSim中用Cycle-based模型实现一个简单的负载均衡算法。节点的状态有两种值:本地负载(localload)和配额(quota),其中配额是指节点在每个周期中允许传输的“负载”的大小。配额是必要的,是一个时间单元中能传输的负载上限。每个节点与和它距离最远的邻居节点交换配额值,这里“距离最远”是指与当前节点的负载差异最大。经过对比距离,协议将在负载均衡时选用push或pull的方式。在每个周期之后,配额值将会被存储。协议并不关心拓扑管理,它依赖于其它组件来访问邻居节点(例如,Newscast,或者由IdleProtocol实现的静态拓扑)。一.必要的组件一般来说只编写一个协议类是不足够的,还需要一些附加的组件。例如,为了在每个周期结束时为每个节点存储配额值,需要一个特定的Control对象。基本上来说,PeerSim是一个可替换的组件集合,所以在开发时需要注意模块化以让代码尽可能重用,出于这样的目的,我们这样设计下面的类:\uf0b7protocol它基于peersim.vector.SimpleValueHolder,这是一个简单的基类,用于访问一个浮点变量。Aggreation协议也使用了同样的基类。\uf0b7ResetQuota用于在每个周期结束时存储每个节点配额的control。\uf0b7QuotaObserver一个control,用于监视quota参数,即覆盖网中交换的流量大小。\uf0b7initialization这是在aggregation示例中的初始化器,这里也可以直接使用,因为它们实现了同样的接口SingleValueHolder。注意在example包中提供的初始化器是轻量级的,开发者应当更多地使用peersim.vector.包中的初始化器。\uf0b7observers可以使用aggreagation.AverageObserver,因为这些组件实现了相同接口。下面将根据源代码来解释这一过程:01packageexample.loadbalance;0203importpeersim.config.Configuration;04importpeersim.config.FastConfig;05importpeersim.core.;06importpeersim.vector.SingleValueHolder;07importpeersim.cdsim.CDProtocol;0809publicclassBasicBalanceextendsSingleValueHolderimplementsCDProtocol{10protectedstaticfinalStringPAR_QUOTA="quota";1112/Quotaamount.Obtainedfromconfigproperty{@link#PAR_QUOTA}.13privatefinaldoublequota_value;14protecteddoublequota;//currentcyclequota1516//初始化17publicBasicBalance(Stringprefix){18super(prefix);19//getquotavaluefromtheconfigfile.Default1.20quota_value=(Configuration.getInt(prefix+"."21+PAR_QUOTA,1));22quota=quota_value;23}这个类需要实现peersim.cdsim.CDProtocol,它提供了一个nextCycle()方法,这个方法包含了协议的算法。而且,这个协议继承了SingleValueHolder类(它是SingleValue接口的实现),为内部变量提供getter和setter方法,允许control以可重用的方式来操作这些数据,在这个例子中,变量保存了节点的实际负载。在构造方法中的String参数是配置组件的全名,例如,对于LoadBanlance协议来说是protocol.lb。1//Resetsthequota.2protectedvoidresetQuota(){3this.quota=quota_value;4}resetQuota方法在每个周期结束时被一个control对象调用,显然地,一个恰当的control条目应该在配置文件中出现,这里是loadbalance.ResetQuota01publicvoidnextCycle(Nodenode,intprotocolID){02intlinkableID=FastConfig.getLinkable(protocolID);03Linkablelinkable=(Linkable)node.getProtocol(linkableID);04if(this.quota==0){05return;//quotaisexceeded06}07//thistakesthemostdistantneighborbasedonlocalload08BasicBalanceneighbor=null;09doublemaxdiff=0;10for(inti=0;imaxdiff){20neighbor=n;21maxdiff=d;22}23}24if(neighbor==null){25return;26}27doTransfer(neighbor);28}这个方法是由CDProtocol接口声明的,它定义了协议的行为。这里的参数代表了一个对节点自身的引用(即仿真器调用其nextCycle方法的那个节点)和正在运行的协议的protocolID。首先我们要取得实现了Linkable接口的协议的protocolID来访问节点的邻居节点,这可以由下面的代码来完成:1intlinkableID=FastConfig.getLinkable(protocolID);2Linkablelinkable=(Linkable)node.getProtocol(linkableID);使用静态类peersim.config.FastConfig我们可以取得为正在执行的协议而配置的linkable协议的protocolID。如果本地的配额是0,代表着这个节点已经使用完网络流量,所以直接return。为了取得与本地节点距离最远的节点,我们循环遍历所有邻居节点的负载值;邻居节点的数量等于节点的度(这可以通过linkable接口来访问),通过linkable接口来取得节点的代码如下:1Nodepeer=linkable.getNeighbout(i);而从这个节点就可以取得BasicBanlance协议:1BasicBalancen=(BasicBalance)peer.getProtocol(protocolID);当协议寻找到一个合适的邻居节点后,调用doTransfer方法来进行负载均衡。01protectedvoiddoTransfer(BasicBalanceneighbor){02doublea1=this.value;03doublea2=neighbor.value;04doublemaxTrans=Math.abs((a1-a2)/2);05doubletrans=Math.min(maxTrans,quota);06trans=Math.min(trans,neighbor.quota);07if(a1<=a2){//PULLphase08a1+=trans;09a2-=trans;10}else{//PUSHphase11a1-=trans;12a2+=trans;13}14this.value=a1;15this.quota-=trans;16neighbor.value=a2;17neighbor.quota-=trans;18}doTransfer方法将会在当前节点和由参数指定的邻居节点间进行实际的负载交换,它决定了在负载均衡时是用pull还是push方法:在Push的情况下,本地值增加而其它节点的值减少,在push情况下则反之。maxTrans变量是两个涉及的节点需要达到平衡而传输的负载的绝对值;由于配额(quota)是每个周期中传输的上限,这个算法将会选择quota和maxTrans中的最小值,最后两个节点都会减去相同数量的负载值。二.负载均衡的control类代码01packageexample.loadbalance;02importpeersim.config.;03importpeersim.core.;0405publicclassResetQuotaimplementsControl{06//参数07privatestaticfinalStringPAR_PROT="protocol";0809/Valueobtainedfromconfigproperty{@link#PAR_PROT}.10privatefinalintprotocolID;1112//初始化13publicResetQuota(Stringprefix){14protocolID=Configuration.getPid(prefix+"."+PAR_PROT);15}1617publicbooleanexecute(){18for(inti=0;i=average&&n.value>=average)15continue;16if(value<=average&&n.value<=average)17continue;18doubled=Math.abs(value-n.value);19if(d>maxdiff){20neighborNode=peer;21maxdiff=d;22}23}24returnneighborNode;25}01privateNodegetUnderloadedPeer(Nodenode,intprotocolID){02intlinkableID=FastConfig.getLinkable(protocolID);03Linkablelinkable=(Linkable)node.getProtocol(linkableID);04NodeneighborNode=null;05doublemaxdiff=0.0;06for(inti=0;i=average&&n.value>=average)14continue;15if(value<=average&&n.value<=average)16continue;17doubled=Math.abs(value-n.value);18if(d0){10Nodepeern=linkable.getNeighbor(11CommonState.r.nextInt(linkable.degree()));12//XXXquickanddirtyhandlingoffailures13//(messagewouldbelostanyway,wesavetime)14if(!peern.isUp())15return;16AverageEDpeer=(AverageED)peern.getProtocol(pid);17((Transport)node.getProtocol(FastConfig.getTransport(pid))).18send(node,peern,newAverageMessage(value,node),pid);19}20}在这里要观察的是event-based模型中的方法,即如何处理传输层。首先,FastConfig类让我们能访问为这个协议配置的传输层,通过使用这个传输层,我们可以在其它节点上将消息发送给协议。一条消息可以是任意的对象,由于这个仿真器并不是分布式的,所以不用处理序列化等等问题;而对象则会通过引用来存储。目标协议是由目标节点peern定义的,协议的标识符则是pid,在这个例子中,我们在一个不同的节点发送消息给同一个协议。显然,目标协议应当实现EDProtocol接口。01/02Thisisthestandardmethodtodefineto03processincomingmessages.0405publicvoidprocessEvent(Nodenode,intpid,Objectevent){06AverageMessageaem=(AverageMessage)event;0708if(aem.sender!=null)09((Transport)node.getProtocol(FastConfig.getTransport(pid))).10send(node,aem.sender,11newAverageMessage(value,null),pid);1213value=(value+aem.value)/2;14}15}上面实现的是EDSimulator中的方法,它用于处理进入的消息。本例中,消息只有一种类型,我们只需要检查sender是否为null,因为如果为null,则我们无需应答消息(当然,实际上这已经是一种“应答”),而如果需要应答时则是通过传输层来处理。01/02Thetypeofamessage.Itcontainsavalueoftypedouble03andthesendernodeoftype{@linkpeersim.core.Node}.0405classAverageMessage{06finaldoublevalue;0708/Ifnotnull,09/thishastobeanswered,otherwisethisistheanswer.10finalNodesender;1112publicAverageMessage(doublevalue,Nodesender){13this.value=value;14this.sender=sender;15}16}这个私有类是协议所使用的消息类型,说其私有是因为没有任何其它组件需要处理这种类型的消息。3.配置文件配置文件与Cycle-based的配置相似,只有很少地方不同,但这些区别很重要。01#networksize02SIZE100003#parametersofperiodicexecution04CYCLES10005CYCLESIZE1000006#parametersofmessagetransfer07#delayvaluesherearerelativetocyclelength,inpercentage,08#eg50meanshalfthecyclelength,200twicethecyclelength,etc.09MINDELAY010MAXDELAY011#dropisaprobability,0<=DROP<=112DROP0这里定义了一些常量以让配置文件更清晰,同时也更易于在命令行中修改,例如,CYCLE定义了一个周期的长度。1random.seed12345678902network.sizeSIZE3simulation.endtimeCYCLECYCLES4simulation.logtimeCYCLE在这里,simulation.endtime是最关键的参数,它通知仿真器何时终止。PeerSim用一个64位的long长整型来表示时间,在启动时它为0,并且由消息的延迟来推进。在事件队列为空,或者队列中所有的事件的调度时间都迟于终止时间时,仿真将会终止。仿真器将在标准错误窗口打印时间的进度,simulation.logtime指定了打印这些消息的频率。01###################protocols===========================02protocol.linkpeersim.core.IdleProtocol03protocol.avgexample.edaggregation.AverageED04protocol.avg.linkablelink05protocol.avg.stepCYCLE06protocol.avg.transporttr07protocol.urtUniformRandomTransport08protocol.urt.mindelay(CYCLEMINDELAY)/10009protocol.urt.maxdelay(CYCLEMAXDELAY)/10010protocol.trUnreliableTransport11protocol.tr.transporturt12protocol.tr.dropDROP在这里我们配置了协议(avg),指定了覆盖网络(link)和传输层(tr),同时也需要指定step参数,这与cycle-based模型是相似的。这是由于我们实现了cycle-based接口,所以我们需要指定一个周期的长度以使用它。覆盖网络只是一个links的容器,在仿真过程中会保持不变,它会按如下初始化:传输层也被视为一个协议进行配置的,它对随机延迟和消息丢失进行了建模。首先我们定义了一个拥有随机延迟(urt)的传输层,然后将它封装在一个通用的传输层包装器中,并以给定的概率tr来丢弃消息。传输层被定义在peersim.transport包中,和其它组件一样,它也是模块化的,用户可以简单地开发和使用一个新的传输层协议。01###################initialization======================02init.rndlinkWireKOut03init.rndlink.k2004init.rndlink.protocollink05init.valsLinearDistribution06init.vals.protocolavg07init.vals.maxSIZE08init.vals.min109init.schCDScheduler10init.sch.protocolavg11init.sch.randstart在这里唯一属于event-based模型范畴的是sch,它对cycle-based接口(nextCycle)的周期性调用进行调度,在这个配置中,这个组件首先会在0到CYCLE的时间内给所有的节点赋一个随机的点,这是在协议avg上第一次调用nextCycle。而下一次的调用将严格地发生在恰好CYCLE的时间间隔之后。更多之前(advanced)的方法也会存在,除此之外,这个调度可以通过类的扩展进行自定义,但在这里不作详述。1################control==============================2control.0SingleValueObserver3control.0.protocolavg4control.0.stepCYCLE注意和协议avg一样,我们也需要指定step参数,它指定了这个control多久会调用一次,否则controls能像cycle-based模型那样进行调度,只是没有默认的step,因为这里没有周期。4.运行协议如果我们用上面的配置文件运行仿真,我们将在标准错误窗口中得到输出:01Simulator:loadingconfiguration02ConfigProperties:Fileconfig-edexample.txtloaded.03Simulator:startingexperiment0invokingpeersim.edsim.EDSimulator04Randomseed:123456789005EDSimulator:resetting06Network:nonodedefined,usingGeneralNode07EDSimulator:runninginitializers08-Runninginitializerinit.rndlink:classpeersim.dynamics.WireKOut09-Runninginitializerinit.sch:classpeersim.edsim.CDScheduler10-Runninginitializerinit.vals:classpeersim.vector.LinearDistribution11EDSimulator:loadedcontrols[control.0]12Currenttime:013Currenttime:1000000014Currenttime:2000000015Currenttime:3000000016Currenttime:4000000017Currenttime:5000000018.19.20.21Currenttime:98000000022Currenttime:99000000023EDSimulator:queueisempty,quittingattime999980413标准输出窗口的输出如下:01control.0:1.01000.01000500.583416.666666666671102control.0:37.5919.01000500.525724.1590912506871103control.0:206.7109375767.8906251000500.58096.8070368893891104control.0:352.373046875695.4531251000500.52578.0225731761351105control.0:412.430419921875625.4746093751000500.5801.10821794468311106control.0:436.43787479400635570.4598584175111000500.5243.539940727629021107control.0:470.7608990445733527.03598450322171000500.4999999999999474.137886745643831208control.0:483.6040476858616518.03010556846861000500.4999999999990323.4289743016775561109control.0:490.5196089811798512.03014718577791000500.49999999999937.2855664195970191110control.0:494.97216907397836506.03759541808541000500.49999999999992.17982993074422461111control.0:497.18190345272336503.58371444605321000500.50000000000010.60731488383362061112control.0:498.54320551492475502.35331565589031000500.50.17867944354458981213control.0:499.4023441821402501.49620484861041000500.499999999999660.0552576075406377851114control.0:500.0032071191514501.098329367096771000500.49999999999950.0179148659840024821115.16.17.18control.0:500.5500.51000500.50.010001000这些值分别代表最小值,最大值,样本的数量,平均数,方差,最小值实例的数量,最大值实例的数量。这个输出代表已经找到正确的平均数500.5,方差为0,即所有的节点都拥有相同的正确的平均值。这看上去很不错,我们可以添加一些延迟并观察一下会发生什么(在默认的配置文件中delay是0),如果在命令行中添加MINDELAY=10和MAXDELAY=10(即表示所有的消息都会恰好延迟10%的周期时间),我们将会得到:1.2.3.4control.0:499.126081326076499.1260813260761000499.126081326088070.0100010005control.0:499.126081326076499.1260813260761000499.126081326088070.0100010006control.0:499.126081326076499.1260813260761000499.126081326088070.010001000也就是说,简单的延迟方案已经破坏了这个协议的良好属性:尽管是收敛的,但结果不正确,还可以验证不同的随机种子将会导致不同的结果,而改变延迟的和丢失率也对性能有影响。那么,将延迟和丢失率保持为0能保证得到正确的行为吗?不一定。下面用更短的周期长度来进行实验,例如,CYCLE=SIZE,这意味着在同一个时间点一般有更多的事件调度发生,在这样的情况下,PeerSim以随机的顺序来执行这些事件,我们将得到:1.2.3.4control.0:500.4835099381911500.48350993819111000500.483509938186057.807634196601234E-9100010005control.0:500.4835099381911500.48350993819111000500.483509938186057.807634196601234E-9100010006control.0:500.4835099381911500.48350993819111000500.483509938186057.807634196601234E-910001000结论是什么?必须指出,这个错误的结果是由于时间分辨率(timeresolution)不足导致的。如果消息的确是零延迟的,那么执行时间的微小差别也会导致不重叠的成对交换,很明显,在连续的时间上没有事件会在相同的时间点执行。然而,在消息传送时微小的随机延迟让结果变得很有意义,因为顺序的不确定性是确实存在的。大体而言,使用event-based模型能看到很多在cycle-based模型中看不到的问题,然而,这也会引入一些假象。5.说明这个例子仅是为了入门,推荐进一步学习相关文档,如peersim.edsim,peersim.transport等。',)


  • 编号:1700774090
  • 分类:其他文档
  • 软件: wps,office word
  • 大小:45页
  • 格式:docx
  • 风格:商务
  • PPT页数:1156608 KB
  • 标签:

广告位推荐

相关其他文档更多>