没有合适的资源?快使用搜索试试~ 我知道了~
91《理论计算机科学电子札记》65卷第4期(2002)网址:http://www.elsevier.nl/locate/entcs/volume65.html15页异构软件构件克劳斯-彼得ohr1;2研究所furInformatikFreieUniversitat Berlin14195 Berlin,Germany摘要提出了一种基于异构构件的软件组合方法。重点是交互风格的异质性。组件的接口以抽象的方式描述,隐藏了组件的实际交互风格。这允许自动生成在不兼容的样式之间进行调解的代码,从而避免了手动构造包装器的需要1介绍组合式软件开发仍然由于明显缺乏一个普遍接受的“组件”定义而失败。我们可以认为,标准化将在适当的时候解决这个问题。然而,本文的前提是,不同种类的组件和相互竞争的标准将继续存在,这就提出了如何缓解随之而来的异质性问题的问题。1.1交互风格可能所有组件定义中最小的公分母是“一个具有良好定义的接口的黑盒子”。界面的性质是这一定义的关键点。组件可以通过多种方式与环境交互例如,考虑一个Java对象(具有数据抽象的特征)和一个Unix lter程序。两者都代表黑盒,向外部世界提供定义良好的接口;但是对象的类型化调用接口与基于输入/输出通道的lter的非类型化数据流接口这些都是1 部分工作是在作者在加州大学圣巴巴拉分校休假期间完成的2 电子邮件地址:lohr@inf.fu-berlin.de2002年由ElsevierScienceB出版。 诉操作访问根据C CB Y-NC-N D许可证进行。LoHR92相当简单的组件。当代组件技术的典型组件模型包括更精细的组件交互,具有基于事件的通信,并且通常提供定制配置的方法;此外,组件平台通常通过容器提供一组标准化服务[9,10,14]。在软件架构中,任何给定类型的组件交互都被称为建立某种架构风格[13]。这种风格可能符合也可能不符合一些小型编程的范例。与Unix过滤器的交互,或基于事件的交互,肯定与流行的面向对象编程不太接近。另一方面,任何数据流风格都与懒惰函数式语言中的流处理密切相关。组合或协调语言的支持者认为,组件应该使用特殊的语言来组合,这些语言反映了大规模编程的需要[1]。在从现有组件开发软件时,我们可能不得不适应具有不兼容交互风格的异构组件,例如,因为要利用遗留软件或者因为要使用现成的组件。小规模的例子再次说明了这种情况。例如,假设我们正在使用Java实现一个必须进行文本抑制的系统。Java库没有任何合适的东西,但我们发现Unix awk实用程序可以完成这项工作。不幸的是,awk没有面向对象的接口;所以我们会尝试设计一些包装方案,也许使用线程,进程间通信等。这是一种被称为架构不匹配的麻烦情况[4]:根本没有简单的即插即用;需要在不兼容的交互风格之间进行费力且容易出错的调解。请注意,问题的根源不仅仅是编程语言的异构性(实际上,awk也可能是用Java编写的)-它是交互异构性。如果一个组件和它的环境在交互风格上达成一致,那么它们可以使用任何可以看到的实现语言。这些差异可以通过编译器或一些合适的中间件来消除:对于流行的风格,对象调用,这可以通过微软的二进制.NET平台[8]或OMG的CORBA标准来实现,该标准使用规范的接口描述语言(IDL)[11]。但是,如果组件和它的环境不能就共同的交互风格、对象调用或其他方面达成一致,那么这种1.2多范式语言?可以说,在软件系统中支持不同交互风格共存的最好方法是提供多范式语言。这些语言确实有其优点,例如,在调和对某些范例(比如,函数式编程)的偏见但也有缺点:多范式编程比坚持单一范式更难;它LoHR93也可能有损于干净的统一范式编程的美丽。即使是像一元编程这样的技术,尽管干净地集成到函数式编程范式中,也可能遇到阻力。最重要的是,遗留系统和现成的组件只是“照原样”出现,配置的可能性有限,当然也不可能调整它们的交互风格。1.3使用抽象接口显然,在不同的交互风格之间进行中介的代码中,一定会出现一些风格/范式的“肮脏”混合。但是,也可以自动生成代码,如远程调用的存根生成所示。使用这种方法,人类将永远不会关心编写多范式包装器代码。如果不同类型的组件之间的中介要通过使用工具来自动化,那么解决方案必须基于正式的接口描述-只有这些才必须从给定组件的实际交互风格中抽象出来。现在,在最抽象的层次上,组件的简化模型只是一个状态机,最基本的交互类型是输入或输出事件。因此,接口描述必须列出这些事件,包括它们的(类型化的)参数。基于给定的样式和语言映射,生成器工具将处理接口描述并为组件生成代理(环境端存根)。因此,将生成组件的驱动程序(组件端存根)。代理和驱动程序通过中介通道进行通信,使用特定的消息交换协议。图1b)给出了如何通过使用一些包装器代码来容纳外来组件的概念视图。图1c)给出了一个更技术性的描述:外来组件通常位于一个单独的地址空间中;包装器被实现为代理和驱动程序,加上进程间通信软件。进程间通信是本地的还是涉及网络消息是次要问题。CC司机代理CC包装器Ca) 同质性:绿色环境中绿色成分b) 异质性:绿色环境c) 使用代理、驱动程序和中介通道Fig. 1. 均质与异质(“红/绿”)相互作用请注意,我们对系统组成的看法集中在一个组件上,LoHR94时间;术语“环境”是指所有其他组件加上组合代码(有时称为粘合代码或脚本[1]),描述系统如何由其组件组成,遵守某种交互风格(图1中的“绿色”)。①的人。连接符,通常被认为是必不可少的组成,没有明确的。我们认为连接器是组合代码的一部分,无论是文本还是图形。对用于组合代码的语言没有先验限制例如,Shell代码,特殊脚本代码,面向对象的代码等也同样可以接受。不要将中介与网络上的远程调用混淆,这一点很重要:我们确实有单独的地址空间;但是1)调用只是交互的一种特殊情况,2)通常不需要物理分布第2节将介绍用于描述抽象接口的简单实验语言AID,并将抽象事件与具体交互联系起来。代理和驱动程序的行为将在第3节中针对几种交互风格进行示例。第4节给出了实验性实现的草图,第5节将讨论相关工作。2抽象界面和具体交互风格我们从顺序组件开始;并发性将很快解决我们经常使用“组件”来表示“组件类型”或“组件实例”(如“类”与“对象”)。如果没有明确规定,预期的含义应该从上下文中显而易见。2.1组件接口描述一个顺序组件可以被看作是一个状态机。它与环境的交互被建模为输入和输出事件。观察到的行为是一系列这样的事件。因此,如果S表示状态集,则组件的行为由两个映射确定在:I S!S,出:S!苏,其中I和O是输入/输出值的集合。一个组件的用户当然必须知道它的接口和它的行为。但是,出于自动中介的目的,我们只关心组件的静态语义,如类型化接口所给出的。下面是一种名为AID的语言的简单具体语法,它将被用于一个baseI接口描述:Interface =interface Identi erf EventTypeg EventType = InOut Identi erf Type g类型=标识符LoHR95InOut =inj out接口被命名,事件类型和给定的基元类型也被命名接口的输入事件类型(in)构成一个简单的代数类型,事件标识符充当构造函数;I是该类型的值的集合。类似地,O是由输出eventty pes(out)定义的代数类型的值的集合。一个事件则 是一个来自I S S su c h的三元组(i;s;s0),其中in( i;s)=s0(对于输入)或(s;s0;o)来自SSOsuchthatout(s)=(s0;o)(对于输出)。只要输入标识符和输出标识符的集合是不相交的,这就捕获了接口的语义。 如果输入事件类型和输出事件类型具有相同的名称,则这指示相应类型的输入和输出事件之间的对应关系:输入事件在组件和其环境之间建立连接;将存在与连接相关联并终止连接的对应输出事件。同步调用是这种方法的典型实现(尽管不是唯一可能的)。AID的初始版本不支持允许根据某些协议进行多事件交互的长期连接并发组件可以表现出并发的输入/输出事件和不能由确定性状态机建模的行为。然而,接口并不受此影响。2.2推与拉行为组件接口描述是抽象的,因为它们与交互风格无关。请考虑以下示例:初始化中接口目录在输入字符串时,in lookup字符串out lookup输出计数out同义词String String我们可能会怀疑这个接口背后的组件只是一个实现面向对象接口的对象(或类),例如(在Java中)intn= nums();void enter(String name,intnumber); int lookup(Stringname);int count();LoHR96G注意,忠实于抽象接口的实现将提供异步操作初始化和输入,而查找和计数将是同步的。但是,如果同义词是为了发出信号,比如说,检测到两个名字映射到同一个数字,那么它将如何实现呢这可能直接发生在输入之后,也可能发生在任意以后的时间。在基于调用的上下文中,它必须实现为对之前传递给组件的某个对象的调用,例如,作为实例化时的参数这表明,进出组件的信息可以由环境或组件本身触发。如果信息流是由信息源触发的,这被称为推送式(或数据驱动式);如果它是由目的地触发的,这被称为拉式(或需求驱动式)。在上面的Java示例中,inenter、inlookup和out同义词是以push样式实现的,而out lookup和out count是以pull样式实现的。请注意,抽象接口也可以以非常不同的方式实现,例如,通过I/O通道与其环境通信的进程,对入事件使用读操作,对出事件使用写操作在这种情况下,输入和查找是以拉式实现的,而输出查找,输出计数和输出同义词是以推式实现的。还有其他推/拉组合是可能的。关键是,任何push/pull组合都可能隐藏在抽象接口后面;接口并没有告诉我们任何关于这一点的信息。2.3打字问题中间件IDL编译器基于IDL和给定实现语言之间的语言映射所有的问题都涉及到抽象接口。其他的复杂性是由交互风格的抽象引起的,但它们与类型问题几乎没有关系这是因为我们坚持抽象接口中的每个事件类型与实现中的交互端点(过程、方法、端口、通道、事件处理程序 等 ) 之 间 存 在 一 一 对 应 的 关 系 例 如 , 不 可 能 通 过 两 个 操 作voidswitchOn()和void switchOff()来实现switch Boolean中的事件类型。应该注意的是,将事件的参数打包到实现语言的某些复合数据对象中是经常需要的,这仅仅是因为不是每个事件类型都有允许任意数量参数的实现。但是,这是IDL编译中的一种众所周知的技术,不会引起新的问题。LoHR973将事件映射到交互我们解决的问题,如何映射抽象的事件,具体的interrac- tions通过研究四个不同的交互风格的例子:类型化的对象调用,非类型化的字节流,功能流和事件系统。为了避免混淆,应该注意的是,“事件系统”与发送和接收事件通知有关;“事件”在此上下文中是一个未定义的术语,并且不要与上面介绍的抽象事件混淆。抽象事件将被映射到发送或接收“事件通知”的交互。3.1类型化对象调用面向对象程序是以命令式风格编写的;交互机制是调用。命令式编程工作在一个相当低的抽象层次上,允许程序员在推式和拉式交互版本之间进行选择如上所示的AID规范不会告诉代理/驱动程序生成器任何关于推和拉的信息。必须以push/pull注释的形式提供附加信息:接口描述中的事件类型可以在push或pull之前,如接口目录push in输入字符串...用于代理或驱动程序生成的目的默认值是pushforin事件和pullforout事件,这对应于通过接口与对象进行的“正常”交互对于推出交互,环境提供了一个侦听器对象供组件调用。生成的代理将有一个构造函数,该构造函数使用每个pushout事件的侦听器进行参数化;它的类型(用Java的说法)是一个接口类型,具有一个方法。在这种情况下,代理和驱动程序的角色颠倒了:代理中的线程负责代表组件调用侦听器。对于拉入交互,代理将使用提供者对象,其方法必须返回组件请求的数据。在组件方面,驱动程序必须以类似的方式构建:如果组件具有推出或拉入交互,则驱动程序将实现适当的接口。如果组件及其环境的推/拉行为不匹配,则将发生非平凡的中介。代理和驱动程序将从两个接口描述中生成,这两个接口描述在推/拉注释中有所不同。每个事件可能有四种组合:LoHR98代理驱动程序推入拉入推出拉入推入推出拉出其中前两个发生在双方积极参与信息流入/流出组件时。 因此,存根必须具有缓冲能力:由组件或环境推送的数据必须分别由代理或驱动程序缓冲上述最后两个组合更棘手。如上所述,代理调用参数对象;驱动程序调用组件。为了真正使信息流出,在代理中留出一个线程,它从提供者(拉入)拉取数据并将其发送给驱动程序,驱动程序反过来调用组件(推入)。 类似地,在驱动程序中留出一个线程,该线程从组件中提取数据(pullout)并发送数据”“是的,是的。 CORBA专家将被提醒用于CORBA事件通道的推/拉使用的机制[10]。3.2非类型化字节流通过消息通道的任务间通信存在于许多变体和不同的上下文中,从高级编程语言到操作系统支持的二进制机制。选择一个简单的例子,仍然可以使要点,我们考虑二进制Unix标准:一个组件是一个进程,它与它的环境交互使用读/写操作的通道。(回想一下,被称为管道的简单线性配置已经产生了术语“管道和”,过滤器架构。)一个Unix程序(如果它是通过Shell启动的)可以依赖于三个标准通道的可用性,stdin用于输入,stdout,stderr用于输出。设计一个合适的界面,接口UnixProcessinstdin Stringout stdout Stringout stderr String,提出了一个关于参数类型的问题。虽然I/O机制仅处理无类型字节流(以及一些应用,例如,压缩程序可以做同样的事情)许多应用程序处理可打印的字符或甚至字符串。一个典型的交互式程序将与LoHR99一B代理C一BB包装纸CBB驱动程序逐行地识别其环境,识别以行分隔符终止的字符串这将证明上面选择的类型是正确的;但是其他类型,例如,选择字节而不是字符串是可能的。许多交互式程序都是命令解释器类型的:输入行以命令名开头,命令名后面可能跟着参数;响应命令,程序可能产生也可能不产生某些输出。在这种情况下,环境可能希望将不同的命令视为不同的事件类型。存根生成器通过接受任意接口定义来支持这一点标准标识符stdin、stdout、stderr保持了它们的含义,并且不会传递到组件或从组件传递。请注意,此处不提供不同的推/拉选项。读操作总是一个拉入交互,写操作总是一个推出交互,仅此而已。所以存根生成器处理一个纯接口描述,如上所示;任何推/拉都被忽略。所生成的代理与其环境通信(例如,管道),并通过中介通道与其对等体驱动程序进行交互。这在图2a中示出,其中假定驱动程序以某种其他方式与组件通信。代理驻留在一个单独的地址空间中的事实无论如何都表明了一种优化:将代理和驱动程序合并到一个单独的包装器中,该包装器连接到组件的地址空间中(图1)。2b)。a) b)优化的图二、管道和过滤器环境中的外来组件(! =通过管道的数据流交互,$=中介通道)3.3职能流状态的概念在纯函数式编程中并不存在。然而,列表的惰性评估允许流处理函数的众所周知的设备如果提供一个“状态”参数,这样的函数代表一个有状态的组件;列表项的消费和生产代表I/O事件。惰性评估是由需求驱动的,LoHR100到拉入/拉出交互模式。与3.2类似,其他模式不可用,AID中的任何推/拉都被忽略。功能代理和功能驱动程序都必须能够通过中介通道进行通信。这可以通过一元输入/输出代码来实现,无论是显式的还是隐式的。支持隐式I/O,例如,由Haskell库函数interact::(String->String)->IO()从/向标准I/O通道读取/写入由其参数处理的字符[5]。如果interact与中介通道上简单的、基于字符串的外部数据表示形式结合使用,则事件将由其名称表示,后跟参数值(作为字符串)。考虑2.2节示例的简化版本,仅支持输入和查找,让模块Directory包含流处理函数目录。从抽象组件接口生成的驱动程序如下所示:模块Main,其中import目录main=interactinters= unlines。地图输出。目录.地图输入。地图文字线input[“lookup”,p1]=p1 input[“enter”,p1,p2]=输入p1(读取p2)输出(p1)=“lookup”++““++show p1使用函数input和output执行参数un/marshalling,基于代数类型,构造函数Enter和Enter用于输入到目录,类型构造函数Enter用于从目录输出。包括模块Main和Directory的程序,虽然是作为某个更大系统的组件,但由于人类可读的外部数据表示,当然可以由人类交互地使用如果我们忘记它的实现,只考虑它的交互,我们看到的是一个Unix风格的组件。因此,如果程序要在Unix环境中使用,则不需要代理。或者,我们可以将模块Main看作是合并的代理和驱动程序,如图所示2 b.将Haskell组件与命令式(即,基于调用的)组件是一种在命令式编程和函数式编程之间进行中介的方法。Haskell a cionados可能想将这种方法与基于单子的“从天堂呼叫地狱,从地狱呼叫天堂”[3]进行比较。3.4事件系统:CORBA通知服务对基于事件的交互的编程语言支持是罕见的;在实时语言中可以找到有限的形式。基于事件的通信infras-LoHR101然而,结构越来越重要。一个主要的例子是CORBA通知服务[10,2],它是早期事件服务的扩展。该服务可通过几个接口(在IDL中指定)获得;它允许客户机通过调用事件通道(不应与1.3中引入的中介通道混淆)上的操作进行间接交互。客户端和通道对象之间的数据流既可以是推送模式,也可以是拉取模式;事件的提供者和消费者之间的混合模式也是可能的。基本的事件提供和消费是通用的:事件通知通过事件通道输出的数据不是静态类型的(即,它们的IDL类型是any);一般的推和拉操作用于提供和消费任何事件3。一个事件式的组件代理将自己表现为一个常规的事件提供/消费组件,同时秘密地与一些真正的组件的驱动程序进行通信,这些驱动程序可能对CORBA组件一无所知,并且可能使用完全不同的交互方式。AID中指定的抽象事件类型来自四种调用事件(显示为IDL签名):(输入事件)在消费者推送(在任何数据中)渠道;任何对供应商代理的pull()sumer;(输出事件)在消费者代理推送(在任何数据中)钳子;事件通道调用的对供应商的任何pull()。每个调用都涉及某个事件通道。通道与其客户端之间的连接可以以不同的方式设置。例如,客户端可以使用HTTP服务连接到已知的现有通道。让我们假设连接是在初始化阶段建立的,并且之后没有改变。对于这种行为,抽象事件类型与来自命名通道的输入事件(或到某个通道的输出事件)相关联。例如,侦听通道“sensor“并在通道“alarm“上生成新事件的事件过滤器的抽象接口Threshold可以指定为传感器中的接口阈值任意报警任何3 通知服务还支持类型化事件和结构化事件;这里不考虑这些。LoHR102这从实现实际用于提供和消费事件的模式(推送或拉取)中抽象出来。 如果确实要从接口生成CORBA环境的代理或驱动程序,则必须以3.1中所示的相同方式添加注释推/拉。重要的是要记住,AID事件名称(如传感器或警报)的解释取决于通道及其客户端配置的设置风格。不同的样式需要不同的存根生成器-或者使用指示样式的参数的生成器CORBA组件[9]是通知服务客户端的示例,其基于事件的互连是通过关联事件源和事件接收器来建立的将事件源和事件接收器作为组件的特殊端口,增强了组件使用的可扩展性。它还允许与AID规范进行更直接的对应,因为不必显式地处理事件通道。因此,IDL规范分量阈值f消耗SensorEvent温度;发布AlarmEvent警告;g;将对应于AID规范接口阈值在温度传感器事件中输出警告AlarmEvent我们不再进一步探讨这个问题;在异构体系结构中完全处理CORBA组件超出了本文的范围。4实验性实施代理和驱动程序之间的中介通道的一个非常简单的实现已经被选择用于AID方法的实验评估:一对Unix管道提供基本的传输服务;事件通知,阳离子作为包含事件名称及其参数的消息发送在文本表示中。用于代理和驱动程序的实验性存根生成器可用于第3.1 - 3.3节中描述的交互风格。对于Java对象调用,生成器识别push/pull注释并生成适当的代码。组件实例化涉及到创建一个进程,该进程充当组件实例及其驱动程序的载体。环境,存在LoHR103rst负责组件实例化,它实例化组件的代理。然后,代理创建一个新进程,建立输入和输出到该进程的管道,并使该进程加载组件及其驱动程序。5相关工作命令式范式是软件开发中的流行风格,既适用于小型编程(基于语句),也适用于组件交互(基于调用)。因此,现有的研究大多局限于祈使句范式。纯命令式设置中的不同推/拉模式可以通过中介(如3.1中所述)或源代码修改(如果源代码可用)来适应。后一种方法相当于M.杰克逊[7]。在[6]中描述了用于程序转换以消除推/拉失配的自动过程代码转换具有运行时效率高的优点但是中介方法独立于任何源代码(可用性、语言等),具有适用于任何类型的遗留软件的优点。在[15]中提出了一种在不兼容的抽象交互协议之间进行中介的半自动方法:在组件之间插入适配器。与国际援助一样,这一方法不受强制性范式的约束。AID处理输入/输出事件的方式与该论文的协议规范方法有关,但尚不支持协议的概念。另一方面,AID提供了完全自动的存根生成,在非常不同的交互风格的存在。类似于Yellin和Strom的适配器已经被建议用于具有不兼容同步属性的并发组件[12],并且已经应用于命令式组件。6结论现实世界的组件通常是复杂和不规范的。因此,建立适当的AID规范可能并不容易。 如果没有存根生成器,它甚至没有意义,例如,因为该组件展现出不保证构造生成器的任务的罕见或独一无二的交互风格。除了交互接口之外,组件还有很多其他功能:定制、管理接口、容器、部署等。本文并不声称解决了世界上所有组件模型的通用互操作性问题AID技术代表了一种轻量级的、实用的方法来处理组件异构性不兼容交互风格的一个重要方面。它应该适用于任何风格-除了给定的例子-这是基于黑盒组件和信息流通过一个良好的界面。LoHR104上面介绍的技术和实验性实现的不足是显而易见的:基本的类型系统 , 原 始 的 通 信 基 础 设 施 , 缺 乏 配 置 支 持 , 对 CORBA 、 EJB 、COM、.NET等中的标准组件模型的因此,在对抽象接口的实际可行性做出安全声明之前,需要调查的问题并不缺乏。AID有意保持简单;这允许快速验证几个发电机作为概念验证。感谢Karsten Otto和Volker Siegel对先前草稿的评论帮助改进了演示文稿,并表示感谢。引用[1] F. Achermann,O. Nierstrasz,应用=组件+负载,M中。Aksit(编辑):软件体系结构和组件技术。 Kluwer2001.[2] G. Brose , A. Vogel , K. Duddy , Java Programming with CORBA ( 3.ed.),Wiley 2001.[3] S. Finne,D. Leijen,E. Meijer,S. Peyton Jones,Calling hell from heaven andheaven from hell,Proc. ICFP '99,ACM 1999.[4] D. 加 兰 河 Allen , J. Ockerbloom , Architectural mismatch : Why Reuse is sohard,IEEE Software 12.6,1995年11月,第17-26页。[5] S. 佩顿·琼斯等人, Haskell 98: 一 种 非 严 格的 纯 函 数 式 语 言,http://www.haskell.org/onlinereport[6] D. Heuzeroth,W. Lowe,A. 路德维希,联合阿斯曼,面向方面构件通信的配置与适应,第三届国际生成式和基于代理的软件工程会议(GCSE),2001年,LNCS 2186,58-69。[7] M.A. Jackson,Principles of Program Design,Academic Press 1975.[8] Microsoft Corporation,.NET开发,2001年,http://msdn.microsoft.com/net[9] 对象管理组,CORBA组件,1999年3月。ftp://ftp.omg.org/pub/docs/orbos/99-02-05.pdf[10] 对象管理组,CORBA通知服务,2000年6月,http://www.omg.org/technology/documents/formal/notificationservice.htm[11] 对象管理组,CORBA 2.4 规范,http://www.omg.org/technology/documents/formal/corbaiiopLoHR105[12] H.W. Schmidt , R.H. Reussner , Generating adapters for concurrentcomponent protocol synchronization,Proc.五、IFIP国际Conf. 开放式基于对象的分布式系统的形式化方法Kluwer 2002.[13] M. 肖,D. Garlan,软件体系结构,Prentice-Hall,1996。[14] SunMicrosystems,EnterpriseJavaBeans2.0规范,http://java.sun.com/products/ejb[15] D. 耶 林 河 Strom , Protocol speci cations and component adaptors , ACMTOPLAS 19.2,March 1997,292-333.
下载后可阅读完整内容,剩余1页未读,立即下载
cpongm
- 粉丝: 5
- 资源: 2万+
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- StarModAPI: StarMade 模组开发的Java API工具包
- PHP疫情上报管理系统开发与数据库实现详解
- 中秋节特献:明月祝福Flash动画素材
- Java GUI界面RPi-kee_Pilot:RPi-kee专用控制工具
- 电脑端APK信息提取工具APK Messenger功能介绍
- 探索矩阵连乘算法在C++中的应用
- Airflow教程:入门到工作流程创建
- MIP在Matlab中实现黑白图像处理的开源解决方案
- 图像切割感知分组框架:Matlab中的PG-framework实现
- 计算机科学中的经典算法与应用场景解析
- MiniZinc 编译器:高效解决离散优化问题
- MATLAB工具用于测量静态接触角的开源代码解析
- Python网络服务器项目合作指南
- 使用Matlab实现基础水族馆鱼类跟踪的代码解析
- vagga:基于Rust的用户空间容器化开发工具
- PPAP: 多语言支持的PHP邮政地址解析器项目
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功