到本系列文章的这里为止,我们仔细考察了 Jxta,一个 Java 参考实现的新 P2P 平台,是如何工作的。在第一部分中,我们了解了 Jxta 的互操作特征。Jxta 被定义为一组互操作协议,可以跨硬件平台、操作系统和编程语言实现。我们也讨论了 Jxta 的操作模型和包括对等机、对等组、服务和管道在内的许多重要概念。在第二部分中,我们的着眼点是建立和运行 Jxta。我们探讨了一个 Jxta 应用程序 — Jxta shell — 并经历了创建管道并从一个对等机发送消息到另一个对等机的情形。在我们编写 Jxta shell 扩展时,我们第一次获得了用 Jxta API 编程的经验。迄今为止,我们讨论 Jxta 的方式都是从下到上的。对于像我们这样具有系统编程和网络工程背景的人来说,这是再自然不过的。
在本系列的这第三篇也即最后一篇文章中,我们要把事情颠倒过来。从那些从事应用级设计和体系结构的人的角度来说,本文是自上而下看待 Jxta 的。我们从一个特定的示例问题开始,对这个问题进行分析并设计出一个解决方案,从而展示 Jxta 是如何自然地解决该问题的。
随着本文的进行,我们讨论 Jxta 如何通过并列(juxtaposition)改变联网的前景展望,我们还提供一个 Jxta 服务和客户机的设计和代码。
解决一个分布式数据收集问题
设想一下我们需要创建一个大规模的气象数据收集和分析系统。在这个系统中,我们有数百个气象数据收集点;每个收集点配备一个微型气象站,这些气象站将当前温度(和其它大气状态)提供给一组数据集中器。收集器遍布世界各地;这些收集器并不是都直接连接到因特网,任何时候都可能有新的数据收集器连接上来或脱开连接。在这个项目中,参与进来的收集器的确切数量经常在变化;数据分析和处理基于区域平均值。
开始时只有 10 个集中器。每个集中器监视来自许多个收集器的数据,这些数据被实时提供给关系数据库。随后,来自关系数据库的数据被提供给运行气象分析和预测的仿真模型的超级计算机并由它处理。集中器的数量和位置会发生变化,但它们的行为则大多更稳定。一旦安装后,集中器就会保持运转,除非碰到系统失效。
我们必须解决的问题:我们的系统如何能够持续运转,并能考虑到在几乎不影响整体性能的条件下,允许动态添加或除去收集器和集中器。
初始分析:特定网络的复杂性
系统中的某些收集器可直接访问因特网;其它的通过无线电传输技术进行连接,它们处在恶劣的外部环境中。事实上,在这些基于无线电的收集器中,许多都被设计成了节能的,以延长电池寿命;收集器的有效范围仅够与下一个最近的收集器或基站联系。这些收集器中许多都不支持 TCP/IP,而是使用基本的分组无线技术。一些更独立的收集器仅仅靠其太阳能电池板获得能量,并使用卫星传输进行通信。还有另外一些收集器则连接到标准蜂窝电话上,用 SMS(short message service,短消息服务)消息传递来发送消息。
在项目的整个生命周期中,可用的收集器的数量会发生变化;在项目开始时,我们无法预测将会构建到未来收集器中的连接类型,也无法预测收集器将使用的技术。例如,在项目的某个阶段,在一个超级计算机群集内使用软件仿真来仿真数量巨大的收集器。我们的解决方案必须能适应所有收集器,不管是真正的还是仿真的,现在的还是将来的。
解决方案:并列(Juxtaposition)
图 1 显示用来解决这个问题的高层次设计。
图 1. 解决数据收集问题
IMG http://www-900.ibm.com/developerWorks/cn/java/j-p2pint/part3/fig1.gif[/IMG]请注意,并列 P2P 网络用来适应网络的多种不同情况,而集中器提供 P2P 网络和传统的客户机/服务器网络之间的连接,数据库服务器和超级计算机驻留在客户机/服务器网络。集中器充当两个网络之间的网桥 — 每个集中器在 P2P 网络上具有动态特性,在客户机/服务器网络具有静态特性。
这个体系结构反映了 Jxta 对传统系统的补充作用和提供并行于这些传统系统的增值的能力 — 通过并列(juxtaposition),Jxta 的名称就源于这个词语。
我们不想深入讨论这里的客户机/服务器网络的细节,因为其中并没有什么独特之处;我们甚至可以使用 VPN 技术在因特网上运行它。有趣的部分在 P2P 网络。图 2 显示了它的组成,它可随将来的变化而变化。请注意其中用到的多种不同技术。
图 2. 数据收集器网络的组成
IMG http://www-900.ibm.com/developerWorks/cn/java/j-p2pint/part3/fig2.gif[/IMG]在实现这个 P2P 网络时,我们可以利用 Jxta,从而获得以下优点:
容易地添加或除去新的收集器或集中器,这得益于 Jxta 的统一分散寻址
设计简单性,这得益于 Jxta 的网络虚拟化
持续运转,这得益于 Jxta 支持故障弹性
免维护运转,这得益于 Jxta 支持动态自我组织网络
支持跨越许多硬件平台和编程语言的多种不同实现,支持所用的各种不同通信协议
让我们来更详细地研究一下其中几个益处,并看看 Jxta 如何为体系结构的各个方面作出独特的贡献。
统一分散寻址
统一分散寻址的字面意思是,对等机可以为自己生成一个 ID 并立即加入到网络,而不必与任何注册人或中央认证机构联系,而当今的 DNS 则必须这样。这一特征使我们任何时候都可以向网络添加收集器和集中器。
在本文附带的代码包中(您可以从参考资料下载它),我们提供了名为 mdidgen 的实用程序,它可以用来为新的 Jxta 服务和管道生成地址。(要更多了解 mdidgen,请参阅旁注 mdidgen 实用程序。)您可以阅读本系列的第一篇文章,了解 Jxta ID 是如何用来对 Jxta 对象(例如:对等机、对等组、服务和管道)进行统一寻址的。
请注意,Jxta 网络中的对等机不一定要有一个独立的物理存在。在我们的示例中,我们用一个超级计算机群集来仿真数量巨大的收集器,每个收集器有它自己的统一地址。这些仿真收集器的每一个在 P2P 网络的其它部分看来都是一个与那些具有物理存在的对等机没有什么差别的对等机。
网络虚拟化
通过分散寻址为所有收集器和集中器赋予网络中唯一的标识后,它们立即就成为网络中的对等机并开始彼此通信。尽管它们可能通过许多种不同的消息传递机制进行相互联系,但在 Jxta 级别上,它们都只是一个虚拟网状网络中的节点,如图 3 所示。
图 3. 网络虚拟化
IMG http://www-900.ibm.com/developerWorks/cn/java/j-p2pint/part3/fig3.gif[/IMG]请注意,将收集器和对等机实际相互连接起来的所有不同的传输和寻址模式都被虚拟化了,只留下一个网状网络,其中的每个对等机都与其它每一个对等机相连接。Jxta 通过使用统一寻址模式和极迟绑定(very late binding),在多个端点协议上添加一个智能消息路由层做到这一点。从本质上说,每一个端点协议或传输协议栈都成为虚拟 Jxta 网络的一个驱动程序,将虚拟网络映射到物理网络上。图 4 显示了这种设置。
图 4. 端点协议作为驱动程序
IMG http://www-900.ibm.com/developerWorks/cn/java/j-p2pint/part3/fig4.gif[/IMG]通信协议要成为合格的端点协议,只需要它能够在两个物理节点之间发送或接收 XML 消息。对传输可靠性或消息广播支持没有什么要求。因而,最简单的分组无线协议也可以用作端点协议驱动程序,与像 TCP/IP 这样的复杂多层协议并列。这也解释了为什么 HTTP 和 TCP/IP 在 Jxta 协议栈内都是同一级别的端点协议,尽管它们的物理级别非常不同。HTTP 是一个受支持的端点协议,因为只要有必要,它就能够穿越尽可能多的防火墙,从而获取从一个 Jxta 对等机传送到另一个的消息。
Jxta 网络中的每个对等机可以同时支持多个端点协议,Jxta 虚拟网络机制会以一种尽可能迟的方式将虚拟化的统一网络地址映射到物理网络地址(在 Jxta 中称为网络端点)。从本质上说,一个对等机对应于一组物理端点,其中的每个物理端点可以在完全不同的物理通信协议上实现。较高级别的虚拟化和路由服务隐藏了这一点。许多人或许能看出这就是多协议路由器的一个非常高级的形式 — 正是这相同的设备使当今的因特网成为现实。这一概念的发展将把我们带向一个更加普遍的因特网,这是再自然不过的了。
让我们更详细地研究一下图 5 所示的示例。对等机 A 是网络中的一个收集器,它试图通过一系列中介收集器(对等机 B、C 和 D)将其数据发送到集中器(对等机 E)。在图中每个对等机的下面是该对等机所支持的一组协议。
图 5. Jxta 路由示例
IMG http://www-900.ibm.com/developerWorks/cn/java/j-p2pint/part3/fig5.gif[/IMG]因为对等机 A 不直接连接到对等机 E,所以它的消息必须通过中介对等机 B、C 和 D 进行路由。Jxta 将自动对消息进行路由:
使用 TCP/IP 从对等机 A 到对等机 B
使用分组无线协议从对等机 B 到对等机 C
使用 SMS 从对等机 C 到对等机 D
使用 HTTP 从对等机 D 到对等机 E
对等机 E 将在它创建的管道上接收来自对等机 A 的消息,完全未觉察 Jxta 为它所执行的复杂工作。请注意,对等机 C 到对等机 D 的路径是非对称的;Jxta 就是专门设计来处理这种状况的。如果有条消息要从对等机 E 发送回对等机 A,则 Jxta 将使用拨号调制解调器 PPP 自动地从对等机 D 路由到对等机 C。
故障弹性
尽管上面所描述的路由功能已经令人非常惊奇,但更为重要的是,Jxta 必须能够适合 P2P 网络不断变化的拓扑结构。特别是它必须能够处理充当消息路由代理的 P2P 对等机与生俱来的不可靠性。在我们的例子中,如果中继收集器不可用,那么,依赖另一个收集器来路由它的消息的收集器将不能进行通信。
当有对等机加入或离开网络时,Jxta 要能够实时对消息进行重路由。再考虑一下图 5 中的路由示例。请设想一下,由于某些原因,就在对等机 A 已经发送出消息(现在正在传输)而尚未到达对等机 C 时,对等机 C 和对等机 D 之间的卫星链路却断了。Jxta 必须能够动态地通过某些替代路径(可能是通过另一组中间节点)将该消息重路由到对等机 E。这种动态重路由是基于最大努力(best-effort)完成的;偶而有这样的情况,如果没有可能的路由(除非中介传输支持持久队列),则消息可能会被丢失。由于这种重路由能够改换实际用来到达对等机 E 的端点协议(例如:从 HTTP 到 TCP/IP),所以,要一直达到路由的最后一个跳数时,对等机到物理端点的绑定才会发生。这就是 Jxta 的极迟绑定的本质。
在对等组级别上(请参阅本系列的第一篇文章了解有关对等组的更多知识),Jxta 通过支持对等组服务 — 在对等组内总是可用的、冗余地实现的服务 — 支持故障弹性。
动态自我组织网络
当具有统一虚拟网络 ID 的对等机插入到 Jxta 网络中时,它必须这样来自我引导:
定位本地对等机并发现它们的功能
发现可用的对等组并加入其中一个
发现对等组中可用的服务并开始使用它们
我们从本系列的第二篇文章中了解到,这一切都是在消息级别上通过发布、中继、中介高速缓存和搜索称为广告的不同类型的消息完成的。Jxta 的 Java 参考实现有一个解析器和使发布-高速缓存-搜索(publish-cache-search)过程简便的集中服务层。
Jxta 中的对等组的作用是作为网络分区(network-partitioning)机制,确保广告只被中继到能够使用这些广告的组成员。不同的对等组可以包含对等机和对等组服务的不同组合,充当功能性的捆束机制。对等组也可以起到特定应用程序的认证域的作用。
mdidgen 实用程序
实用类 com.ibm.jxta.mdidgen 可以用来以分散方式为 Jxta 对象生成统一地址。它生成一个新的 ModuleClassID、一个相应的 ModuleSpecID 和一个与某个组(在启动时被读取的配置文件中指定)关联的新 PipeID。所生成的这些 ID 是立即可以使用的 Java 声明形式,并且立即可以插入到您的代码中。这就是我们为 ModuleSpecAdvertisement 和集中器服务管道生成 ID 的方式。
设计 Jxta 服务和 Jxta 客户机
让我们回到气象站示例上来。从概念上说,集中器实现必须:
读取并处理适当的配置文件,这个文件告诉集中器加入到哪个 Jxta 组。(样本代码包中包含有我们示例的配置文件。)
启动 Jxta。
加入到配置文件所指定的组。
进行搜索,以判断集中器服务的服务广告是否存在;如果不存在,就创建一个并发布它。
创建一条相应于该服务的输入管道。
在管道等待来自收集器的消息。
一旦消息到达,就处理它并存储到 RDBMS 中。
回到第 6 步。
这个逻辑在 com.ibm.jxta.Concentrator 类中实现。您可以从参考资料部分下载这个类及所有来自本文的代码。
收集器实现必须:
读取并处理上述配置文件。
启动 Jxta。
加入到配置文件所指定的组。
发现集中器服务的服务广告;如果服务广告不可用,我们就无法继续。
从服务广告抽取管道信息。
每隔一段时间收集数据。
创建包含收集器位置和数据的消息。
通过管道将消息发送到集中器服务。
回到第 6 步。
上述逻辑在 com.ibm.jxta.Collector 类中实现。
将公共任务分解到 DwJxtaPeer 超类
有很多任务对收集器和集中器角色都是公共的。为了消除不必要的代码重复并使将来的维护更简单,让我们把这些公共任务分解出来放入名为 com.ibm.jxta.DWJxtaPeer 的超类。
其中一个公共任务是执行 ModuleSpecAdvertisement 的发现(请参阅旁注 JXTA 中的服务广告了解关于这个广告的更多知识)。这由清单 1 中的 findModuleSpecAdv() 方法执行:
清单 1. findModuleSpecAdv()
protected ModuleSpecAdvertisement findModuleSpecAdv() {
return (ModuleSpecAdvertisement) findAdv("ModuleSpecAdvertisement",
"Name",ModuleSpecName, new ModuleSpecAdvValidator(), false );
}
请注意,findModuleSpecAdv() 调用另一个名为 findAdv() 的通用方法,我们用这个方法发现广告。findAdv() 的参数是:
参数 描述
AdvType 广告类型的字符串描述 — 例如,PipeAdvertisement。
Attr 搜索广告时要匹配的标记 — 例如,Name。
Value 与所指定的属性匹配的值。
Validator 一个实现 FindValidate 接口的对象。这个接口有一个方法 checkAdv(),当找到一条广告时,这个方法就被用来立即对这条广告进行验证。
LocalOnly 一个布尔标志,表明该发现是否只应在本地执行,还是跨网络在远程执行。
如清单 2 所示,该方法的第一部分通过使用组的发现服务的 getLocalAdvertisement() 方法,仅根据本地广告高速缓存执行对广告的发现。请注意对 validator.checkAdv() 调用,用来对所找到的任何广告进行验证。
清单 2. findAdv(),第 1 部分
protected Advertisement findAdv(String advType, String attr, String val,
FindValidate validator, boolean localOnly) {
Enumeration enum = null;
System.out.println("Looking for " + advType + ", please wait...");
// First look in the local storage
try {
enum = discovery.getLocalAdvertisements(DiscoveryService.ADV,
attr, val);
} catch (Exception e) {
}
if ((enum != null) && (enum.hasMoreElements())) {
Advertisement adv = null;
while (enum.hasMoreElements()) {
try {
adv = (Advertisement) enum.nextElement();
if( validator.checkAdv(adv))
return adv;
} catch(Exception e) {
continue;
}
} // while
} // if
如果该发现是本地的,则逻辑就在这里停止。否则,我们就发送一条查询到网络,执行远程发现。发现服务将把所找到的任何广告都存储到本地高速缓存。我们只要给点时间就可以让远程发现发生。在清单 3 中,循环大约持续了五秒钟:
清单 3. findAdv(),第 2 部分
if (localOnly)
return null;
System.out.println(" cannot find it locally, trying remote");
// Now, search remote
discovery.getRemoteAdvertisements(null, DiscoveryService.ADV,
attr, val, 2, null);
// Wait a bit in order to get an answer.
int i=0;
while (true) {
try {
if (i>MAXRETRIES){
System.out.print(".");
break;
}
Thread.sleep(WaitingTime);
i++;
} catch (Exception e) {
}
System.out.println("");
此时,已发现的任何广告都应可在本地高速缓存中找到。在清单 4 中,我们再次执行一个本地检查。
清单 4. findadv(),第 3 部分
// Look in the local storage again
try {
enum = discovery.getLocalAdvertisements(DiscoveryService.ADV,
attr, val);
if ((enum != null) && (enum.hasMoreElements())) {
Advertisement adv = null;
while (enum.hasMoreElements()) {
try {
adv = (Advertisement) enum.nextElement();
if( validator.checkAdv(adv))
return adv;
} catch(Exception e) {
continue;
}
} // while
}
} catch (Exception e) {
}
}
return null;
}
超类中的另两个公共方法的描述在下表中;您可以作为练习完成对它们的分析。
方法 描述
PublishModuleSpecAdv() 如果发现过程没有为服务找到现有的 ModuleSpecAdvertsiement,则这个方法被集中器调用。这个方法将创建一个服务(根据我们所生成的、固定的服务 ID)。这条广告将在本地和远程发布。仅在集中器第一次启动时,当配置改变时,或者在本地高速缓存被清除后,才有创建广告的必要。
JoinGroupIfExists() 这个方法为收集器和集中器所调用;它尝试加入到一个已命名的子组(subgroup),这个子组是全局 NetPeerGroup(缺省情况下大家都在这个组)的子(child)组。
请看一下清单 5,它是 DwJxtaPeer 类的常数声明部分的一部分:
清单 5. 模块 ID 定义
public static final String ClassID =
"urn:jxta:uuid-EE99266A1DE84E3DB34D9CC842EC889105";
public static final String SpecID =
"urn:jxta:uuid-EE99266A1DE84E3DB34D9CC842EC8891B9EB13ECA6FE44DDA112B5F5E357763006";
Jxta 中的服务广告
服务广告概念分解成一组相互联系的广告(共三条):
ModuleClassAdvertiseent
ModuleSpecAdvertisement
MdouleImplAdvertisement
为了减小在系统中循环的广告的大小,也为了将服务的通用类(例如:银行)、该类的特定规范(例如:存款和提款 API)和该服务(例如:API 基于 Java 的实现)的实现之间的关系规格化,这样做都是必要的。
应用程序或 Jxta 服务不必使用所有这些广告,只要使用它所需要的就行了。在我们的系统中,我们只需要ModuleSpecAdvertisement,我们用它将服务连到管道上,并使这条广告是远程可发现的。
ModuleClassID 和 ModuleSpecID 用 mdidgen 实用程序生成并以硬编码方式置于模块中;它们与一个集中器服务的 ID 相对应。所有的集中器都知道这个服务的 ID,而且这个 ID 一旦生成就一直保持不变,所以组中的收集器肯定能够找到这个集中器服务。因为生成 ModuleSpecID 时需要 ModuleClassID,所以这里有 ModuleClassID。为了轻松生成这些 ID,我们使用一个名为 AdvCooker 的库,它是 W.R. Bauer(vasha@jxta.org)创建的名为 jxta-wire 的 Jxta 项目的一部分。
网络中运行的所有集中器实例将对同一个集中器对等组服务(通过使用相同的 ModuleSpecID 和侦听广播管道的同一个逻辑实例)作出应答。这种冗余实现将确保集中器服务在对等组中始终可用。
集中器:一个 Jxta 对等组服务
我们来看一下 com.ibm.jxta.Concentrator 实现。我们已经提到过,它继承(扩展)自 DwJxtaPeer 类。这里是逐个方法地对 Concentrator 进行的描述:
方法 描述
init() 它应该是该类被调用的第一个方法。这个方法调用私有 jxtaInit() 方法,然后创建输入集中器服务管道的一个实例。
process() 这个方法进入一个无限循环。它在输入集中器服务管道上侦听传入的收集器数据提交。对每一个提交,它都调用 processData() 对数据进行处理。
findPipeAdv() 这个方法对服务管道广告执行本地发现(也就是说,它检查本地高速缓存)。
jxtaInit() 这个方法首先读取配置文件并设定我们想要加入到的组。接着,它启动 Jxta 和 NetPeerGroup 网络,然后调用超类的 joinGroupIfExist() 加入到指定的组。接着,如果能够,它就从本地高速缓存检索服务管道广告;否则,它将创建一个新的服务管道广告(通过使用 createInputPipeAdvIfNotExist())。最后,它执行发现,看看是否可以找到 ModuleSpecAdvertisement;如果不能找到,它就创建一个并发布它。
processData() 这个方法是占位符。在实际的项目中,它将使用后端客户机/服务器网络将所收集到的数据提交给 RDBMS(可能使用 JDBC)。
createInputPipeAdvIfNotExist() 这个助手方法首先检查高速缓存,看看服务管道广告是否可用。如果不可用,它将创建该广告并将它存储到高速缓存中。在任一种情况下都返回正确的广告。
静态类型定义如下:
public static String servicePipeID =
"urn:jxta:uuid-969610EE8945417CA56F9771197EE3965207E4C303154E7EB5878751AE22761804";
这是由 mdidgen 实用程序生成的管道 ID。它是该服务管道的统一地址,被所有集中器使用。它是一条广播管道,因而侦听消息的所有集中器都应接收到那些来自收集器的消息。收集器从作为 ModuleSpecAdvertisement 的一部分的管道广告中获得这个管道 ID;收集器通过发现过程找到该广告。
收集器:编写 Jxta 客户机逻辑的代码
最后,我们来看一下 com.ibm.jxta.Collector 类的本地方法。
方法 描述
init() 它应该是从这个类中调用的第一个方法。这个方法调用私有 jxtaInit(),然后创建用来将所收集到的数据发送到集中器服务的输出管道。
process() 这个方法有一个无限循环,这个循环首先调用 collectData() 获得测量的数据,接着,创建一条 Jxta 消息并沿集中器服务管道将它发送到正在等待的集中器。循环内每次采样都延迟一段固定时间。
jxtaInit() 这个方法首先读取配置文件并对我们想要加入到的组进行设置,接着确定收集器的位置。接着,它启动 Jxta 和 NetPeerGroup 网络,然后调用超类的 joinGroupIfExist() 加入到指定的组。接着,它执行发现,看看是否可以找到相应于众所周知的集中器服务的 ModuleSpecAdvertisement;如果找不到,则退出。一旦找到了 ModuleSpecAdvertisment,它就将抽取集中器服务管道广告并为输出管道的创建做好准备。
collectData() 这个方法是一个占位符,用于实际的数据收集。在实际的项目中,这个方法将访问各种数据输入通道(可能使用输入/输出端口或本机代码)并将所收集到的数据返回给调用者。
实际运转 Jxta:在您自己的机器上测试这个动态网络
本文附带的源代码包中有一个便于您实验的目录结构。下面的目录在 code 子目录下:
目录 描述
lib 来自 Jxta 核心最新稳定版的所有 jar 文件,用于 Jxta shell 的所有 jar 文件以及来自 jxta-wire 项目的 jxta-wire.jar 文件都放在这里。(请参阅参考资料了解关于 Jxta shell 和 jxta-wire 的更多信息。)
src 包含我们系统的源代码。
classes 包含我们系统的编译好的类文件。
shell1 第一个实验目录。我们将在这个目录创建一个带有一个集中器的 shell。我们还将在这里充分考查 mdidgen 实用程序。
shell2 设置为网络中的第二个对等机。这将运行另一个集中器。
shell3 设置为网络中的第三个对等机。这将运行一个收集器。
要编译这些代码,您需要安装 JDK 1.3 或更新版本。在 code 目录时,执行 MAKEIT.BAT 批处理文件。这将编译代码并在 classes 目录中创建类文件。
接着,运行 MAKEJAR.BAT 批处理文件。这将创建一个包含所有代码的 dwjxta.jar 文件;将它放到 lib 目录,为实验做好准备。
现在,请启动三个不同的命令窗口。将它们的目录分别改到 shell1、shell2 和 shell3。
在 shell1 目录中编辑 runshell.bat 文件,将您在配置期间用来设置安全性的用户标识和密码反映出来(密码必须至少八个字符长)。编辑 runconc.bat 和 mdidgen.bat 文件,同样要有这个用户标识和密码。
使用 runshell.bat 运行这个 shell,并按以下所示配置这个对等机:
对等机名: node1
传输: TCP/IP 启用,HTTP 禁用,选中作为集中点,无中继
所用 TCP 端口: 9701
安全性用户名和密码: 如在批处理文件中所定制
因为我们的系统假设已经创建了一个用于操作的组,所以我们需要在该 shell 中创建这个组。在这个 shell 中时,使用以下命令创建 dwtest 组:
Jxta> myadv = mkadv -g dwtest
Jxta> mygrp = mkpgrp -d myadv dwtest
这将创建我们将使用的 dwtest 组。您可以这样来确认它已经被创建:
Jxta>groups
group0: name = dwtest
现在您可以退出该 shell。
现在,请使用 mdidgen.bat 文件试验统一地址(ID)的分散生成。当您运行这个文件时,应得到类似这样的输出:
清单 6. mdidgen.bat 的输出
remote group discovery message sent
group joined successfully
public static final String ClassID =
"urn:jxta:uuid-DCDD418FCC194040AA13A52A334B967105";
public static final String SpecID =
"urn:jxta:uuid-DCDD418FCC194040AA13A52A334B96716C515B975C2941AD9FBC90178B6918A806";
public static final String PipeID =
"urn:jxta:uuid-2184CACA259B42E0A866AEA788A923054C519D304E07415195B0917C81238FD004";
请注意所生成的 ModuleClassID、ModuleSpecID 和 PipeID。这就是我们获得在集中器服务用到的 ID 的办法。
通过执行 runconc.bat 文件启动集中器。这将读取 dwConfig 文件,这个文件告诉集中器加入到 dwtest 组。您的输出应与此有些相似:
清单 7. 1 号集中器(runconc.bat)的输出
Starting Jxta...
Joining default NetPeerGroup...
Attempting to join group: dwtest
remote group discovery message sent
group joined successfully
group dwtest joined successfully
Look for previously created Pipe Adv, create one if not exist
Looking for PipeAdvertisement, please wait...
Previously published pipe advertisement not found, creating a new one.
Locally caching the new pipe advertisement...
Checking to see if MSA previously published...
Looking for ModuleSpecAdvertisement, please wait...
cannot find it locally, trying remote
... MSA not found, need to create it
Creating new MSA
Locally and remotely publish the MSA
Creating pipe for data collection...
pipe created successfully
Waiting for data from collector...
到这里,集中器实例就建立好了,并且为接收来自收集器的数据做好了准备。
现在,到 shell2 命令窗口中编辑 runconc.bat 文件,将您的安全性用户标识和密码反映出来。接着,使用 runconc.bat 文件运行集中器实例。在配置过程中设置以下参数:
对等机名: node2
传输: TCP/IP 启用,HTTP 禁用,无集中点,无中继
所用 TCP 端口: 9702
安全性用户名和密码: 如在批处理文件中所定制
如果一切都正确运行,则您应看到与此相似的输出:
清单 8. 2 号集中器(来自 Shell2 的 runconc.bat 输出)
Starting Jxta...
Joining default NetPeerGroup...
Attempting to join group: dwtest
remote group discovery message sent
group joined successfully
group dwtest joined successfully
Look for previously created Pipe Adv, create one if not exist
Looking for PipeAdvertisement, please wait...
Checking to see if MSA previously published...
Looking for ModuleSpecAdvertisement, please wait...
.. found previously published MSA
Creating pipe for data collection...
pipe created successfully
Waiting for data from collector...
请注意,集中器的 ModuleSpecAdvertisement 被找到了,所以这个集中器实例不必另外创建一个 ModuleSpecAdvertisement。现在它也在等待来自收集器的输入。
最后,到 shell3 命令窗口中编辑 runcoll.bat 文件,将您的安全性用户标识和密码反映出来。接着,使用 runcoll.bat 文件运行收集器实例。这个实例将使用 shell3 目录中的 dwColConfig 文件,该文件告诉收集器应加入到 dwtest 组,这个组的位置是“Timbuktu North。在配置过程中设置以下参数:
对等机名: node3
传输: TCP/IP 启用,HTTP 禁用,无集中点,无中继
所用 TCP 端口: 9703
安全性用户名和密码: 如在批处理文件中所定制
这个收集器实例将开始查找 ModuleSpecAdvertisement 并且应该能找到。然后,它将创建一条管道与已经运行的集中器通信。您应看到与此相似的输出:
清单 9. 收集器(来自 Shell3 的 runcoll.bat 的输出)
Reading config file, dwColConfig, and processing...
group to join will be dwtest
collector location is Timbuktu North
Starting Jxta...
Joining default NetPeerGroup...
Attempting to join group: dwtest
remote group discovery message sent
group joined successfully
group dwtest joined successfully
Searching for collector's MSA...
Looking for ModuleSpecAdvertisement, please wait...
cannot find it locally, trying remote
.. found collector's MSA
Extracting pipe adv from MSA...
Connecting to concentrator network...
pipe created successfully
... collecting data....
... data collected, sending to concentrator
waiting until next sample...
... collecting data....
... data collected, sending to concentrator
waiting until next sample...
请注意,数据被收集起来并定期发送到集中器服务。当数据穿过 P2P 网络以及两个集中器接收这些数据并进行处理时,请注意观察。
高难度的应用模式
我们的气象收集示例说明了这样一个应用模式:在一般的方面,它使用普遍流行的应用 P2P 系统;从特定的方面,它使用 Jxta。这个模式包含两个耦合极其松散的群体:消费者和生产者。当消费者想要生产者所生产的产品时,消费者不愿作出坚定的许诺,也不愿受限于特定生产者。在这种想法背后可能有几个现实动机。消费者可能想:
可以在任意时间进行选择,以选择最佳的可用生产者
降低对某个生产者的成功或失败的依赖风险
从非常庞大的动态社区中选择,这种社区的大小和拓扑结构在物理上是难于管理的
当消费者群体和生产者群体出现交迭时,这种模式变得十分有趣,当前可用的、流行的、世界范围内的文件共享系统就例证了这一点。与传统的联网技术不同,P2P 系统从一开始就是设计来适应这种应用模式的。特别地,与使用传统的客户机/服务器技术进行设计时,必须提供的复杂的解决方案不同,Jxta 使得创建这些系统既容易又轻松。
超越 TCP/IP 的联网
为了真正突出 Jxta 带来的价值,我选择了全球气象信息收集系统作为一个示例。然而,这个问题及解决方案具有许多业务模式(business scenario)的典型特征,这些业务情形如移动销售队伍自动化、商品贸易、内容分发和企业到企业电子商务等等,可以列出很多。您可以同时使用 P2P 网络和传统的客户机/服务器网络,从而构建大大超出当今静态边界的新型网络解决方案。开放源代码的 Jxta 平台将是这些新型解决方案的实现工具。我希望本系列已经激起您探索 Jxta 提供的可能性的愿望。
from-ibm developer
Java, java, J2SE, j2se, J2EE, j2ee, J2ME, j2me, ejb, ejb3, JBOSS, jboss, spring, hibernate, jdo, struts, webwork, ajax, AJAX, mysql, MySQL, Oracle, Weblogic, Websphere, scjp, scjd
标签: