转自:http://www.microsoft.com/china/msdn/archives/library/techart/pdc_websvc.ASP
Microsoft .NET Framework SDK Net Classes:用管理代码编写联网应用程序
Lance OlsonMicrosoft Corporation
2000年7月
摘要:本文概述了如何用 Microsoft .NET Framework SDK 管理代码框架来编写在 Internet 上发送或接收数据的应用程序。
注:本文所涉及的文档,比如包括 QuickStart 文档的 Microsoft .NET Framework SDK,可在一张给 PDC 事件参加者的 Microsoft PDC 技术预览版 CD 上找到。
注:阅读本文前您需要熟悉与 Microsoft .NET Framework SDK 的 Microsoft PDC 技术预览版相关的关键概念,比如活动服务器页 + (ASP+) 和通用语言运行时环境。
注:本文术语“Net classes”是指 Microsoft .NET Framework SDK 的 System.Net 名称空间中的类集合。这个术语不应该与 Microsoft .NET initiative 相混淆,在 http://www.microsoft.com/net/default.asp(英文)有关于 initiative 的详细说明。 Net classes 是构成 Microsoft .NET initiative 的众多技术中的一种。
目录
简介
Microsoft .NET Framework SDK 技术预览的一个关键特色就是通用类框架,旨在提供一个功能丰富的平台,用以构建那些使用 SDK 运行时功能的应用程序。这一框架提供对如下领域的支持:
- 数据—涉及 XML 和 ADO 样式数据处理的类。
- Win 窗体—使编写 Windows GUI 应用程序和大量的控件变得更加容易的类。
- ASP+—支持构建基于服务器的 Web 应用程序,既支持 Web UI (HTML 或 WML) 也支持 XML Web 服务。
- 基本类型—框架其余部分完成通用任务(比如字符串、集合和阵列处理)所使用的基类。
- 服务—支持与 Windows 服务应用程序、Microsoft 消息队列一起工作,以及其它系统级功能。
- 网络—对创建使用 Internet 协议来发送和接收数据的应用程序提供支持的类。
在本文中,我们将仔细研究该框架的 Net classes 部分,并重点研究如何使用这些类来更容易地编写那些很酷的通过 Internet 发送和接收数据的应用程序。
如何使用 Net Classes
尽管可使用 Net classes 编写的应用程序的范围很广,但基本设计有三个关键目标。理解设计目标是很有用的,因为这将使您更加清楚利用类来编写应用程序的好处。不必为您不熟悉其中的一些功能而担扰;下面我们将对其进行更加详细的介绍。
- Net classes 对用管理代码编写联网应用程序提供了一种简单但完整的解决方案。
使用分层的方法,Net classes 可以使应用程序根据其需要以各种不同级别的控件访问网络。这些级别所覆盖的范围几乎包括当今 Internet 上的每一种情况—从套接字上的小粒度控件到一般的请求/响应模型。进一步讲,该模型是可扩展的,它会随着 Internet 的进步始终与您的应用程序一起工作。
- Net classes 涉及 HTTP 协议的卓越实施。
鉴于今天大量的 Web 传输通过 HTTP 协议进行的现状,其作为应用程序协议的重要性是非常重大的。Net classes 支持 HTTP 1.1 协议的大多数功能。其高级功能包括:管道技术、程序分块、身份验证、事先身份验证、加密、代理支持、服务器证书验证、连接管理和 HTTP 扩展。
- Net classes 被设计用来编写可伸缩的高性能活动服务器页 (ASP+) 中间层应用程序。
作为单用户浏览器请求的结果,今天 Web 服务器的通用方案包含对后端或外部服务器作出多个请求。这种方案要求有一个能经受高负载、健壮的中间层联网堆栈。Net classes 在设计时特别考虑了这类客户需求。象连接管理、管道技术、保活技术和异步发送与接收确保对中间层的有力支持。另外,因为 Net classes 是整体框架的一部分,所以它与 ASP+ 功能(如顶替功能和高速缓存功能)的集成是无缝的。
Net Classes 与 WinInet 的比较
Net classes 与 Microsoft 的 WinInet API 的相似之处在于允许应用程序使用 Internet 协议来获取和发送数据。尽管如此,Net classes 在设计和功能上有很大差别。正如您可能已从上述设计目标中猜想到的那样,其最显著的差异是 Net classes 设计的重点放在了经受高强度的服务器环境。
Net Classes 的形式
现在让我们仔细研究一些使用 Net classes 编写的代码。从逻辑角度上讲,Net classes 包含三个层:请求/响应层、应用协议层和传输层。WebRequest 和 WebResponse 类代表请求/响应层。HTTP、TCP 和 UDP 类组成了应用协议层,而套接字存在于传输层中。WebRequest/WebResponse 和 HTTP 可以在 System.Net 名称空间中找到,而 TCP/UDP 和套接字则处在 System.Net.Sockets 名称空间中。
图 1. Net classes
下面对每一层进行介绍,并有一个代码示例显示其用法。
请求/响应模型
请求/响应模型位于顶部,提供一种简单的方式访问 Web 上的资源。这个示例显示如何获取一个 Web 页并将其内容写入到控制台应用程序的屏幕上。
使用 Visual Basic
'设置用于获取服务器流的变量
Dim WReq As WebRequest
Dim WResp As WebResponse
Dim sr As StreamReader
' 创建将 URI 传递给 .Create() 方法的 WebRequest 对象
' 并通过调用 .GetResponse() 从服务器获取响应;
' 注意 WebRequestFactory 总是用于创建这种请求。
' 当涉及进展时,我们会仔细研究这样做的原因
WReq = WebRequestFactory.Create("http://www.microsoft.com/default.htm")
WResp = WReq.GetResponse()
' 从服务器获取可读的流——将数据编写为 ASCII 码以写入到控制台
sr = new StreamReader(WResp.GetResponseStream(), Encoding.ASCII)
' 声明用于读取文本的变量
Dim Buffer(1024) As Char
Dim bytesread As Integer
Dim length As Integer
length = 1024
' 从流读取并将任何数据写入到控制台
bytesread = sr.Read(Buffer, 0, length)
Do while (bytesread > 0)
Console.Write( Buffer,0, bytesread)
bytesread = sr.Read( Buffer, 0, length)
Loop
' 完成时关闭流
sr.Close
使用 C#
// 创建将 URI 传递给 .Create() 方法的 WebRequest 对象
// 并通过调用 .GetResponse() 从服务器获取响应;
WebRequest WReq = WebRequestFactory.Create
("http://www.microsoft.com/default.htm");
WebResponse WResp = WReq.GetResponse();
// 从服务器获取可读的流——将数据编写为 ASCII 码以写入到控制台
StreamReader sr = new StreamReader(WResp.GetResponseStream(),
Encoding.ASCII);
// 声明用于读取文本的变量
int length = 1024;
char [] Buffer = new char[1024];
int bytesread = 0;
// 从流读取并将任何数据写入到控制台
bytesread = sr.Read( Buffer, 0, length);
while( bytesread > 0 )
{
Console.Write( Buffer,0, bytesread);
bytesread = sr.Read( Buffer, 0, length);
}
// 完成时关闭流
sr.Close();
HTTP、TCP 和 UDP 类
HTTP 类与一些其他的属性一起执行一般请求/响应模型,这些属性提供对 HTTP 特定功能更高级别的控制,这些特定功能诸如在属性级别控制标头、程序分块或设置“用户代理”字符串时访问对象模型中的 HTTP 协议。在大多数情况下,使用 WebRequest 和 WebResponse 发送和接收数据就足够了。只有在 WebRequest 和 WebResponse 所揭示的详细信息级别不够充分时才需要使用 HttpWebRequest 和 HttpWebResponse 类。下面的示例说明如何访问某些特定的 HttpWebRequest 属性,以便在这种情况下关闭 HTTP 保活技术行为并从 Web 服务器获取协议的版本号。
使用 Visual Basic
' 为了在 VB 中获取隐式转换,必须关闭 Strict 选项
Option Strict Off
Dim HttpWReq As HttpWebRequest
Dim HttpWResp As HttpWebResponse
Dim sr As StreamReader
Dim ver As String
' 创建将 URI 传递给 .Create() 方法的 WebRequest 对象
' 并通过调用 .GetResponse() 从服务器获取响应;
' 注意 WebRequestFactory 总是用于创建这种请求。
' 当涉及进展时,我们会仔细研究这样做的原因
HttpWReq = WebRequestFactory.Create("http://www.microsoft.com ")
' 关闭连接保活技术
HttpWReq.KeepAlive = false
HttpWResp = HttpWReq.GetResponse()
' 查看由服务器返回的 HTTP 协议版本号
ver = HttpWResp.Version.ToString
' 从服务器获取可读的流——将数据编写为 ASCII 码以写入到控制台
sr = new StreamReader(HttpWResp.GetResponseStream(), Encoding.ASCII)
...Then read the stream just as was done in the WebRequest example
使用 C#
// 创建将 URI 传递给 .Create() 方法的 WebRequest 对象
// 并通过调用 .GetResponse() 从服务器获取响应;
HttpWebRequest HttpWReq = (HttpWebRequest)WebRequestFactory
.Create ("http://www.microsoft.com ");
// 关闭连接保活技术
HttpWReq.KeepAlive = false;
HttpWebResponse HttpWResp = (HttpWebResponse)HttpWReq.GetResponse();
// 查看由服务器返回的 HTTP 协议版本号
String ver = HttpWResp.Version.ToString();
// 从服务器获取可读的流——将数据编写为 ASCII 码以写入到控制台
StreamReader sr = new StreamReader(WResp.GetResponseStream(),
Encoding.ASCII);
...Then read the stream just as was done in the WebRequest example
TCP 和 UDP
对于编写自己的网络协议、发送 UDP 数据包或者使用 IP 多点传送,TCP 和 UDP 类在照顾到大多数套接字正常工作的同时给出了正确的访问级别。
使用 Visual Basic
'创建新的 TCPClient
Dim tcpc As TCPClient
Dim Buffer(32) As Byte
Dim bytes As Integer
Dim server As String
server = "tcpserver"
' 验证服务器已存在
if (DNS.GetHostByName(server) = "")
{
Console.WriteLine(“找不到 tcpserver”)
return
}
' 尝试连接到服务器
if (tcpc.Connect(server, 13) = -1)
{
Console.WriteLine(“无法连接服务器:” + 服务器)
return
}
' 获取流
Dim s As Stream
Dim ServerData as String
s = tcpc.GetStream
' 读取流并将它转换为 ASCII 码
bytes = s.Read(Buffer, 0, Buffer.Length)
ServerData = Encoding.ASCII.GetString(Buffer)
' 显示数据
Console.WriteLine(“已接收到的” & 字节 & “字节”)
Console.WriteLine(“从服务器接收的数据为:” &
ServerData)
' 关闭流
tcpc.Close
使用 C#
// 创建新的 TCPClient
TCPClient tcpc = new TCPClient();
Byte[] read = new Byte[32];
// 验证服务器已存在
if (DNS.GetHostByName("tcpserver") == null)
{
Console.WriteLine(“找不到 tcpserver”);
return;
}
// 尝试连接到服务器
if (tcpc.Connect(server, 13) == -1)
{
Console.WriteLine(“无法连接到服务器:”+ 服务器);
return;
}
// 获取流
Stream s = tcpc.GetStream();
// 读取流并将它转换为 ASCII 码
int bytes = s.Read(read, 0, read.Length);
String ServerData = Encoding.ASCII.GetString(read);
// 显示数据
Console.WriteLine(“已接收到的” + 字节 + “字节”);
Console.WriteLine(“从服务器接收到的数据为:” +
ServerData);
// 关闭流
tcpc.Close();
套接字
对于熟悉 Winsock 的开发者或那些目标是套接字所提供的控件级的人们来说,Net classes Socket API 使用起来的感觉就象您已熟悉和喜爱的 Win32 API 一样。套接字类在 Net classes 中充当从管理代码到本地代码的过渡点。在大多数情况下,套接字只是将数据汇集到其本地的 Win32 套接字中,并进行任何必要的安全检查。下面的示例函数显示如何使用套接字类将数据发送到 HTTP 服务器并读取响应。
使用 C#
public string DoSocketGet(string server)
{
// 设置要写入到服务器的变量和字符串
Encoding ASCII = Encoding.ASCII;
string Get = "GET / HTTP/1.1/r/nHost: " + server +
"/r/nConnection: Close/r/n/r/n";
Byte[] ByteGet = ASCII.GetBytes(Get);
Byte[] RecvBytes = new Byte[256];
// IPAddress 和 IPEndPoint 表示接收请求的端点
IPAddress hostadd = DNS.Resolve(server);
IPEndPoint EPhost = new IPEndPoint(hostadd, 80);
StringBuilder sb = new StringBuilder();
// 创建通过 TCP 发送数据的套接字
Socket s = new Socket(AddressFamily.AfINet,
SocketType.SockStream,
ProtocolType.ProtTCP);
// 使用 IPEndPoint 连接到主机
if (s.Connect(EPhost) != 0)
{
return "Unable to connect to host";
}
// 将 GET 文本发送到主机
s.Send(ByteGet, ByteGet.Length, 0);
// 接收默认页面,循环直至接收到所有字节
Int32 bytes = s.Receive(RecvBytes, RecvBytes.Length, 0);
sb.Append( "Default HTML page on " + server + ":/r/n");
sb.Append( ASCII.GetString(RecvBytes, 0, bytes));
while (bytes > 0)
{
bytes = s.Receive(RecvBytes, RecvBytes.Length, 0);
sb.Append( ASCII.GetString(RecvBytes, 0, bytes));
}
return sb.ToString();
}
与 Web 上的资源进行交互
Net classes 被设计用来使应用程序容易地与 Web 上的资源进行交互。对于请求/响应类,这些资源必须是 URI 可表述的,意思是可以使用统一资源标识符 (URI) 对其进行解析。今天 Web 上最典型的 URI 是“http://www.<servername>.com/<path>”。URI 可表述的资源类型包括静态页面、动态页面、应用程序、数据和服务。
对于基于 Internet 的应用程序(如信使应用程序)或者象 Napster 那样充当彼此直接通信的节点的应用程序,TCP 和 UDP 类提供了理想的接口。
数据表示为流
当使用 Net classes 对 Web 上的资源进行解析时,正在发送和接收的数据会通过一个流对象进行表示。作为这种设计的结果,应用程序会得到某些关键的益处。
- 表示 Web 数据的通用方法 — 流提供了一种发送和接收数据的一般方法。您也许正在下载 GIF 文件、HTML、XML 或其他任何数据,而您的应用程序会仍使用 Stream.Read() 下载数据。
- 对经过框架的流的 Rich 支持 — 因为在整个框架中都使用流,所以在适当的位置有一个基础结构 rich 集处理它们。例如,您可以修改从某个 FileStream 读取 XML 文件而后又将其处理成从某个 NetworkStream 进行读取的应用程序,而无需更改除获取该流的少数几行之外的任何内容。以一般方式处理每一个流会使建立一个更加模块化和健壮的代码基准变得容易。请注意,由于来自网络和来自来地文件系统的数据存在差异,所以在使用网络流时会需要理解一些概念。最常见的缺陷是无法理解网络流不易识别这一事实。因为网络数据通常都是动态生成的,所以讲“MyNetStream.Length()”并不总是有意义的。出于这一目的,框架中的基本流类拥有一些诸如 CanSeek、CanRead 和 CanWrite 等方法,这些方法在检测流的容量时很有用,并且应当在应用程序不确定要事先使用的流类型的情形下被调用。
与现有的 Web 服务进行交互
这无需多言,但确信要理解这一点,让我们这样来说:Net classes 使用 Internet 所基于的标准协议提供对网络的访问。这就意味着,倘若您的应用程序知道该使用哪个协议,那么使用 Net classes 编写的应用程序就可以与 Internet 上的其他任何应用程序进行交流,包括当今 Internet 上可用的现有平台和服务。除了那些在协议中使用的隐式需求外,Net classes 对服务器没有任何要求。例如,使用 Net classes 编写的应用程序可以从任何正确执行了 HTTP 1.1 协议的 Web 服务器上下载数据。
功能细览
现在让我们更仔细地研究一下如何使用 Net classes 中的一些关键功能。
请求/响应模型
Net classes 中的请求/响应模型由两种主要的类来表示:WebRequest 和 WebResponse。这两种类提供了一种访问网上资源的一般方式。WebRequest 表示一个网络请求,包含诸如 RequestURI、headers、Credentials 和 ContentType 等属性。WebRequest 上的主要方法有 GetRequestStream、GetResponse 以及它们的异步方法 Begin/EndGetRequestStream 和 Begin/EndGetResponse。 GetRequestStream 用于获取流以便将数据上载到服务器。GetResponse 用于获取服务器返回的响应对象。WebResponse 表示从处理该请求的服务器接收回的响应。其关键属性有 ContentLength、ContentType、headers、ResponseURI 和 Status。WebResponse 上最常用的方法是 GetResponseStream,它用于从服务器读取(下载)数据。
当对 WebRequest.GetResponse 进行调用时,通常发出实际的网络请求。
' 创建将 URI 传递给 .Create() 方法的 WebRequest 对象。
' 注意 WebRequestFactory 总是用于创建这种请求。
Dim MyUri As String
Dim WReq As WebRequest
Dim WResp As WebResponse
MyUri = "http://www.microsoft.com/default.htm"
' 创建 Request 对象
WReq = WebRequestFactory.Create(MyUri)
' 现在发送请求并取回响应
WResp = WReq.GetResponse
然而,在发送数据的情况下,请求实际上是在应用程序从服务器请求上载流的那一刻发出的。
// 创建将 URI 传递给 .Create() 方法的 WebRequest 对象。
// 注意 WebRequestFactory 总是用于创建这种请求。
Dim MyUri As String
Dim WReq As WebRequest
Dim RequestStream As Stream
Dim SomeBytes() As Byte
Dim payload As String
' 上载数据的 URI
MyUri = "http://www.mycorporateuploadsite.com/public/"
' 这是准备用于上载的数据。通常它来自数据库、文件或另一个网络流
payload = "Data to be sent to the server"
' 创建 Request 对象
WReq = WebRequestFactory.Create(MyUri)
' ASCII 编码有效负载
SomeBytes = System.Text.Encoding.ASCII.GetBytes(payload)
' 设置某些 WebRequest 属性
WReq.Method = "POST"
WReq.ContentType = "application/x-www-form-urlencoded"
WReq.ContentLength = SomeBytes.Length
' 获取请求流并写入数据
RequestStream = WReq.GetRequestStream
RequestStream.Write(SomeBytes, 0, SomeBytes.Length)
RequestStream.Close
请求实际发送的时刻并不是应用程序通常需要关注的细节,因为它对响应更感兴趣。应用程序开发者所要知道的最重要的事情是当 WebRequest.GetResponse 方法被调用时,它会获取响应(或者一些事情的例外出错)。
WebRequest 和 WebResponse 是按可扩展方式设计的,以支持许多诸如 FTP、HTTP 和 SMTP 之类的 Internet 协议。当前 HTTP 是作为 SDK 中的支持协议提供的,而 FTP 是作为一个示例“可插入”协议提供的。要创建一个 WebRequest,会将一个 URI 传递到 WebRequestFactory.Create 方法中。这种方法查看 URI 的模式(如“http:”和“ftp:”并选择基于这种模式的基础实现类。对于该应用程序,这种选择过程是透明的,并一直保持透明,除非该应用程序需要访问这种模式的特定协议的 API。从上面提供的原始示例里面,请注意对 WebRequestFactory.Create() 的调用。
' 创建将 URI 传递给 .Create() 方法的 WebRequest 对象。
' 注意 WebRequestFactory 总是用于创建这种请求。
Dim MyUri as String
MyUri = "http://www.microsoft.com/default.htm"
WReq = WebRequestFactory.Create(MyUri)
WebRequestFactory 的返回值可以在任何时候提交给 HttpWebRequest,但这通常是不必要的,因为在 WebRequest 中提供该支持。
可插入协议
当某个应用程序仅仅使用 WebRequest 和 WebResponse 类时,无需修改应用程序的任何代码就可以“插入”和使用新的协议。注册一个带 WebRequestFactory 的 URI 模式在程序的持续时间内插入协议支持。注册是通过调用 WebRequestFactory.Register() 方法完成的。对于 HTTP 协议,这种方法是从内部调用的,因此它被默认注册;尽管如此,在将来可以实现和注册任意数目的其他协议。当然,由于 Internet 上的协议数量巨大,这种模型并不是对所有的情况都理想。那些“饶舌”的或另外排斥请求/响应模型的协议可能会在 TCP 或 UDP 类中更好地执行,或者在某些情况下会在 Sockets 类中更好地执行。如果您不确定哪一层符合您的需要,请先查看请求/响应模型,如果请求/响应看起来不是太合适,那么就继续向着 Socket 向下移动栈。
HTTP
对 HTTP 协议的健壮支持在 Net classes 的设计和实现中曾有很高的优先级。在下面详细讲述的 API 显示如何获取 HTTP 的一些更高级功能。
程序分块
当应用程序需要发送或接收数据,而数据的准确大小在下载/上载开始时还未知时,程序分块是有用的。当基于其他应用程序或服务器逻辑正在创建所讨论的数据时,使用程序分块技术是最普遍的。要发送分块的数据,应该将 WebRequest 转换为 HttpWebRequest 并且将 HttpWebRequest.SendChunked 的属性设置为TRUE。
' 为了在 VB 中获取隐式转换,必须关闭 Strict 选项
Option Strict Off
Dim MyUri As String
Dim HttpWReq As HttpWebRequest
Dim RequestStream As Stream
' 上载数据的 URI
MyUri = "http://www.mycorporateuploadsite.com/public/"
' 创建 Request 对象
HttpWReq = WebRequestFactory.Create(MyUri)
' 设置某些 WebRequest 属性
HttpWReq.Method = "POST"
HttpWReq.ContentType = "text/xml"
HttpWReq.SendChunked = True
' 获取请求流并写入数据
RequestStream = HttpWReq.GetRequestStream
Here you would loop through reading the dynamic data and writing it
to the RequestStream
' 完成时关闭——当发送分块数据时这一点尤其重要,
' 因为这一操作告诉服务器操作已完成
RequestStream.Close
HTTP 管道技术
管道技术是 HTTP 1.1 的一项功能,它允许 Net classes 通过持久性连接向后端服务器发送多个 HTTP 请求,而无需在发出下次请求之前等待来自服务器的响应。这会显著影响性能,因为从服务器请求多个资源的应用程序不会被阻塞而等待某个特定资源(可能是服务器上一个非常耗时的操作,如数据库查找)。图 2 说明管道技术的作用与传统的 HTTP 请求/响应行为的对比。在使用管道技术的情形下(图的右侧),您会注意到由于客户是在收到响应前就发送请求,处理所有这三个请求所花费的总时间减少了。
图 2. 管道技术与传统的 HTTP 请求/响应行为的对比
在 Net classes 中,默认使用管道技术。在某些不希望使用管道技术的特定情况下,将 HttpWebRequest.Pipelined 属性设置为 FALSE 可以禁用管道技术。
' 为了在 VB 中获取隐式转换,必须关闭 Strict 选项
Option Strict Off
Dim MyUri As String
Dim HttpWReq As HttpWebRequest
' 要请求的 URI
MyUri = "http://www.mycorporateuploadsite.com/public/"
' 创建 Request 对象
HttpWReq = WebRequestFactory.Create(MyUri)
' 关闭管道
HttpWReq.Pipelined = False
连接管理
保活技术 — 将保活技术功能引入到 HTTP 1.0 协议中以允许使用 HTTP 的客户机通过保持到服务器的现有连接处于激活状态并重用该连接,而不是在每次请求时都先关闭它然后再新创建一个来保存网络资源并以一种更有效的方式操作。在默认情况下,将保活技术的属性设置为 TRUE,倘若服务器支持这一行为,该设置会导致创建一个到服务器的持久性连接。如果您正在从一个中间层 ASP+ 应用程序访问后端服务器,您应该意识到到后端服务器的连接会始终打开着,直到后端服务器连接超时。
连接限制 — 连接管理对于在联网应用程序中获取最佳规模和性能是一项重要功能。在两台机器间所用的连接数会对应用程序的吞吐量产生显著影响。使用 Net classes 从应用程序到给定的服务器的默认连接数为两个。在每个应用程序基础上,这个数目可以增加或减少。下图说明三台客户机连接到一台 ASP+ 服务器的情形,其中每台客户机使用两个连接。而服务器对后端机器使用六个连接。
图 3. 三台客户机连接到一台 ASP+ 服务器上,其中每台客户机使用两个连接
要使用的最佳连接数取决于应用程序在其中运行的情况,因此,不是给出一个特定的连接建议,而是建议您根据默认设置通过获取对您的应用程序吞吐量的基准度量开始,然后改变默认设置,并研究性能是如何受到影响的。例如,假定默认数目是两个,你会试图将它设置为四个。一般情况下,并发连接的数目不应达到数百个,因为在应用程序从多个连接中所受益处与创建一个新连接所需要的开销之间有一个精细的平衡。在某些情况下,创建了许多连接的应用程序实际上会比精明地只使用几个连接执行起来要慢。一个好消息是:在大多数情况下,Net classes 恰好为您“做正确的事情”。对于使用非同步 API 或在多线程方式下使用同步 API 的人们来说,可以使用静态的 ServicePoint.DefaultPersistentConnectionLimit 属性来改变连接。
' 如果您想要将默认值由两个改为四个,请在应用程序初始化时就调用这一属性
' 注意,在许多情况下,两个都是最佳连接数
System.Net.ServicePoint.DefaultPersistentConnectionLimit = 4
连接组 — Net classes 中的连接组提供一种使单个应用程序中的特定请求与已定义连接池相关联的方法。当正在使用连接级身份验证并正在将许多请求从中间层应用程序发送到后端机器时,这是非常有用的。常常期望那些请求在其上流动的连接与某个用户相关联。例如,假定一个名叫 Joe 的用户正在访问一个显示其薪水信息的内部 Web 站点。当 Joe 第一次找到该站点要进入时,他会被提示使用其域、用户名和口令进行登录。在后端,Joe 所访问的 Web 站点正在使用 Joe 的 Windows NT 证书向其他后端服务器发出 HTTP 请求,以找到表述其配置文件的文件。接着使用 Joe 的配置文件来获取其薪水信息。在许多情况下,这种后端请求是使用用来验证的 Microsoft NTLM 协议来完成的,因此该连接现在使用 Joe 的证书通过了验证。接着 Susan 也访问该站点并请求查看她的薪水资料,但后端连接是由 Joe 所验证的,因此,后端服务器仍然以 Joe 的配置文件作出响应。尽管此示例有点极端,但它应该可以帮助您理解能通过连接组将一些请求类型分开的重要性。要达到这一目的,在作出请求前应用程序只需设置 WebRequest.ConnectionGroupName 属性即可。
' 创建将 URI 传递给 .Create() 方法的 WebRequest 对象。
' 注意 WebRequestFactory 总是用于创建这种请求。
Dim MyUri as String
Dim WReq As WebRequest
MyUri = "http://www.microsoft.com/default.htm"
WReq = WebRequestFactory.Create(MyUri)
WReq.ConnectionGroupName = "Joe"
身份验证
Net classes 支持各种客户机身份验证机制,包括“摘要”、“基本”、Kerberos、NTLM 和“定制”。身份验证是通过在作出请求前对 WebRequest.Credentials 对象进行设置来达到的。在“摘要”和“基本”情况下,会指定用户名和口令。对于 NTLM 或 Kerberos,则使用 Windows 安全机制,并且 Credential 对象或者可以被设置为用户名、口令和域的结合,或者可以请求使用系统默认值。
' 使用 NTLM 向安全的内部站点作出请求
Dim MyUri as String
Dim WReq As WebRequest
MyUri = "http://paychecks/default.aspx"
WReq = WebRequestFactory.Create(MyUri)
WReq.Credentials = CredentialCache.DefaultCredentials
使用“基本”身份验证对 Internet 站点发出请求的情形看起来如下:
' 使用 NTLM 向安全的内部站点作出请求
Dim MyUri as String
Dim WReq As WebRequest
MyUri = "http://paychecks/default.aspx"
WReq = WebRequestFactory.Create(MyUri)
WReq.Credentials = CredentialCache.DefaultCredentials
Dim MyUri as String
Dim WReq As WebRequest
MyUri = "http://www.basicprotectedsite.com/default.aspx"
WReq = WebRequestFactory.Create(MyUri)
WReq.Credentials = new SingleCredential("username", "password)
SSL
在 Net classes 中对安全 (SSL 3.0) 连接的支持是无缝的。当 https:// 模式被用在 URI 的开头时,类在捕集器下使用 SSL。
' 使用 SSL 向某个站点发出请求——注意 HTTPS URI
Dim MyUri as String
Dim WReq As WebRequest
Dim WResp As WebResponse
MyUri = "https://www.sslsecuredsite.com/default.aspx"
WReq = WebRequestFactory.Create(MyUri)
WResp = WReq.GetResponse
代理支持
在 Net classes 中的 HTTP 代理支持可以在每个请求的基础上进行控制,或者可以一次全局性地设置它,用于应用程序的生存期。下面的示例显示如何在通过代理服务器发出请求时全局性地设置代理。
' 通过代理服务器向某个外部站点发出请求
Dim MyUri as String
Dim WReq As WebRequest
Dim WResp As WebResponse
Dim proxyObject as DefaultControlObject
proxyObject = new DefaultControlObject("myproxyservername", 80)
' 当主机是本地的时,禁止代理的使用,即没有句点。
proxyObject.ProxyNoLocal = true
' 现在用我们的新设置进行全部取代,所有新的请求都使用这一代理信息
GlobalProxySelection.Select = proxyObject
MyUri = "https://www.someexternalsite.com/default.aspx"
WReq = WebRequestFactory.Create(MyUri)
WResp = WReq.GetResponse
TCP 和 UDP
在 System.Net.Sockets 名称空间中可得到的 TCPClient、TCPListener 和 UDPClient 类提供对 TCP 和 UDP 协议的支持。
TCPClient
TCPClient 类提供了一种使用 TCP 协议连接到某个端点的简化方法。它还通过 NetworkStream 对象展现在连接过程中读取或写入的数据。请参见下面从 QuickStart 文档中摘录的日期/时间客户机示例。
使用 C# 编写
using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text;
class Client
{
public static void Main(String[] args)
{
TCPClient tcpc = new TCPClient();
Byte[] read = new Byte[32];
if (args.Length != 1)
{
Console.WriteLine(“请在命令行中指定服务器名称”);
return;
}
String server = args[0];
// 验证服务器是否存在
if (DNS.GetHostByName(server) == null)
{
Console.WriteLine(“找不到服务器:” + 服务器);
return;
}
// 尝试连接到服务器
if (tcpc.Connect(server, 13) == -1)
{
Console.WriteLine(“无法连接到服务器:” + 服务器);
return;
}
// 获取流
Stream s = tcpc.GetStream();
// 读取流并将它转换为 ASCII 码形式
int bytes = s.Read(read, 0, read.Length);
String Time = Encoding.ASCII.GetString(read);
// 显示数据
Console.WriteLine(“已接收到的” + 字节 + “字节”);
Console.WriteLine(“当前日期和时间是:” + 时间);
tcpc.Close();
}
}
TCPListener
TCPListener 类便于在来自某个客户机的 TCP 连接的特定套接字上进行侦听的工作。请参见下面包括在 QuickStart 文档中的日期/时间服务器示例。
使用 C# 编写
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class Server
{
public static void Main()
{
DateTime now;
String strDateLine;
Encoding ASCII = Encoding.ASCII;
// 在端口 13 进行侦听
TCPListener tcpl = new TCPListener(13);
tcpl.Start();
Console.WriteLine(“正在等待客户进行连接”);
Console.WriteLine(“请按 Ctrl+c 退出...”);
while (true)
{
// 接收会阻塞,直到有人连接上
Socket s = tcpl.Accept();
// 获取当前的日期和时间并将它连接成一个字符串
now = DateTime.Now;
strDateLine = now.ToShortDateString() + " " +
now.ToLongTimeString();
// 将该字符串转换成一个字节数组并发送它
Byte[] byteDateLine =
ASCII.GetBytes(strDateLine.ToCharArray());
s.Send(byteDateLine, byteDateLine.Length, 0);
Console.WriteLine(“发送” + strDateLine);
}
}
}
UDPClient 与多点传送
UDPClient 类使得使用组管理方法(如 UDPClient.JoinMulticastGroup 和 UDPClient.DropMulticastGroup)发送网络数据报和 IP 多点传送变得更加容易。
代码访问
WebPermissions 和 SocketPermissions 类可用来许可应用程序接受的连接或分别连接基于 URI 或传输地址的其他主机。这两种许可对准许/拒绝访问采用相同的策略,但呈现为两种单独的 API,因为他们在两种不同的抽象层次下工作。WebPermissions 和 SocketPermissions 既可以单独使用,也可以组合使用。
WebPermissions
WebPermissions 类控制应用程序访问或导出 URI 的权利。
SocketPermissions
SocketPermissions 类控制应用程序接受在本地传输地址上的连接的权利,或控制应用程序与主机名称、端口号和传输所描述的一些传输地址上的其他应用程序进行联系的权利。
结论
有关 Net classes 和其他令人激动的开发者功能的更多详细信息可以在