利用Vista和WCF中强大P2P通信功能

作者:Justin Smith | 日期:2008-05-23 | 字体:

  图 3 显示了完成后的应用程序。步骤 1 和 2 是开发任何 Windows 窗体应用程序时所必需的步骤,因此我将不在这里对其说明。对于任何 Windows Communication Foundation 应用程序,开发过程的第一步是定义服务合约。PeerChannel 要使用的服务合约类似于其他 Windows Communication Foundation 合约,只不过 PeerChannel 需要所有的 OperationContractAttribute 批注都将 IsOneWay 实例属性设置为 true。此属性规定消息的接收方不应发送回复。如果想要接收方发送回复,可以将服务合约定义为双向合约,但每个 OperationContractAttribute 批注仍必须将 IsOneWay 实例属性设置为 true。就此例而言,我不会创建一个双向合约(Windows SDK 中有几个双向合约的示例)。我要使用的合约如下所示:

  

      [ServiceContract]
  interface IPictureViewer {
  [OperationContract(IsOneWay = true)]
  void SharePicture(Stream stream);
  }

  PictureViewer P2P 应用程序

  图 3 PictureViewer P2P 应用程序

  请注意,SharePicture 接口方法用 OperationContractAttribute 属性加以批注,并且 IsOneWay 实例属性被设置为 true。SharePicture 操作将 System.IO.Stream 视为一个参数,因为此操作将被用于向网格中其他节点传送图片的字节。

  在定义了我们的服务合约后,现在就该添加 Windows Communication Foundation 代码,该代码会将我们的应用程序连接到 PeerChannel 网格并且被动等待来自网格的消息。首先,在窗体中实现新定义的服务合约。然后,定义类型 ServiceHost 的字段。所接收的消息将被发送到 frmPictureViewer 类型的单个实例。要表明此功能,我必须将正确的 ServiceBehavior 分配给 frmPictureViewer 类型。这两个步骤如下所示。

  实施服务合同

  

      [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
  public partial class frmPictureViewer : Form, IPictureViewer
  {
  // 托管接收者
  ServiceHost host;
  // 接收消息时将要调用的方法
  public void SharePicture(Stream stream)
  {
  // 获取图像
  Image image = Bitmap.FromStream(stream);
  // 在窗体的图片框中显示图像
  pbView.SizeMode = PictureBoxSizeMode.StretchImage;
  pbView.Image = image;
  }
  ... // 为清晰起见省略其他成员
  }
  接下来,我必须对 ServiceHost 进行实例化,添加端点并开始侦听外来的消息。由于我正在构建 Windows 窗体应用程序,因此实现此操作的逻辑位置就是窗体的构造函数,如下所示。

  尝试加入网格和侦听消息

  

      public frmPictureViewer()
  {
  InitializeComponent();
  StartReceiving();
  }
  private void StartReceiving()
  {
  // 定义网格名并设置与 PNRP 解析器的
  // 对等绑定
  Uri meshAddress = new Uri("net.p2p://pictureView");
  NetPeerTcpBinding binding = new NetPeerTcpBinding();
  binding.Resolver.Mode = PeerResolverMode.Pnrp;
  binding.Security.Transport.CredentialType =
  PeerTransportCredentialType.Password;
  binding.MaxReceivedMessageSize = 700000L;
  host = new ServiceHost(this);
  host.AddServiceEndpoint(typeof(IPictureViewer), binding,
  meshAddress);
  // 定义密码并获取数字签名证书
  host.Credentials.Peer.MeshPassword = "JustinSmith";
  host.Credentials.Peer.Certificate = GetCertificate();
  // 尝试联结和侦听消息
  host.Open();
  }
  此时,我已经完成了要连接到网格并侦听消息所需的所有步骤。与标准的 Windows Communication Foundation 代码相比,不同之处只在于 Uri 的方案 (net.p2p)、所使用的绑定 (NetPeerTcpBinding) 以及所增添的基于密码的安全性。请注意,我已选择将网格密码直接置于代码中,这一点很重要。如果想要使网格密码保密,请不要在您当前所使用的应用程序中如此操作。

  只要调用了 ServiceHost.Open,我们的应用程序就会尝试通过 PNRP 来解析网格名 (pictureView)。此时,我可以通过运行 netsh 命令以列出注册的对等名称来验证我们的 PeerChannel 应用程序是否正在使用 PNRP。如果 PNRP 可以将网格名解析为一个或多个 IP 地址,则我们的应用程序将尝试连接到这些节点。如果不是这样,则该节点将成为网格中的第一个节点。如前所述,现有节点将通过发送欢迎消息或拒绝消息来接受或拒绝连接。这里的重要一点是,这种情况有可能在对 ServiceHost.Open 的调用返回后发生。

  将消息发送到其他节点 在共享图片之前,我必须首先加载图片。实现此操作所需的代码是 Windows 窗体基本代码:首先,对 OpenFileDialog 进行实例化,获得一个 Stream,将该 Stream 转换为 Image,然后通过 PictureBox.Image 属性引用 Image。等一下,这不是 SharePicture 方法所执行的操作吗?事实上,确实如此。从本质上说,要将图像加载到 PictureBox 中,我只需要调用 SharePicture 方法,将从 OpenFileDialog.OpenFile 返回的 Stream 作为一个参数传递。

  要将包含图片的消息发送到网格中的其他节点,我必须编写几行代码,但是此代码与您在其他任何 Windows Communication Foundation 应用程序中编写的代码几乎相同。起初,我需要在类型 ChannelFactory 和 IPictureViewer 的窗体中定义一些字段。接下来,我需要在窗体的构造函数中将这些变量实例化。这些步骤如下所示。

  创建发送基础结构

  

      ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
  public partial class frmPictureViewer : Form, IPictureViewer
  {
  ChannelFactory channelFactory;
  IPictureViewer channel;
  public frmPictureViewer()
  {
  InitializeComponent();
  StartReceiving();
  }
  private void StartReceiving()
  {
  // 为清晰起见省略其他代码
  channelFactory = new ChannelFactory(
  binding, new EndpointAddress(meshAddress));
  channelFactory.Credentials.Peer.MeshPassword = "JustinSmith";
  channelFactory.Credentials.Peer.Certificate = GetCertificate();
  channel = channelFactory.CreateChannel();
  }
  ... // 为清晰起见省略其他代码
  }
  请注意,所使用的网格密码和证书(用于创建消息的数字签名)与设置 ServiceHost 时所用的必须是同一个。除此之外,此代码要与非 PeerChannel Windows Communication Foundation 应用程序中所需的代码相同。

  既然我已经构建了自己的发送基础结构,我就可以使用它向网格中的其他节点发送消息。为此,我只需为共享按钮编写一个事件处理程序即可,如下所示:

  

      private void btnShare_Click(object sender, EventArgs e)
  {
  using(MemoryStream stream = new MemoryStream())
  {
  Image image = pbView.Image;
  image.Save(stream, ImageFormat.Jpeg); // 将图像存储到 stream 中
  stream.Position = 0; // 复位位置
  channel.SharePicture(stream); // 向网格发送消息
  }
  }
  简言之,PeerChannel 大大简化了 P2P 应用程序的开发。PictureViewer 的完全功能版约有 150 行源代码,其中大部分代码专用于 Windows 窗体基础结构。这个功能完全的应用程序包含了一个跳跃计数实现。

  People Near Me

  PNM 是集成在 Windows Vista 之中的一种网格技术,它允许邻近的设备组和人员组相互发现、连接、邀请并进行协作。PNM 特别适用于这样一些任务:在咖啡店与邻座其他几个人一起玩游戏;与同事共享您的桌面;甚至连接到会议室中的投影仪,等等。PNM 提供的这些功能如此强大,我们有理由假设,一旦它被发布,开发人员社区就将会找到新的、具有独创性的方式来利用此技术。重要的是,要注意 PNM 是一项完全自选的网格技术,在默认情况下是关闭状态。

  除其他应用程序之外,PNM 体系结构包含了一个称为 p2phost.exe 的 P2P 应用程序。此进程运行时,将通过连接到其他计算机上 p2phost.exe 的实例来创建网格。通常而言,此网格的用途是定向消息传送。更确切地说,PNM 用于解析本地节点并与这些本地节点的子集进行通信。PNM API 作为 Windows API 的一部分提供,并且多半程度上侧重于配置 p2phost.exe 的行为。

  总的来说,PNM API 的主要类别包括函数、结构、事件和错误代码,通过这些类别可以向 PNM 注册应用程序、邀请其他人加入协作会话、启动已注册的应用程序、创建持久性合约并邀请不再属于本地的联系人。提要栏中的“真实环境中 People Near Me 的示例”将例示此过程。请注意,不支持应用程序使用 PNM 进行通信。就 PictureViewer 而言,这表示在提要栏中说明的 Tom 和 Harry 的 PictureViewer 实例之间传递的消息仍由 PeerChannel 来处理。

  结束语

  P2P 应用程序开发是一个涉及范围非常广泛的主题,并且对于多数开发人员而言还相当陌生。随着 Windows Vista 和 .NET Framework 3.0 的发布,P2P 应用程序的传统开发门槛将明显降低。我相信,技术的进步(如 PNRP、IPv6)加上更具生产力的新型平台的问世(如 PeerChannel 和 PNM)将在 P2P 应用程序开发领域开创一个新时代。最终,应用程序将更具协作性,并提供我们起初只能想像的一些功能。





上一页 [1] [2] [3]    
阅读: 次 | 来源:微软 | 录入:admin

评论 】 【 推荐 】 【 打印
上一篇:P2P网络“自由”穿越NAT的“秘密”
下一篇:P2P流媒体业务技术分析与设计
本文点评       全部点评
我要点评


字数

姓名:
 
广告内容
 
下面是广告内容