使用Sun公司的网络计算平台建立peer-to-peer应用程序开发基础平台

使用Sun公司的网络计算平台建立peer-to-peer应用程序开发基础平台

作者:Navaneeth Krishnan

译者: gracepig

英文原文地址:
http://www.javaworld.com/javaworld/jw-10-2001/jw-1019-jxta-p2.html
中文地址
http://www.matrix.org.cn/resource/article/43/43627_P2P_Jxta.html
关键词: P2P Jxta peer-to-peer

摘要
Peer-to-Peer网络毫无疑问是当今的热点技术主题。Napster和Gnutella的广泛使用证明了peer-to-peer应用的强大潜力。鉴于在这个定于大量的重复劳动,Sun Microsystems发起了Jxta工程-新一代的p2p应用程序开发平台。本文专门探讨了P2P和Jxta在这方面的成果。可以作为早期接触者,程序员,爱好者开发P2P应用程序的简介。(4,100 词;十月 19日,2001年)

今天的Internet正在验证一种变革。这种变革将会改变网络的一个基本特征。所有的网络终端包括桌面电脑,PDA,移动电话,都要要求更高的网络状况。这场变革在诸如Napster 和 Gnutella的应用软件推动下,将会终结以服务器为主导的Internet。这场变革就是P2P。

P2P(或者说peer-to-peer)网络是一种基于操作上下文的网络模型,任何一个节点都同时作为客户机和服务器。由于在传统的客户机/服务器模式当中,客户机和服务器的角色已经实现定义好了,所以这是一种他们所不能提供的能力。

在这片文章里,我对比了p2p网络与client/server网络。并介绍了Jxta(发音为jux-ta)这种由Bill Joy(Sun公司首席科学家兼公司执行官)引领开发的P2P计算平台。目前,Jxta由数百名开源开发者共同实现。Jxta工程承载P2P世界的多个期望。它定义了一系列协议,开发者使用这些协议可以开发几乎所有的p2p程序。同时这些协议还可以适应应用程序所特有的需求。Jxta并没有规定所使用的编程语言和使用环境,但是使用Java语言开发P2P程序具有先天的优势,例如:可移植性,开发难度低,具有丰富的类库。

P2P:总揽
现在大多数的分布式计算模型是基于client/server形式的。图1描述了一个典型的client/server架构。

使用Sun公司的网络计算平台建立peer-to-peer应用程序开发基础平台_第1张图片

图1:client/server模型

这种架构下的工作模式是,客户机发出服务请求,服务器响应服务请求并提供服务。在Internet上存在这大量各种各样的服务器?D?Dweb服务器,邮件服务器,FTP服务器,等等。Client/server架构是一种典型的中央集中式架构,整个网络服务都依存中央节点(服务器)而存在。如果没有服务器,网络就存在就没有价值;没有它们,Web浏览器将如何工作?所以说无论有多少浏览器和用户的存在,网络只有在存在的情况下才能工作。

和client/server架构类似,P2P同样也是一种分布式网络架构。但它和client/server架构有一个显著的不同点。P2P架构是一种非集中架构(见图2),在网络中没有服务器或是客户机的概念。对于网络中的每一个实体,都会被认为是一个对等点(peer),它们拥有相同的地位,任何一个实体都可以请求服务(client的特性)和提供服务(server的特性)。图2图示了一个P2P网络。

使用Sun公司的网络计算平台建立peer-to-peer应用程序开发基础平台_第2张图片

图2:peer-to-peer 模型

虽然所有的peer在网络中都具有相同的地位,但并不是所有的peer都需要具有相同的性能。在P2P网络当中,可以均有不同性能的多种节点,从移动设备到工作站。一个移动peer由于其内在的限制即使网络允许可能也并不能像服务器那样工作。

两种网络模型各有优缺点。可以想想如图1那种的client/server架构,在网络增长(client越来越多时),不可避免的将压力附加给中央节点服务器。每增加一个用户,服务器的能力就相对下降一些;当服务器崩溃的时候整个网络也就被摧毁了。

P2P网络将不同的场景传送出去。由于每一个实体(或peer)在网络中都是一个活跃的参与者,所以peer将自身的特定资源贡献给整个网络,例如存储空间和CPU计算周期。当越来越多的peer加入网络当中的时候,网络的能力也就随之增长。应此,随着网络的增长,网络自身的能力也会越变越强。这种扩展性是client/server架构所不具备的。

P2P网络区别于client/server模型的令一个特性是只要有一个peer是活跃的那么网络就被认为是可用的。P2P网络只有在没有任何一个节点是活跃的时候才不可用。

在获得P2P网络提供优势特性的同时,你将会付出如下的代价。首先,相比client/server模型来说,P2P网络的管理如同一场恶梦。P2P网络的上的增强安全策略,备份策略都将会更为复杂。其次,P2P协议相比client/server协议来说更加“多变”,peer可以随时的加入或者退出网络。这种瞬时变化的特性将会引发对性能的担忧。(参看"Bandwidth Barriers to Gnutella Network Scalability"获取更多的信息)

Jxta 解决方案
不同的协议,不同的架构,不同的实现是对P2P解决方案现状的真实描述。目前,开发者门使用了很多种不同的方案来实现P2P应用。在client/server世界中显的过剩的“标准”,在P2P世界中显的如此罕见。用了解决这个问题,Sun公司开发了Jxta。

摘自Jxta的目标声明:

Jxta工程要创建一种核心网络计算技术,提供支持跨越平台,时间,空间P2P计算的一组简单,小型,灵活的机制。工程首先才对P2P的功能进行总结抽象,然后创建能够坚决目前P2P计算主要限制的核心技术。工程主要致力于创建基本的机制将策略的选择权保留给应用的开发者。


Jxta致力于为P2P应用提供一个P2P平台基础。其中包括一系列独立于语言,平台和网络技术之外的协议(假设并不知道网络的下层实现)。这些协议解决了P2P应用的基本需求。协议的设计目标是简单并且低成本,引用Jxta目标声明的话就是“每一个设备都有一个数字心跳”(every device with a digital heartbeat,这句话实在不好翻译)。

Jxta目前定义了6个协议,但并不是要求Jxta peer实现全部的6个协议。Peer实现协议的数量取决于这个peer的能力;一个peer甚至可以只实现一个协议。Peer也能够根据自身的需求扩展任意一个协议。

值得注意的一点是Jxta协议本身并不保证互操作性。Jxta和TCP/IP在应用的时候是类同的。正如虽然FTP和HTTP都是建立在TCP/IP基础之上的,但你不能用FTP客户端去访问网页。在Jxta中也一样,假如有两种应用都是建立在Jxta之上的,并不说明它们之间一定能够具有互操作性。互操作性有开发者自己设计实现。尽管如此,开发者将应用建立在Jxt提供的护操作层之上,这样就减少了对于护操作性的实现困难。

Jxta中的XML
不容置疑,提供统一的基础协议的第一部就是采用一种可以在大多数平台上标示的语言形式。XML是一种完美的选择。Jxta的开发者意识到XML很快就会成为数据交换的缺省标准。XML提供了一种全局的,具有语言独立性和平台独立性的数据表示形式。同时XML也可以很容易的转变为其它编码形式。所以,Jxta使用XML定义所有的协议。

尽管Jxta的消息是使用XML定义的,但Jxta并不依赖于XML编码。事实上,解析器是一个可选的组件,一个Jxta的实体甚至并不需要一个XML的解析器。考虑到XML是一种方便的数据表示形式。例如移动电话这样小的实体可能会使用预先编译好XML消息。

Jxta的术语:
在我们了解进一步的概念之前,我们来迅速浏览一下Jxta的多种概念。

Peers (对等点)
     任何实现一个或多个Jxta协议的实体。一个Peer可以是从大型机到移动电话,甚至是一个移动传感器的任何设备。Peer是独立存在的,并且与其它Peer的通信都是异步的。

Peer groups (对等点组)
     具有相同兴趣的Peer可以集结成Peer Group(对等点组)。对等点组可能跨越多种物理网络。

Messages(消息)
      Jxta网络中的所有通信都通过接收和发送消息(messages)的方式来实现。这些Messages叫做Jxta消息,这些消息具有标准的格式,这也是具有护操作性的关键。

Pipes(管道)
      管道在Jxta环境当中建立虚拟的通信通道。Peer使用管道来发送和接收Jxta 消息。管道是一种虚拟的概念,peer不需要知道它们所在的实际网络地址就可以使用管道,这是一种重要的抽象。

Services(服务)
   Peer和peer group都可以提供服务。由peer提供的服务属于个人级服务,叫做peer服务,这种服务的方式和中央集中式服务相同。没有其它peer提供这种服务;如果这个peer不是活跃的,怎么这种服务就是不可用的。

   Peer Group提供的服务叫做peer group服务(对等组服务)。和peer 服务不同的是,这种服务不只是针对某一个特殊用户的,而是针对这个Group中的多个用户。Peer Group服务更容易被使用,原因是当某一个用户不可用的时候,其它的peer仍然会提供同样的服务。

Codats(代码/数据)
   Codat(代码/数据),在Jxta当中,这个词说明内容可以是代码或是数据。Codats可以被发布,发现,或是在必要是取代。

Advertisements(广告)
      广告用来发布和接收Jxta网络用的资源,例如peer,peer group,管道,或是codat. 广告是以XML文件的形式表现。

Identifiers(标识符)
   在Jxta环境当中,标识符起到了非常关键的作用。Jxta使用标识符来识别资源,而不是使用物理网络地址。Jxta的标识符被定义为URN(统一资源名(Uniform Resource Name))。一个URN本质上就是一个URI(统一资源标识符),这个URI在全局范围内唯一存在,并且即使资源已经不在存在,但它的URI还是存在的。(请参看Resources获取更多的资源)。

World peer group(世界对等点组)
每一个Jxta的Peer都缺省的属于world peer group。任何一个Jxta的peer都内在的属于world peer group并能够加入这个peer group。即使在peer无法在网络上找到任何其它的peer的情况下,甚至在Peer没有连接在网络上的情况下所有的peer也都是属于这个peer group的。

Net peer group(网络对等点组)
在一个本地网络中,网络管理员可以创建一个任何peer都可以加入的peer group:这样的peer group就是一个net peer group。这种group类似于DHCP服务。一个net peer group可以在管理员的限制下为peer提供全局接入的服务。

Rendezvous peers(集结点)
一个Rendezvous peer 是一个通过缓存其它peer广告的而保存有这些节点的信息的特殊peer。应此,rendezvous电可以帮助其它的peer互相发现。Rendezvous peer点同样可以将收到的发现请求信息(discovery request)转发给其它的Rendezvous peer.

Endpoints (终结点)
Endpoint是网络的目的地节点,它可以使用网络地址来表示。Peers一般并不直接使用endpoint,它们间接的通过pipe来使用endpoint。Pipe是建立在endpoint之间的。

Routers(路由器)
如何将数据包在Jxta网络上传送的节点称之为Jxta路由器。并不是所有的peer都需要成为一个路由器。任何不是路由器的peer都需要找到一个路由器来传递它们的消息。

Jxta 协议
Jxta的关键建立在由Jxta社区所指定的一系列通用协议之上。这些协议可以被用作应用程序的基础。这些协议被设计为低开销的,协议本身和使用它们的应用程序所在的网络拓朴环境是无关的。

Peer Discovery Protocol(PDP)对等点发现协议
Peer使用这个协议来发现被发布出来的Jxta资源。由于广告就是代表着发布的资源,所以PDP的主要工作就是帮助peer来其它peer的广告。作为最低级别的发现协议,PDP提供发现的最基本机制。应用程序可以选择使用其它更高级别的发现机制。PDP可以作为低基本的协议为其它高级别协议提供服务。

Peer Resolver Protocol(PRP) 对等点解析协议
在通常情况下,peer向其它peer发送查询消息来定位服务或者内容。Peer Resolver Protocol会将查询的格式标准化。使用这个协议,peer可以发送通用的查询并接收回复。

Peer Information Protocol(PIP)对等点信息协议
PIP可以被用来在Jxta环境中对一个peer发出ping消息。当一个peer接收到一个peer消息的时候可以有几种选择:可以选给出一个简单的回复,回复当中仅包含peer的运行时间。Peer也可以选择发送一个完全的回复,当中包含它自身的广告信息。或者它也可以选择忽略这个ping消息。

Peer Membership Protocol(PMP)对等点成员协议
对等点使用对等点成员协议来加入和离开peer group。这个协议识别peer使用的4个分散的步骤并为每一步的动作定义的Jxta消息:
      Apply:一个peer如果想加入一个group可以向这个group的成员验证者提过申请。
      Join:在申请之后,peer可以选择加入这个group
         Renew:如果要更新group的成员信息,peer可以使用renew的消息。
      Cancel:peer可以选择取消它在peer group中的成员资格。

Pipe Binding Protocol(PBP)管道绑定协议
在Jxta环境当中,peer使用管道来连接服务。一个peer可以动态的将绑定pipe的一端连接服务。Peer可以新建pipe,把它绑定到现存的pipe上,或是取消对pipe的绑定。在这些情况下,peer使用管道绑定协议。

Endpoint Routing Protocol (ERP) 终点路由协议
这个协议帮助peer将消息路由至目的地。ERP帮助peer 路由器查询其它peer路由器用于传递消息的有效路由。

Jxta Java 绑定
观察这些协议是怎样工作的最好的办法是了解一下Jxta Java 绑定,也就是Jxta的Java实现。开发者选择在现有的协议基础上开发应用或是使用他们自己选择的语言和平台实现这些协议。尽管这种实现由于HTTP和TCP/IP的简单和流行性选择了使用他们来进行传输,但开发者可以选择耕具网络拓朴状况选择任何传输协议来实现Jxta协议。

让我们迅速的分析一下今天的Jxta Java 实现(由于本文写在2001年,所以具体实现发现目前已经有所变化。译者注)

类组织:
         net.jxta.* 类
         net.jxta.impl.* 类

第一个包中包含了Jxta所有的接口,这些接口代表了Jxta的协议和核心模块所提供的功能。第二个包中包含了这些接口的实现。接口和他们的实现必须被清晰的分开。接下来我们深入看一些例子。

我的peer在哪里?
Peer是网络上的一个独立的,异步实体,它和一个peer ID关联起来。你可以认为一个代码的运行实例就是一个peer。目前,启动类(net.jxta.impl.peergroup.Boot)将会提供main()方法,启动以后将会成为一个peer。

一个peer拥有哪些能力取决于它属于那个group。但是,作为一个基本的peer,它会拥有一些最基本的能力,比如说它的ID。这也就是说,任何一个peer都必须处在一个peer group当中:这个peer group叫做world peer group。也叫做platform peer group,world peer group由net.jxta.impl.peergroup.Platform表示,这个类是PeerGroup 类的一个实现(net.jxta.peergroup.PeerGroup)。

Peer group nesting (Peer group 嵌套)
假设有一个Peer P1,作为一个peer group PG1的成员,这个group提供一个基本的发现和查询服务。现在假设网络中存在另一个peer group,PG2, 提供更加强大的搜索服务。P1如果想要使用这种服务就必须加入PG2当中去,但它可以同时使用PG1所提供的搜索服务。要实现这个功能,我们可以使用Peer group嵌套。通过Peer group嵌套,一个peer group提供的服务即使在被其它的peer group重载的情况下,也可以被使用。它提供了一种继承关系:第一个peer group,PG1,在这里作为一个父组,PG2作为一个孩子组。在这种情况下,孩子组的服务覆盖了父组的服务。也就是说,一但P1加入了PG2,这种继承关系就变为WorldPeerGroup/PG1/PG2。请注意到World Peer Group总是处在这种层次关系的最高端,是所有的Peer缺省处于的group。

作为应用程序的Peer group
作为绑定的一种重要的抽象,一个应用(net.jxta.platform.Application)是一个可以由peer group初始化,启动和停止的东西。有意思的是一个peer group由于应用的原因(net.jxta.peergroup.PeerGroup)经常会启动其它的peer group(如果peer group 嵌套的讨论)。World peer group是一个例外。它作为peer group层次关系的基础,并不会启动其它任何的peer group。一个应用定义了三个方法:init(), startApp(), and stopApp()。

在一个Application 类中的这些方法如下所示:

public void init(PeerGroup group, Advertisement adv);
public int startApp(String[] args);
public void stopApp();



管道和边界节点(pipes and endpoints)
像我们早先提到的那样,pipe是Jxta环境中用来进行消息传输的虚拟管道。Pipe由Pipe接口表示(net.jxta.pipe.Pipe),作为一种继承自Service (net.jxta.service.Service).接口的服务。Pipe被进一步的划分为输入管道(net.jxta.pipe.InputPipe)和输出管道(net.jxta.pipe.OutputPipe).PipeService 类(net.jxta.impl.pipe.PipeService)包含了使用绑定的pipe实现。

Pipe是建在在终端节点(endpoint)之上的。Endpoint类,net.jxta.impl.endpoint.Endpoint,是一个传输终结点的集合。Endpoint即可以使用propagate()方法来发送消息或是利用终结点消息实现(net.jxta.impl.endpoint.EndpointMessenger)来将消息发送到一个指定的终结点。这种终结点消息实现取决于具体的它所实现的传输协议的情况。举例来说,net.jxta.impl.endpoint.http.HttpNonBlockingMessenger类就是将终结点传输实现建立在HTTP协议的基础上的。


广告(Advertisements)
所有的广告都是从抽象超类Advertisement(net.jxta.document.Advertisement)继承下来的。由广告具体所代表的资源,我们可以将广告进一步划分为peer group广告(net.jxta.protocol.PeerGroupAdvertisement),管道广告(net.jxta.protocol.PipeAdvertisement),等等。广告由一个AdvertisementFactory 类 (net.jxta.document.AdvertisementFactory)创建。使用工厂方法有助于隐藏广告的内部实现。

服务(Services)
所有的服务都实现了Service 接口(net.jxta.service.Service)。服务是一个扩展了Application接口的应用。由于服务对象并不能够直接被操纵,所以通常都使用Service接口访问Service 对象。举例来说,Discovery接口 (net.jxta.discovery.Discovery) 代表 Discovery 服务。DiscoveryServic类(net.jxta.impl.discovery.DiscoveryService) 代表Discovery Service的实现。DiscoveryService类并不能够被直接访问,而需要使用DiscoveryInterface接口来访问。(net.jxta.impl.discovery.DiscoveryInterface).


Jxta community projects(Jxta社区工程)
我们已经提到过,Jxta是一个由开源开发者,技术狂热者和学术研究者参加的社区推动的工程。任何人都可以加入工程,并做出自己的贡献。Jxta.org 提出了一些很有意思的工程。我们来了解其中的几个。

The Jxta Shell
Jxta shell是一个建立在Jxta的Java实现上的范例应用程序。它以命令行方式为用户提供了一种互动接入方式到的Jxta。Jxta shell使用和Unix相似的界面并提供相似的命令帮助用户使用Jxta的源语。用户可以从shell homepage下载到Jxta Shell,它可以很容易的安装和配置。Jxta的Shell命令和Unix的命令很想象。并且支持管道操作符(|)

在Jxta shell当中,大部分的命令都可以被动态的加载和激活,命令的加载与平台框架相对独立。这就给了开发者一种方便的途径,在shell当中加入自己的命令。我们在这里列出一些基本的内嵌shell指令:

Man
   Man命令是Jxta的shell的帮助系统。使用这个命令可以列出当前的Jxta Shell当中所有可用的命令列表。如果需要查询某个特定命令的的帮助信息时,可以使用参数

Clear:
   将shell的屏幕清空

Env:
   Env命令将当前shell 会话的环境变量显示出来。缺省定义有七个环境变量:
1.        consin:缺省控制台输入管道
2.        consout:缺省控制台输出管道
3.        stdin:缺省输入管道
4.        stdout:缺省输出管道
5.        stdgroup:缺省peer group
6.        rootgroup:缺省 net peer group
7.        shell:根shell(root shell)

setenv:
设置一个shell环境变量

Cat:
     使用cat命令可以打印出一个Jxta对象的内容
Whoami
     显示出一个peer或者peer group的信息。如果没有加参数的话,显示出的是本地的peer信息。

Rdvstatus
     显示出peer当前所连接的所有的rendezvous peer。同时也显示出当前peer是否是一个rendezvous peer。

Peers
使用peers命令用于发现处在同一个peer group中的其它peer。如果不加参数就会列出当前peer的所有已知peer。这是应为所有被shell发现的广告信息都被缓存在了本地。使用-r参数将会清除保存在缓存中的peer广告信息。

Groups
   Groups命令类似于peers命令;用于发现peer groups。

Importfile
  将一个外部文件导入shell的环境变量

Exportfile
   将环境变量导出到一个文件中。

Mkadv
   使用mkadv命令将会根据shell环境变量信息生成一个广告。广告可以是peer group广告也可以是管道广告。

Mkpgrp
Mkpgrp命令将会使用peer 广告创建一个新的peer group。如果没有指定广告,shell将会创建一个net peer group的克隆。

Join
   使用join命令可以把peer将如到一个peer group当中

Leave
   使用leave命令可以使一个先前使用join命令加入peer group当中的peer退出该peer group

Mkpipe
  使用mkpipe命令将会传见一个输入或者输出管道。管道从一个本地的输入管道广告文件创立。

Talk
   使用talk命令可以在两个远程peer之间进行简单的,最小化的即时消息会话。它包括三个步骤。第一,用户注册,主要包括为那个用户创建一个新的talk广告,这是一个one-time过程。用户注册是使用talk -register 命令实现的。其次,一旦注册完成,用户可以登入并开始交谈。用户使用talk -login 命令进行登陆。用户还可以通过talk -search命令来搜索其它的用户。第三,一旦定位到另一位用户,当前用户可以使用talk -u 来发送消息。

Exit
  使用exit命令退出shell

Jxta 内容管理服务(The Jxta Content Manager Service)
Jxta 内容管理服务(通常称为CMS)用来帮助用户在一个peer group当中共享与获取由一个全局唯一的cotent ID所代表的内容。CMS同时也将内容通过元数据的形势表现出来。更进一部 ,CMS帮助用户对本地的内容进行管理,并允许用户通过它们浏览和下载其它远程peer的内容。

InstantP2P
InstantP2Pshi 是一个建立在jxta之上的peer-to-peer即时消息服务。它在功能上包括一对一的即时消息,群体聊天,文件共享等功能。它可以工作在Linux, Solaris,Win32等多种平台之上。使用Personal Java 3.1的设备也可以支持InstantP2P。

InstantP2P可以做为学习Jxta的一个良好范例。用户可以使用自己选择的昵称登陆进入这个应用程序。之后就可以搜寻所有在网络上可用的Jxta Group并选择加入它们。用户可以看到所以的group成员。使用chat选项来进行一对一的聊天,使用group chant进行群聊。使用share选项用户可以在group成员之间共享内容。用户也能够搜索group中的共享内容。InstantP2P内部使用内容管理服务来管理文件共享。

Jxta的未来
在这篇文章中,我向大家介绍了peer-to-peer网络。通过这些用户可以发现Jxta给P2P世界所提供的功能。我也为大家介绍了在创建基于Jxta的应用的时候一些重要的术语和概念。

Jxta将会成为P2P应用的地层开发平台。现在的Jxta还处在初级阶段,未来它会逐渐成熟提供一个强壮的,可靠的框架给P2P计算。由于Java是构建异构环境下应用的首选所以它也是建立P2P应用的自然选择。我希望这篇文章能够带给您启发,帮助您开始探索Jxta和P2P世界。

作者简介:
Navaneeth Krishnan是Aztec Software and Technology Solutions的资深产品工程师,曾为用户开发过多个电子商务解决方案和框架。他也是一位狂热的P2P技术爱好者,对Jxta有深入的研究。他的Jxta社区项目iPeers,用来集成在P2P网络中的人工智能。

资源列表:
Jxta工程主页
http://www.jxta.org
Jxta协议细节及白皮书
http://www.jxta.org/white_papers.html
The Jxta shell 工程主页
http://shell.jxta.org
The CMS 主页
http://cms.jxta.org
The InstantP2P主页
http://instantp2p.jxta.org/
如果想要了解更多的关于Gnutella网络的扩展性问题,        请阅读"Bandwidth Barriers to Gnutella Network Scalability" (Clip2, September 2000)一文:
http://www.clip2.com/dss_barrier.html
了解更多关于URIs,URLs,和URNs的知识
http://www.ietf.org/rfc/rfc2396.txt
"The Gnutella File-Sharing Network and Java," “Gnutella文件共享网络与Java”Ken McCrary (JavaWorld, October 2000):
http://www.javaworld.com/javaworld/jw-10-2000/jw-1006-fileshare.html
Mark Johnson 在JavaOne 2001对于创建新的P2P协议动机所做的报告"Get Connected with Jxta" (JavaWorld, June 2001):
http://www.javaworld.com/javaworld/javaone01/j1-01-jxta.html
更多的关于企业级Java,        请浏览JavaWorld的标        题索引:
http://www.javaworld.com/channel_content/jw-enterprise-index.shtml
订阅JavaWorld’s每周免费新闻邮件
http://www.idg.net/jw-subscribe
你可以在我们的姐妹刊物IDG.net上找到IT行业有价值的信息。

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=647185

 

你可能感兴趣的:(软件知识)