实现异步请求
System.Net 类使用 .NET 框架的标准异步编程模型对 Internet 资源进行异步访问。WebRequest 类的 BeginGetResponse 和 EndGetResponse 方法分别启动和完成对 Internet 资源的异步请求。
注意 在异步回调方法中使用同步调用可能会导致严重的性能降低。通过
WebRequest 及其子代实现的 Internet 请求必须使用 Stream.BeginRead 读取由 WebResponse.GetResponseStream 方法返回的流。
下面的 C# 示例程序说明如何通过
WebRequest 类使用异步调用。该示例是一个控制台程序,它从命令行获得 URI,请求此 URI 处的资源,然后在从 Internet 接收数据的过程中在控制台上打印数据。
该程序定义了两个供自己使用的类:一个是
RequestState 类,它在异步调用间传递数据;另一个是
ClientGetAsync 类,它实现对 Internet 资源的异步请求。
RequestState 类在服务于请求的异步方法调用间保留请求的状态。在
RequestState 类中,有包含当前资源请求和收到的响应流的
WebRequest 和 Stream 实例、包含当前从 Internet 资源接收到的数据的缓冲区和包含整个响应的 StringBuilder 实例。当 AsyncCallback 方法向
WebRequest.BeginGetResponse 注册时,
RequestState 实例 (ar) 作为
state 参数传递。
ClientGetAsync 类实现对 Internet 资源的异步请求,并将结果响应写到控制台。此类包含以下列表中描述的方法和属性。
- allDone 属性包含 ManualResetEvent 类的一个实例,该实例发出信号表示请求已完成。
- Main() 方法读取命令行并开始对指定 Internet 资源的请求。此方法创建 WebRequest 实例 wreq 和 RequestState 实例 ar,调用 BeginGetResponse 开始处理请求,然后调用 allDone.WaitOne() 方法,以使应用程序在回调完成后才退出。读取来自 Internet 资源的响应后,Main() 将响应写到控制台,然后应用程序结束。
- showusage() 方法将示例命令行写到控制台。如果命令行中没有提供 URI,Main() 将调用此方法。
- RespCallBack() 方法为 Internet 请求实现异步回调方法。此方法创建包含来自 Internet 资源的响应的 WebResponse 实例,获取响应流,然后开始从该流中异步读取数据。
- ReadCallBack() 方法实现读取响应流的异步回调方法。它将从 Internet 资源接收的数据传输到 RequestState 实例的 ResponseData 属性中,然后对响应流启动另一个异步读取,直到不再有数据返回为止。读取完所有数据后,ReadCallBack() 关闭响应流,并调用 allDone.Set() 方法以指示 ResponseData 中的响应是完整的。
注意 关闭所有网络流至关重要。如果没有将所有的请求和响应流都关闭,应用程序将用完服务器连接,而无法处理其他请求。
[C#]
using System;
using System.Net;
using System.Threading;
using System.Text;
using System.IO;
// The RequestState class passes data across async calls.
public class RequestState
{
const int BufferSize = 1024;
public StringBuilder RequestData;
public byte[] BufferRead;
public WebRequest Request;
public Stream ResponseStream;
// Create Decoder for appropriate enconding type.
public Decoder StreamDecode = Encoding.UTF8.GetDecoder();
public RequestState()
{
BufferRead = new byte[BufferSize];
RequestData = new StringBuilder(String.Empty);
Request = null;
ResponseStream = null;
}
}
// ClientGetAsync issues the async request.
class ClientGetAsync
{
public static ManualResetEvent allDone = new ManualResetEvent(false);
const int BUFFER_SIZE = 1024;
public static void Main(string[] args)
{
if (args.Length < 1)
{
showusage();
return;
}
// Get the URI from the command line.
Uri httpSite = new Uri(args[0]);
// Create the request object.
WebRequest wreq = WebRequest.Create(httpSite);
// Create the state object.
RequestState rs = new RequestState();
// Put the request into the state object so it can be passed around.
&nbs