与 .NET Framework 3.5 接轨(转)
http://msdn.microsoft.com/zh-cn/magazine/cc163356.aspx
网络
与 .NET Framework 3.5 接轨
Mariya Atanasova and Larry Cleeton and Mike Flasko and Amit Paka
本文讨论:
|
本文使用了以下技术:
.NET Framework |
在 Microsoft® .NET Framework 中,System.Net 命名空间公开了 HTTP 和 SMTP 等多种网络协议的功能。即将发布的 .NET Framework 3.5(将随以前代号为“Orcas”的 Visual Studio® 2008 一起交付)包含了针对这些核心网络层的多种增强性能和功能。在本文中,我们将了解一下 System.Net 团队提供的三个关键更改:
- 高性能 Socket API
- 对 URI 的国际化资源标识符支持
- 对等 (P2P) 命名空间
即将发布的 .NET Framework 3.5 将推出对 Framework 本身所做的更改。本文所描述的功能在 Visual Studio 2008 测试版 1 中提供,该测试版可从 MSDN® 下载。
Socket 类性能
在 .NET Framework 2.0 版本中,System.Net.Sockets 命名空间提供了一个几乎拥有 Windows® WinSock Win32®
API 的所有功能的 Socket 类。该功能所属的类包含为托管代码开发人员设计的各种方法和属性。在 Socket 上,有一组包括 Send 和
Receive 在内的同步方法,具备针对各种情况的参数重载。这些同步方法不仅易于使用,而且非常适合于使用套接字的简单网络任务。Socket
上还有一组基于异步编程模型 (APM) 的异步方法,APM 在 .NET Framework 中非常普遍(有关详细信息,请参阅 msdn.microsoft.com/msdnmag/issues/07/03/ConcurrentAffairs)。这些异步方法让 Socket 类的异步使用相对简单,而且还提供了一种方法来处理许多套接字,或处理在许多套接字上进行的多个发送和接收操作。
2.0
版本的 Socket 类适合多种需要使用网络套接字的客户端应用程序,以及一些服务器和服务类型的应用程序。遗憾的是,一些服务应用程序方案不适用于
2.0 版本的 Socket 类,却和直接使用 Windows WinSock API 的本机语言相容。2.0 版本的 Socket
类的主要问题是它不仅在分配必要的基础对象以便在大量套接字上同时保持 I/O 操作时需要占用过多的 CPU 循环,而且在执行单个套接字 I/O
操作时也同样如此。
凭
借 .NET Framework 3.5,公共语言运行时 (CLR) 便可以更有效地同时管理大量的 Overlapped 对象。CLR 中的
Overlapped 对象可以有效封装用于管理异步 I/O 操作的本机 Windows OVERLAPPED 结构。每个进行中的 Socket
异步 I/O 操作中都有一个 Overlapped 对象实例。现在可以拥有 6
万个甚至更多的连接套接字,并同时在每个套接字上保持一个挂起的异步接收 I/O 操作。
2.0
版本的 Socket 类使用 Windows I/O 完成端口来完成异步 I/O
操作。这使应用程序可以轻易地扩展到大量的打开的套接字。.NET Framework 实现了
System.Threading.ThreadPool 类,该类提供可读取完成端口并完成异步 I/O 操作的完成线程。在开发即将发布的 3.5
版本的 .NET Framework 的过程中,我们将大量的精力放在了消除代码路径中的开销上,包括读取完成端口和调用应用程序的完成代理或在
IAsyncResult 对象中发出 I/O 完成事件对象信号之间。
.NET
Framework 中的 APM 也称为 Begin/End 模式。这是因为会调用 Begin 方法来启动异步操作,然后返回一个
IAsyncResult 对象。可以选择将一个代理作为参数提供给 Begin 方法,异步操作完成时会调用该方法。或者,一个线程可以等待
IAsyncResult.AsyncWaitHandle。当回调被调用或发出等待信号时,就会调用 End
方法来获取异步操作的结果。这种模式很灵活,使用相对简单,在 .NET Framework 中非常常见。
但
是,您必须注意,如果进行大量异步套接字操作,是要付出代价的。针对每次操作,都必须创建一个 IAsyncResult
对象,而且该对象不能被重复使用。由于大量使用对象分配和垃圾收集,这会影响性能。为了解决这个问题,新版本提供了另一个使用套接字上执行异步 I/O
的方法模式。这种新模式并不要求为每个套接字操作分配操作上下文对象。
我们没有创建全新的模式,而只是采用现有模式并做了一个基本更改。现在,在 Socket 类中有了一些方法,它们使用基于事件的完成模型的变体。在 2.0 版本中,您可以使用下列代码在某个套接字上启动异步发送操作:
void OnSendCompletion(IAsyncResult ar) { } IAsyncResult ar = socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, OnSendCompletion, state);
在新版本中,您还可以实现:
void OnSendCompletion(object src, SocketAsyncEventArgs sae) { } SocketAsyncEventArgs sae = new SocketAsyncEventArgs(); sae.Completed += OnSendCompletion; sae.SetBuffer(buffer, 0, buffer.Length); socket.SendAsync(sae);
这
里有一些明显的差别。封装操作上下文的是一个 SocketAsyncEventArgs 对象,而不是 IAsyncResult
对象。该应用程序创建并管理(甚至可以重复使用)SocketAsyncEventArgs 对象。套接字操作的所有参数都由
SocketAsyncEventArgs 对象的属性和方法指定。完成状态也由 SocketAsyncEventArgs
对象的属性提供。最后,需要使用事件处理程序回调完成方法。
所
有这些更改都显著改进了 .NET Framework 3.5 中 System.Net.Sockets
类的性能和可伸缩性。现有应用程序可以自动实现其中的两项改进。第三项改进,即新型 Socket
方法,只能通过修改应用程序而得到使用,但这些方法都能为基于套接字的高要求应用程序提供更理想的可伸缩性。
国际化资源标识符支持
Web 地址通常使用由一组非常有限的字符组成的通用资源标识符 (URI) 来表示。一般来说,这些地址中只能包含英文字母表中的大、小写字母、数字 0 到 9 以及少量其他包括逗号和连字符在内的 ASCII 符号。
对
于世界上使用非拉丁字母字符集(如日文和希伯莱文)的地区来说,这种语法不是很方便。设想一下诸如
www.BaldwinMuseumOfScience.com 的地址,如果您讲英语,这个地址便很容易理解和记忆。但是,如果您不会说英语,则这个
URL 看上去跟符号的随机排列没什么差别。如果您只会说英语,您能记住用中文写的一长串地址吗?
国际化资源标识符(或 IRI)支持非 ASCII 字符,或者更准确的说是 Unicode/ISO 10646 字符。这意味着域名可以包含 Unicode 字符,即可以有这样的 URL:http://微軟香港.com。
我们已将现有的 System.Uri 类扩展为根据 RFC 3987 提供 IRI 支持(请参见 faqs.org/rfcs/rfc3987.html)。对于当前的用户来说,除非他们特意选择启用 IRI 功能,否则不会看到 .NET Framework 2.0 的行为有任何变化。原因是我们要确保 3.5 版本与以前版本的应用程序兼容。
如果选择采用,您必须做两项更改。首先,将下列元素添加到 machine.config 文件:
<section name="uri" type="System.Configuration.UriSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
然后,指定是否应将国际化域名 (IDN) 分析应用到域名中,以及是否应该应用 IRI 分析规则。这可以在整个计算机范围的 machine.config 或单个应用程序的 app.config 中进行,如:
<configuration> <uri> <idn enabled="All" /> <iriParsing enabled="true" /> </uri> </configuration>
启
用 IDN 可以将域名中的所有 Unicode 标签转换成其 Punicode 等同项。Punicode 名称只含有 ASCII
字符,而且总是以前缀“xn--”开头。这是因为 Internet 上目前部署的大多数 DNS 服务器仅支持 ASCII 字符。启用 IDN
只会影响 Uri.DnsSafeHost 属性的值。对于微軟香港.com 来说,它包含 xn--g5tu63aivy37i.com,而
Uri.Host 将包含 Unicode 字符。
根据您所使用的 DNS 服务器,在 idn 元素的已启用属性中,有三种可能的 IDN 值供您使用:
- “All”会将 IDN 名称 (Punicode) 用于所有域名。
- “AllExceptIntranet”会将 IDN 名称用于所有外部域名,而将 Unicode 名称用于所有内部域名。仅当 Intranet DNS 服务器支持 Unicode 名称时,这种情况才适用。
- “None”是默认值,它和 .NET Framework 2.0 的行为相符。
启用 IRI 分析 (iriParsing enabled = "true") 后,系统会根据 RFC 3987 中的最新 IRI 规则进行规范化和字符检查。当默认值为 false 时,则会根据 RFC 2396(请参见 faqs.org/rfcs/rfc2396.html)进行规范化和字符检查。要了解有关通用资源标识符和 Uri 类的更多信息,请参阅在线文档,地址为 msdn2.microsoft.com/system.uri。
System.Net.PeerToPeer 命名空间
作
为新增到 .NET Framework 3.5 的一个令人兴奋的新命名空间,System.Net.PeerToPeer 命名空间位于
System.Net.dll 程序集中,它提供了轻松创建对等 (P2P) 应用程序所需的核心构建基块。该命名空间是根据典型的 P2P
应用程序的三个阶段而设计的,即:发现、连接和通信。发现阶段负责动态定位对等点及其相关的网络位置。连接阶段负责在对等点之间建立网络连接。而通信阶段
则负责在对等点之间来回传输数据。
System.Net.PeerToPeer
命名空间中的功能提供了很多推动发现和连接阶段的选项。同时,诸如 Socket、HTTPWebRequest 和 Window
Communication Foundation Peer Channel 之类的配套技术可以为通信阶段提供解决方案。
在
对等点之间可以进行通信之前,它们必须能够发现彼此并根据名称或其他类型的标识符解析它们的网络位置(地址、协议和端口)。由于瞬时连接、DNS
中缺少地址记录以及动态 IP 地址等原因,对等点发现彼此并解析位置的方法很复杂。.NET Framework 3.5 中支持的对等名称解析协议
(PNRP) 功能不仅有助于发现,还可以通过无服务器的名称解析将任何资源解析为一组网络终结点,从而实现对等点之间的通信。PNRP
承担两项核心任务:发布供其他对等点解析的对等名;解析另一个对等点发布的对等名,并检索相关元数据(要了解有关 PNRP
协议如何工作的更多信息,请参阅 microsoft.com/p2p)。
在
System.Net.PeerToPeer
命名空间中,一个对等名代表一个通信终结点,该终结点可以是您希望与元数据相关联的任何对象(如计算机、服务或应用程序)。对等名有两种形式:安全的和不
安全的。安全的对等名由一个公/私钥对支持,当使用 PNRP 进行注册时,不会受到欺骗。每个对等名字符串都有一个 Authority
节,后面跟有一个句点,然后是一个 Classifier 节。Authority 节是由计算机根据对等名的类型(安全的或不安全的)生成的;而
classifier 则是用户定义的字符串。
对于一个安全的对等名来说,Framework 会自动创建一个由 40 个字符组成的十六进制字符串作为 Authority。此十六进制字符串是由和对等名关联的公钥组成的哈希 (Hash),用于确保此类对等名注册不会受到欺骗。下面是创建安全对等名的方法:
PeerName p = new PeerName("My PeerName", PeerNameType.Secured);
对于不安全的对等名,Authority 组件总是为字符 0。不安全的对等名只是一个字符串,不提供安全保障:
PeerName p = new PeerName("My PeerName", PeerNameType.UnSecured);
创
建对等名之后,接下来要通过实例化 PeerNameRegistration 对象将此名称与相关元数据关联起来。一个对等名通常与一个 IP
地址相关联,但就像您将看到的一样,一个对等名也可以与一个注解字符串和二进制数据 blob 相关联。在下列代码段中,通过将一个
PeerEndPoint 实例添加到注册终结点集合,可以使一个 IP 地址与对等名产生显式关联:
PeerName peerName = new PeerName("My PeerName", PeerNameType.Secured); PeerNameRegistration pnReg = new PeerNameRegistration(); pnReg.PeerName = peerName; pnReg.EndPointCollection.Add(new IPEndPoint( IPAddress.Parse("<ip address to associate with the name>"), 5000)); pnReg.Comment = "up to 39 unicode char comment"; pnReg.Data = System.Text.Encoding.UTF8.GetBytes( "A data blob up to 4K associated with the name");
虽
然这是对 PeerNameRegistration
类的合法使用,但是我们发现,常见的情形是将所有分配给本地计算机的地址与对等名相关联。要做到这一点,您只要确保
PeerNameRegistration.UseAutoEndPointSelection 的属性设置为 true,并且不要对
PeerNameRegistration.EndPointCollection 进行任何添加即可。
现
在所有相关元数据都通过 PeerNameRegistration
对象被分配给该对等名,最后一步是将该对等名发布到群中,以便其他对等点可以解析该名称。在 PNRP 中,群只是一组参与 PNRP
的计算机,它定义众多名称的发布或解析范围。在发布一个名称时,您需要确定要将名称发布到哪个群(或范围)。
PNRP
目前使用两种群:链接-本地群和全局群。一个对等名若发布到链接-本地群就意味着只有同一链接上的其他对等点可以解析该名称。而发布到全局群上的对等名则
允许 Internet 上的任何人解析该名称。要将对等名发布到全局群,您只需通过 Cloud.Global 枚举将该全局群分配到
PeerNameRegsitration 对象的 Cloud 属性,然后对注册对象调用 Start 方法即可。一旦 start
方法调用完成,该名称就发布了,而且可以被远程对等点解析。图 1 显示了用于创建和发布对等名的代码。
Figure 1 创建并发布一个对等名
using System; using System.Collections.Generic; using System.Text; using System.Net.PeerToPeer; namespace CreateAndPublish { class Program { static void Main(string[] args) { // Creates a secured PeerName. PeerName peerName = new PeerName( "MyWebServer", PeerNameType.Secured); PeerNameRegistration pnReg = new PeerNameRegistration(); pnReg.PeerName = peerName; pnReg.Port = 80; //Starting the registration means the name is published //for other peers to resolve. pnReg.Start(); Console.WriteLine("Registration of Peer Name: {0} complete.", peerName.ToString()); Console.WriteLine("Press any key to stop the registration " + "and close the program"); Console.ReadKey(); pnReg.Stop(); } } }
您已了解了如何创建并发布对等名,现在您需要了解如何解析对等名。首先,您要设置 PeerNameResolver 类的实例,然后使用该实例来同步(参见图 2)或异步解析名称。如果您正在异步解析名称,务必要注意相同的 PeerNameResolver 可以用来解析多个对等名。也就是说,在第一个操作完成之前,您就可以开始对不同对等名启动多个异步解析操作,这样就不必为每个并行的解析操作都实例化一个新的解析程序对象。
Figure 2 同步名称解析
using System; using System.Collections.Generic; using System.Text; using System.Net.PeerToPeer; using System.Net; namespace SyncResolve { class Program { // The application accepts the peer name to resolve as the first // and only command line parameter. static void Main(string[] args) { // Create a resolver object to resolve a peername. PeerNameResolver resolver = new PeerNameResolver(); PeerName peerName = new PeerName(args[0]); // Resolve the PeerName - this is a network operation and will // block until the resolve request is completed. PeerNameRecordCollection results = resolver.Resolve(peerName); // Show the data returned by the resolve operation. Console.WriteLine("Records from resolution of PeerName: {0}", peerName); Console.WriteLine(); int count = 1; foreach (PeerNameRecord record in results) { Console.WriteLine("Record #{0} results...", count); Console.WriteLine("Comment:"); if (record.Comment != null) { Console.WriteLine(record.Comment); } Console.WriteLine("Data:"); if (record.Data != null) { //Assumes the data is an ASCII formatted string Console.WriteLine( System.Text.Encoding.ASCII.GetString(record.Data)); } Console.WriteLine("Endpoints:"); foreach (IPEndPoint endpoint in record.EndPointCollection) { Console.WriteLine("\t Endpoint:{0}", endpoint); Console.WriteLine(); } count++; } Console.ReadKey(); } } }
此时,您可以使用图 1 和图 2 中所示的代码来尝试创建和解析对等名。但要注意,当您尝试使用 PNRP 功能的时候,不能从发布对等名的进程中解析该名称。还应指出,本文介绍的 PNRP API 使用 Windows PNRP 基础结构,并受 Windows XP(安装了 support.microsoft.com/kb/920342 提供的 PNRP 更新)、Windows Vista® 和 Windows Server 2008 支持。
.NET
Framework 3.5 还推出了 System.Net.PeerToPeer.Collaboration
命名空间。协作可在两种环境中进行:第一种是“网络邻居”,适用于已登录到协作基础结构并位于相同子网的用户。(有关此主题的更多详细信息,请参阅 microsoft.com/technet/network/p2p/pnm.mspx。)另一种环境称为“联系人”,适用于那些已添加到 Windows 通讯簿的人员(可以在“联系人”文件夹的“用户”目录中找到它)。在该“联系人”环境中,用户不必位于相同子网上。
这
两种环境都允许用户共享应用程序和对象、发送邀请并获取涉及其他用户的事件通知。比如,一名销售人员在机场等班机时需要和她的同事“见面”。理想情形是,
这名销售人员应该能打开她的笔记本电脑,启动公司的主要业务线 (LOB)
应用程序,然后让此应用程序动态查找她的同事,而不论他们是和她一起坐在机场还是仍在办公室里。该应用程序首先必须登录协作基础结构,然后指定登录范围。
在本例中,PeerScope.All 既包括 Internet 也包括“网络邻居”范围:
PeerCollaboration.Signin(PeerScope.All);
登录后,该应用程序便使用以下代码开始查找该销售员附近的所有人员:
PeerNearMeCollection peers = PeerCollaboration.GetPeersNearMe();
对
与调用方位于相同子网的每个对等点,PeerNearMeCollection 都包含 PeerNearMe
类的一个实例。这样,该应用程序现在有一个所有“网络邻居”(以 PeerNearMe 实例形式存在)的清单。一个 PeerNearMe
实例包括一个用于指定网络位置或远程对等点的 IPEndPoint(IP 地址 + 端口)的属性。
要查找存储在这名销售员通讯簿中的所有联系人,该应用程序必须用下列代码行取得所有联系人:
ContactManager contactManager = PeerCollaboration.ContactManager(); PeerContactCollection contacts = contactManager.GetContacts();
ContactManager 代表 Windows 通讯簿,该通讯簿是 System.Net.PeerToPeer.Collaboration 基础结构所使用的联系人存储库。
现
在已经生成所有对等点(由 PeerNearMe 和 PeerContact
组成)的清单,该销售员就可以选择和哪些同事交互并迅速给每个人发去邀请。在 System.Net.PeerToPeer.Collaboration
环境中的邀请是请求远程对等点启动某个特定应用程序的一种机制。要在两台对等计算机之间建立网络连接,其中一个对等点需要主动侦听传入的数据。该机制允许
一个对等点告知另一方需要运行哪一个应用程序。
就
拿上述例子中的销售员来说,她想通过使用公司 LOB 应用程序和另一名同事进行交互。她需要确保她的同事也在运行 LOB
应用程序。因此,她向该同事发出邀请。当该同事的系统收到邀请后,会在该用户面前出现一个对话框,声明某个特定人员希望他们启动一个特定的应用程序(参见图 3)。对话框提供了“接受”或“拒绝”邀请的选项。如果接收方单击“接受”按钮,邀请中提到的应用程序会在接收方的电脑中自动启动(本例中为 LOB 应用程序),并且假设该应用程序已经安装好。
图 3 从对等点启动应用程序的邀请 (单击该图像获得较大视图)
现在双方各自的系统中都有所需的应用程序在运行,并做好了协作准备。此时,LOB 应用程序使用另一个网络技术(如 Windows Communication Foundation Peer Channel、套接字或 HTTP)进行通信。
我
们已经对邀请做了说明,现在让我们看一下用 System.Net.PeerToPeer.Collaboration
命名空间启用邀请所需的详细信息以及相关代码。就 P2P
基础结构来说,应用程序是指您计算机上的任意可执行文件。为了支持邀请,在邀请方和被邀请方的机器上都必须使用相同的 GUID
向对等协作基础结构注册了该应用程序。以下代码显示了如何创建和注册基于本地计算机上安装的可执行文件的应用程序:
PeerApplication application = new PeerApplication( appGuid, "Collaboration Application", bytes, pathToApp, arguments, PeerScope.Internet); PeerCollaboration.RegisterApplication( application, PeerApplicationRegistrationType.AllUsers);
通
过邀请启动的已注册应用程序可以查询是哪个联系人或终结点使用 PeerCollboration.ApplicationLaunchInfo
发送的邀请。这允许刚刚启动的应用程序知道它是通过一个远程对等点发来的邀请启动的,这样它就知道应重新连接到发送该邀请的对等点。发送邀请的方式可以是
对 GetPeersNearMe 返回的对等对象调用 Invite,或者对从 GetContacts 返回的联系人调用 Invite,如下所示:
PeerInvitationResponse pir = peerNearMe.Invite( app, "Hello World", data); PeerInvitationResponse pir = contact.Invite( app, "Hello World", data);
比
如,这名销售员和一名同事在机场进行通信,并打算在两人分开后继续。她可以在自己的计算机上将那名同事添加为联系人。这是通过使用
peer.AddToContactManager 从 GetPeersNearMe
调用返回的对等类实现的。一旦这位销售员和她的同事相互将对方添加为联系人,他们就可以在任何地方查找对方,并进行交互。
.NET
Framework 3.5 中的协作 API
还能让您共享数据。比如,如果该公司的所有销售人员都希望以电子方式共享其名片,通过使用对等对象便可实现这一愿望。对等对象只是一些可以被远程对等点查
看的数据 blob(如图像文件)。各种对象都可以根据范围进行共享,指定“网络邻居”以允许位于相同子网上的用户都能查看这些对象,或在整个
Internet 范围共享以便任何地方的用户都能查看这些对象。比如,要创建一个对象并在“网络邻居”范围共享,您只需使用以下代码:
PeerObject object = new PeerObject( objectGuid, bytes, PeerScope.NearMe); PeerCollaboration.SetObject(object);
状
态和更改通知也是 P2P 协作的一个重要方面。比如说,我们的销售员一看到在机场的同事 Steve 登录而且有空,就希望与他聊天。在
PeerNearMe 类中提供了一个称为 PeerNearMeChanged
的事件,用于更新位于同一子网的对等点。对等点的任何更改都将触发对关联代理的调用,并发送更改信息。这样,当 Steve
进入(或离开)网络时该销售员都会得到通知。所需代码如下所示:
PeerNearMe.PeerNearMeChanged += PeerNearMeChangedCallback; ... void PeerNearMeChangedCallback( object sender, PeerNearMeChangedEventArgs args) { // Check which PeerNearMe has changed and what the change was // from the args parameter. }
为
异地联系人提供的更改通知还需要若干其他步骤:该过程要求相互信任,这表示您必须选择监视该联系人,而该联系人也必须选择允许您监视。所以,首先您选择通
过对 Contact 调用 Subscribe 方法监视该联系人。然后,您想要监视的对等点必须添加您为联系人,并允许您监视 — 通过将您的
Contact 上的 SubscribeAllowed 属性设置为
SubscriptionType.Allowed。在这些步骤完成后,您可以对您监视的对等点的名称、对象、应用程序等的特定更改进行跟踪。
例如,假设我们的销售员一看到客户联系人上线就希望和他聊天。下列代码将允许这名销售员取得该客户必要的状态更改:
custContact.PresenceChanged += ContactPresenceChangedCallback; ... void ContactPresenceChangedCallback( object sender, PresenceChangedEventArgs args) { if (args.PeerPresenceInfo.PresenceStatus == PeerPresenceStatus.Online) { // Start chatting with the customer } }
注
意,更改信息既可以针对特定对象,也可以针对特定应用程序。向 PeerObject 类中的 ObjectChanged
事件附加一个代理,便可提供对该对象所做更改以及已更改对象来源的信息,例如来自联系人或 PeerNearMe。同样,向
PeerApplication 中的 ApplicationChanged 事件添加一个代理,便可提供与该应用程序的任何更改有关的信息。
例如,若要监视联系人名单中某联系人公开的一系列应用程序中的某个特定应用程序是否更改,必须向 PeerApplication 的 ApplicationChanged 事件添加一个代理:
peerApplication.ApplicationChanged += AppChangedCallback; ... void AppChangedCallback( object sender, ApplicationChangedEventArgs args) { // Check what the change was and which contact and endpoint it // originated from the args parameter. }
现在让我们设想这名销售员马上要做其他事情,因此必须更改她的状态,以便让对等点知道她当下没有时间。通过修改和 PeerCollaboration.LocalPresence 属性关联的数据便可实现这一目的,如下所示:
PeerCollaboration.LocalPresenceInfo = new PeerPresenceInfo( PeerPresenceStatus.Away, "Talking with Customer");
结束语
本文仅简单介绍了 .NET Framework 3.5 新增的一些核心网络功能。如果您已经迫不及待想体验一番,可以到 msdn2.microsoft.com/aa700831 下载最新 CTP 版本,尝试一下这些新功能。请访问 Windows Network Developer Platform 团队博客 blogs.msdn.com/wndp,随时了解有关 System.Net 以及 Windows 网络技术的最新新闻。