论文部分内容阅读
摘要:利用Windows Vista的增强功能并结合PNRP(对等名称解析协议)、PNM(People Near Me)和WCF(WindowsCommunication Foundation)中引进的PeerChannel功能,解决了传统的P2P应用程序开发中的常见问题。
关键词:对等名称解析协议;PNM;WCF;PeerChannel
0引言
从传统意义来说,P2P应用程序开发所面临的难题包括:需要开发用于消息交换的专用协议;必须查找并连接隐藏在“网络地址转换”(NAT)或防火墙背后的应用程序实例;需要支持在广域网(WAN)中定位各应用程序所需的惯常基础结构。这些问题将随着Windows Vista和.NET Framework的发布而得到解决。将Windows Vista的增强功能与PNRP、PNM和WCF中引进的PeerChannel功能相结合,就能顺利开发P2P应用程序。
1 P2P基本原理:网格计算
网格计算是利用互联网技术,把分散在不同地理位置的计算机组成一台虚拟超级计算机,其中每台计算机是一个“节点”,所有计算机就组成了节点网——网格。节点加入网格的方式取决于所使用的网格技术,通常,该节点必须用网格名来解析网格中已有的一个或多个节点的物理地址。在接收到网格中一个或多个节点的物理地址后,预期节点必须立即连接到这些地址中的一个、部分或全部地址,并应该准备好响应后续的其他预期节点的网格名解析请求。网格名解析是一个复杂的问题。这是因为,在许多情况下,网格名解析要依赖于一个或更多的其他网格。
节点连接到网格,它就可以通过以下两种方式之一与其他节点进行通信:网格扩散(也称多方消息传送),或定向消息传送。网格很少处于静态。在多数P2P应用程序中,由于网络连接变动,或者是用户启动和终止应用程序,节点可能会频繁地加入和离开网格。多数网格都具备一些维护机制。通常而言,网格维护的目标就是修复或调整网格以使其更高效或更稳健地运行;各种网格技术实现网格维护的方式都不同。
2 PNRP(对等名称解析协议)
PNRP完成网格名向物理地址的转变。PNRP v1可供Windows XP(SPl)以上版本使用。可以说,PNRP本身就是一个采用Windows服务形式的P2P应用程序,并且PNRP节点的网格专用于发现加入到其他网格中的节点的物理地址。
PNRP和1Pv6 PNRP构建于Internet协议版本IPv6之上。PNRP功能的原型、结构、错误代码均在Windows SDK的p2p.h头文件中定义。如果某应用程序想要向PNRP注册—个网格名,它必须用非托管代码通过Windows API实现,或用托管代码通过公共语言运行库(cLR)的P/Invoke工具实现。目前,在Windows API的PNRP部分的.NET Framework中未包含托管包装。但通过使用netsh命令行实用程序能访问PRNP。命令向PNRP注册—个新的PNRP名可以使用以下命令:
c:\temp>netsh
netsh>p2p pnrp peer
netsh p2p pnrp peer>add 0.baogxm
Ok.
0.baogxm即是P2P名。当此命令执行时,PNRP会生成--5"-PNRP ID,将该PNRP ID与P2P名相关联,并为该PNRP ID分配—个IPv6和IPv4地址。如果访问另一台已安装PNRP并已启动的计算机,则可以用以下netsh命令解析网格名0.baogxm:
netsh p2p pnrp peer>resolve 0.baogxm
Resolve started...
Found:Comment:gonzo//Comment字段代表注册了0.baogxm的计算机名称,该字段从netsh自动填充,并且不能用作解析进程的一部分
Addresses:[0000:0000:0000:0000:0000:0000:0000:0001]:8350 udp
210.41.35.1 99:8350 tcp
3 PeerChannel
WCF为许多不同类型的分布式应用程序提供了一个通用的编程模型。使用这个通用编程模型可以构建P2P应用程序。实际上,PeerChannel WCF模块专用于构建P2P应用程序。
PeerChannel网格专为消息扩散而设计。PeerChannel网格的结构由每个节点所连接的邻居数量所控制,PeerChannel网格会主动维护网格的结构。更具体点说,网格中的节点会将连接的邻居数保持在2~7个之间,以使本地节点的资源需求与保持网格稳健性之间取得平衡。假设某节点在进入网格时带有3个邻居,随后其中2个邻居离开了网格,则该节点将开始一个维护周期以获取新的邻居。当一个PeerChannel节点连有3个邻居时,则认为它处于理想的连接状态,但一个节点可以接受多达7个邻居,以便低于邻居数最低阈值的节点能迅速获得新的邻居。应注意的是,应用程序不能更改这些阈值或对网格的维护实施任何控制,这些细节问题完全由PeerChannel基础结构逐个节点地处理。
PeerChannel提供了PNRP解析程序和自定义解析程序,用于预期节点发现网格中已有节点的地址。这两种方法都将网格名传递给解析程序并接收网格中其他节点的IP地址列表。一旦解析进程生成地址列表,预期PeerChannel节点就并发连接到每个地址。当PeerChannel网格中已有的节点收到其中一个连接请求时,它可以接受或拒绝该连接。如果接受该连接,则节点会向新连接的节点发送一条包含网格中其他节点地址列表的欢迎消息。如果拒绝该连接,则节点会向预期节点发送一条包含拒绝理由以及网格中其他节点地址列表的拒绝消息。
PeerChannel向预期节点返回地址列表的方式,不限于网格名解析(通过PNRP解析程序或自定义解析程序执行)。与将网格名解析作为预期节点获取地址的惟一方法相比,这可使节点更快速地进入理想的连接状态,也可使网格中的节点可对节点拥有的邻居数(这一因素会进而影响网格的稳健性)进行控制。
PeerChannel网格内节点问传送消息的重复率和网络带宽消耗较低。网格中的节点在网格内发送消息,实际上是在向其邻居发送消息。收到消息后,每个邻居都会检验该消息,然后将其转发给自己的邻居。节点从某邻居收到消息,不会将此消息转发回该邻居。此外,如果节点多次从某邻居收到先前已收到并处理过的消息,则与该邻居的连接会在下一个维护周期中终止。这些功能是通过节点上的本地高速缓存来实现的。PeerChannel网格中的每个节点都会对WS-Addressing消息ID的值和传送消息的 邻居的标识符进行缓存处理,在决定向哪些邻居传送该消息时会检查这个高速缓存。
PeerChannel节点还可以将消息发送给网格中节点的子集。这通过向消息分配一个跳跃计数实现。跳跃计数是模糊界定接收消息的节点数的一种方法。例如,如果一个PeerChannel节点(节点A)有3个邻居且在跳跃计数为1的情况下向网格发送一个消息,则该消息将被传送到3个节点。同样,如果节点A的每个邻居也都有3个邻居且节点A在跳跃计数为2的情况下向网格发送一个消息,则该消息将被传送到9个节点。但如果节点A的任一邻居有共用的邻居,则此数字将相应减少。
从物理上说,跳跃计数在消息中被表示为标头块中的一个整数。当某节点收到带有跳跃计数的消息时,它会检查跳跃计数的值。如果该值大于零,节点会单调递减此跳跃计数,然后将带有递减后的跳跃计数值的消息转发给相应邻居。如果节点所接收消息中包含的跳跃计数为0,则不转发该消息。需要注意的是,跳跃计数标头块被排除在消息签名之外,因此更改这个值不会影响到应用于消息的数字签名的完整性,而且会避免产生与重复生成数字签名并将其序列化到消息相应部分中的相关开销。
4 People Near Me
PNM是集成在Windows Vista之中的一种网格技术,它允许邻近的设备组和人员组相互发现、连接、邀请并进行协作。PNM是一项完全自选的网格技术,默认情况下处于关闭状态。PNM体系结构包含了一个称为p2phost.exe的P2P应用程序。此程序运行时,将通过连接到其他计算机上p2phost.exe的实例来创建网格。PNM用于解析本地节点并与这些本地节点的子集进行通信。PNM API作为Windows API的一部分,主要用于配置p2phost.exe。
5 PeerChannel实例
利用PeerChannel构建P2P应用程序的步骤如下:
(1)定义基本的Windows窗体样板代码。
(2)向窗体添加控件。
(3)定义必需的WCF服务合同。
(4)编写连接到网格和从网格接收消息的WCF代码。
(5)编写向网格中其他节点发送消息的代码。
对于任何WCF应用程序,开发过程的第一步是定义服务合同。PeerChannel要使用的服务合同类似于其他WCF合同,只不过PeerChannel中所有的OperationContractAttribute都将IsOneWay实例属性设置为true。此属性规定消息的接收方是否应发送回复。如果想要接收方发送回复,可以将服务合同定义为双向合同,但每个OperationContractAttribute仍必须将IsOneWay实例属性设置为true。定义合同代码如下:
[ServiceContract]
interface IPictureViewer{
[OpemtionContract(IsOneWay=true)]//
void SharePicture(Stream stream)://SharePicture接口方法用
OperationContractAttdbute属性加以说明,并且IsOneWay实例属性被设置为true。此操作将被用于向网格中其他节点传送图片的字节
}
在定义了服务合同后,需要添加WCF代码,该代码会将我们的应用程序连接到PeerChannel网格并且被动等待来自网格的消息。首先,在窗体中实现新定义的服务合同;然后,定义类型ServiceHost的字段。所接收的消息将被发送到frmPictureViewer类型的单个实例。要显示此功能,我们必须将正确的ServiceBehavior分配给frmPictureViewer类型。
接下来,必须对ServiceHost进行实例化,添加端点并开始侦听外来的消息。由于构建的是Windows窗体应用程序,因此实现此操作的逻辑位置就是窗体的构造函数。到此,已经完成了连接到网格并侦听消息所需的所有步骤。与标准的WCF代码相比,只在URI的方案(net.p2p)、所使用的绑定(NetPeerTcpBinding)以及所增添的基于密码的安全性方面有所不同。
只要调用了ServiceHost.Open,我们的应用程序就会通过PNRP来解析网格名(pictureView)。此时,可以通过运行netsh命令以列出注册的对等名称来验证我们的PeerChannel应用程序是否正在使用PNRP。如果PNRP可以将网格名解析为一个或多个IP地址,则我们的应用程序将尝试连接到这些节点。如果不是这样,则该节点将成为网格中的第一个节点。如前所述,现有节点将通过发送欢迎消息或拒绝消息来接受或拒绝连接。这种情况有可能在对ServiceHost.Open的调用返回后发生。
加载共享图片的代码是Windows窗体基本代码:首先,对OpenFileDialog进行实例化,获得一个Stream,将该Stream转换为Image,然后通过PictureBox.Image属性引用Image。实际上,要将图像加载到PictureBox中,只需调用Sharepicmm方法,将从OperlFileDialog.OpenFile返回的Stream作为参数传递。
要将包含图片的消息发送到网格中的其他节点,需要在类型ChannelFactory和IPictureViewer的窗体中定义一些字段,然后在窗体的构造函数中将这些变量实例化。
请注意,所使用的网格密码和证书(用于创建消息的数字签名)必须与设置ServiceHost时所用的相同。此外,其代码也要与非PeerChannel WCF应用程序中的代码相同。
构建了发送基础结构后,就可以使用它向网格中的其他节点发送消息。为此只需为共享按钮编写一个如下所示的事件处理程序:
private void btnShare_Click(object sender,EventArgs e)
{using(MemoryStream stream=new Memo~Stream())
{Image image=pbView.Image;
image.Save(stream,ImageFormat.Jpeg);
//将图像存储到stream中
stream.Position=O;//复位位置
channel.SharePicture(stream);//向网格发送消息
}
}
6 结束语
随着Windows Vista和.NET Framework 3.0的发布,P2P应用程序的开发门槛将明显降低。我们相信,技术的进步(如PNRP、IPv6)加上更具生产力的新型平台的问世(如PeerChannel和PNM)将在P2P应用程序开发领域开创一个新时代。最终,应用程序将更具协作性,并完成我们原来只能想像的一些功能。
注:本文中所涉及到的图表、注解、公式等内容请以PDF格式阅读原文。
关键词:对等名称解析协议;PNM;WCF;PeerChannel
0引言
从传统意义来说,P2P应用程序开发所面临的难题包括:需要开发用于消息交换的专用协议;必须查找并连接隐藏在“网络地址转换”(NAT)或防火墙背后的应用程序实例;需要支持在广域网(WAN)中定位各应用程序所需的惯常基础结构。这些问题将随着Windows Vista和.NET Framework的发布而得到解决。将Windows Vista的增强功能与PNRP、PNM和WCF中引进的PeerChannel功能相结合,就能顺利开发P2P应用程序。
1 P2P基本原理:网格计算
网格计算是利用互联网技术,把分散在不同地理位置的计算机组成一台虚拟超级计算机,其中每台计算机是一个“节点”,所有计算机就组成了节点网——网格。节点加入网格的方式取决于所使用的网格技术,通常,该节点必须用网格名来解析网格中已有的一个或多个节点的物理地址。在接收到网格中一个或多个节点的物理地址后,预期节点必须立即连接到这些地址中的一个、部分或全部地址,并应该准备好响应后续的其他预期节点的网格名解析请求。网格名解析是一个复杂的问题。这是因为,在许多情况下,网格名解析要依赖于一个或更多的其他网格。
节点连接到网格,它就可以通过以下两种方式之一与其他节点进行通信:网格扩散(也称多方消息传送),或定向消息传送。网格很少处于静态。在多数P2P应用程序中,由于网络连接变动,或者是用户启动和终止应用程序,节点可能会频繁地加入和离开网格。多数网格都具备一些维护机制。通常而言,网格维护的目标就是修复或调整网格以使其更高效或更稳健地运行;各种网格技术实现网格维护的方式都不同。
2 PNRP(对等名称解析协议)
PNRP完成网格名向物理地址的转变。PNRP v1可供Windows XP(SPl)以上版本使用。可以说,PNRP本身就是一个采用Windows服务形式的P2P应用程序,并且PNRP节点的网格专用于发现加入到其他网格中的节点的物理地址。
PNRP和1Pv6 PNRP构建于Internet协议版本IPv6之上。PNRP功能的原型、结构、错误代码均在Windows SDK的p2p.h头文件中定义。如果某应用程序想要向PNRP注册—个网格名,它必须用非托管代码通过Windows API实现,或用托管代码通过公共语言运行库(cLR)的P/Invoke工具实现。目前,在Windows API的PNRP部分的.NET Framework中未包含托管包装。但通过使用netsh命令行实用程序能访问PRNP。命令向PNRP注册—个新的PNRP名可以使用以下命令:
c:\temp>netsh
netsh>p2p pnrp peer
netsh p2p pnrp peer>add 0.baogxm
Ok.
0.baogxm即是P2P名。当此命令执行时,PNRP会生成--5"-PNRP ID,将该PNRP ID与P2P名相关联,并为该PNRP ID分配—个IPv6和IPv4地址。如果访问另一台已安装PNRP并已启动的计算机,则可以用以下netsh命令解析网格名0.baogxm:
netsh p2p pnrp peer>resolve 0.baogxm
Resolve started...
Found:Comment:gonzo//Comment字段代表注册了0.baogxm的计算机名称,该字段从netsh自动填充,并且不能用作解析进程的一部分
Addresses:[0000:0000:0000:0000:0000:0000:0000:0001]:8350 udp
210.41.35.1 99:8350 tcp
3 PeerChannel
WCF为许多不同类型的分布式应用程序提供了一个通用的编程模型。使用这个通用编程模型可以构建P2P应用程序。实际上,PeerChannel WCF模块专用于构建P2P应用程序。
PeerChannel网格专为消息扩散而设计。PeerChannel网格的结构由每个节点所连接的邻居数量所控制,PeerChannel网格会主动维护网格的结构。更具体点说,网格中的节点会将连接的邻居数保持在2~7个之间,以使本地节点的资源需求与保持网格稳健性之间取得平衡。假设某节点在进入网格时带有3个邻居,随后其中2个邻居离开了网格,则该节点将开始一个维护周期以获取新的邻居。当一个PeerChannel节点连有3个邻居时,则认为它处于理想的连接状态,但一个节点可以接受多达7个邻居,以便低于邻居数最低阈值的节点能迅速获得新的邻居。应注意的是,应用程序不能更改这些阈值或对网格的维护实施任何控制,这些细节问题完全由PeerChannel基础结构逐个节点地处理。
PeerChannel提供了PNRP解析程序和自定义解析程序,用于预期节点发现网格中已有节点的地址。这两种方法都将网格名传递给解析程序并接收网格中其他节点的IP地址列表。一旦解析进程生成地址列表,预期PeerChannel节点就并发连接到每个地址。当PeerChannel网格中已有的节点收到其中一个连接请求时,它可以接受或拒绝该连接。如果接受该连接,则节点会向新连接的节点发送一条包含网格中其他节点地址列表的欢迎消息。如果拒绝该连接,则节点会向预期节点发送一条包含拒绝理由以及网格中其他节点地址列表的拒绝消息。
PeerChannel向预期节点返回地址列表的方式,不限于网格名解析(通过PNRP解析程序或自定义解析程序执行)。与将网格名解析作为预期节点获取地址的惟一方法相比,这可使节点更快速地进入理想的连接状态,也可使网格中的节点可对节点拥有的邻居数(这一因素会进而影响网格的稳健性)进行控制。
PeerChannel网格内节点问传送消息的重复率和网络带宽消耗较低。网格中的节点在网格内发送消息,实际上是在向其邻居发送消息。收到消息后,每个邻居都会检验该消息,然后将其转发给自己的邻居。节点从某邻居收到消息,不会将此消息转发回该邻居。此外,如果节点多次从某邻居收到先前已收到并处理过的消息,则与该邻居的连接会在下一个维护周期中终止。这些功能是通过节点上的本地高速缓存来实现的。PeerChannel网格中的每个节点都会对WS-Addressing消息ID的值和传送消息的 邻居的标识符进行缓存处理,在决定向哪些邻居传送该消息时会检查这个高速缓存。
PeerChannel节点还可以将消息发送给网格中节点的子集。这通过向消息分配一个跳跃计数实现。跳跃计数是模糊界定接收消息的节点数的一种方法。例如,如果一个PeerChannel节点(节点A)有3个邻居且在跳跃计数为1的情况下向网格发送一个消息,则该消息将被传送到3个节点。同样,如果节点A的每个邻居也都有3个邻居且节点A在跳跃计数为2的情况下向网格发送一个消息,则该消息将被传送到9个节点。但如果节点A的任一邻居有共用的邻居,则此数字将相应减少。
从物理上说,跳跃计数在消息中被表示为标头块中的一个整数。当某节点收到带有跳跃计数的消息时,它会检查跳跃计数的值。如果该值大于零,节点会单调递减此跳跃计数,然后将带有递减后的跳跃计数值的消息转发给相应邻居。如果节点所接收消息中包含的跳跃计数为0,则不转发该消息。需要注意的是,跳跃计数标头块被排除在消息签名之外,因此更改这个值不会影响到应用于消息的数字签名的完整性,而且会避免产生与重复生成数字签名并将其序列化到消息相应部分中的相关开销。
4 People Near Me
PNM是集成在Windows Vista之中的一种网格技术,它允许邻近的设备组和人员组相互发现、连接、邀请并进行协作。PNM是一项完全自选的网格技术,默认情况下处于关闭状态。PNM体系结构包含了一个称为p2phost.exe的P2P应用程序。此程序运行时,将通过连接到其他计算机上p2phost.exe的实例来创建网格。PNM用于解析本地节点并与这些本地节点的子集进行通信。PNM API作为Windows API的一部分,主要用于配置p2phost.exe。
5 PeerChannel实例
利用PeerChannel构建P2P应用程序的步骤如下:
(1)定义基本的Windows窗体样板代码。
(2)向窗体添加控件。
(3)定义必需的WCF服务合同。
(4)编写连接到网格和从网格接收消息的WCF代码。
(5)编写向网格中其他节点发送消息的代码。
对于任何WCF应用程序,开发过程的第一步是定义服务合同。PeerChannel要使用的服务合同类似于其他WCF合同,只不过PeerChannel中所有的OperationContractAttribute都将IsOneWay实例属性设置为true。此属性规定消息的接收方是否应发送回复。如果想要接收方发送回复,可以将服务合同定义为双向合同,但每个OperationContractAttribute仍必须将IsOneWay实例属性设置为true。定义合同代码如下:
[ServiceContract]
interface IPictureViewer{
[OpemtionContract(IsOneWay=true)]//
void SharePicture(Stream stream)://SharePicture接口方法用
OperationContractAttdbute属性加以说明,并且IsOneWay实例属性被设置为true。此操作将被用于向网格中其他节点传送图片的字节
}
在定义了服务合同后,需要添加WCF代码,该代码会将我们的应用程序连接到PeerChannel网格并且被动等待来自网格的消息。首先,在窗体中实现新定义的服务合同;然后,定义类型ServiceHost的字段。所接收的消息将被发送到frmPictureViewer类型的单个实例。要显示此功能,我们必须将正确的ServiceBehavior分配给frmPictureViewer类型。
接下来,必须对ServiceHost进行实例化,添加端点并开始侦听外来的消息。由于构建的是Windows窗体应用程序,因此实现此操作的逻辑位置就是窗体的构造函数。到此,已经完成了连接到网格并侦听消息所需的所有步骤。与标准的WCF代码相比,只在URI的方案(net.p2p)、所使用的绑定(NetPeerTcpBinding)以及所增添的基于密码的安全性方面有所不同。
只要调用了ServiceHost.Open,我们的应用程序就会通过PNRP来解析网格名(pictureView)。此时,可以通过运行netsh命令以列出注册的对等名称来验证我们的PeerChannel应用程序是否正在使用PNRP。如果PNRP可以将网格名解析为一个或多个IP地址,则我们的应用程序将尝试连接到这些节点。如果不是这样,则该节点将成为网格中的第一个节点。如前所述,现有节点将通过发送欢迎消息或拒绝消息来接受或拒绝连接。这种情况有可能在对ServiceHost.Open的调用返回后发生。
加载共享图片的代码是Windows窗体基本代码:首先,对OpenFileDialog进行实例化,获得一个Stream,将该Stream转换为Image,然后通过PictureBox.Image属性引用Image。实际上,要将图像加载到PictureBox中,只需调用Sharepicmm方法,将从OperlFileDialog.OpenFile返回的Stream作为参数传递。
要将包含图片的消息发送到网格中的其他节点,需要在类型ChannelFactory和IPictureViewer的窗体中定义一些字段,然后在窗体的构造函数中将这些变量实例化。
请注意,所使用的网格密码和证书(用于创建消息的数字签名)必须与设置ServiceHost时所用的相同。此外,其代码也要与非PeerChannel WCF应用程序中的代码相同。
构建了发送基础结构后,就可以使用它向网格中的其他节点发送消息。为此只需为共享按钮编写一个如下所示的事件处理程序:
private void btnShare_Click(object sender,EventArgs e)
{using(MemoryStream stream=new Memo~Stream())
{Image image=pbView.Image;
image.Save(stream,ImageFormat.Jpeg);
//将图像存储到stream中
stream.Position=O;//复位位置
channel.SharePicture(stream);//向网格发送消息
}
}
6 结束语
随着Windows Vista和.NET Framework 3.0的发布,P2P应用程序的开发门槛将明显降低。我们相信,技术的进步(如PNRP、IPv6)加上更具生产力的新型平台的问世(如PeerChannel和PNM)将在P2P应用程序开发领域开创一个新时代。最终,应用程序将更具协作性,并完成我们原来只能想像的一些功能。
注:本文中所涉及到的图表、注解、公式等内容请以PDF格式阅读原文。