使用.NET访问 Internet(2)

实现异步请求

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.

rs.Request = wreq;

// Issue the async request.

IAsyncResult r = (IAsyncResult) wreq.BeginGetResponse(

new AsyncCallback(RespCallback), rs);

// Wait until the ManualResetEvent is set so that the application

// does not exit until after the callback is called.

allDone.WaitOne();

Console.WriteLine(rs.RequestData.ToString());

}

public static void showusage() {

Console.WriteLine("Attempts to GET a URL");

Console.WriteLine("\r\nUsage:");

Console.WriteLine(" ClientGetAsync URL");

Console.WriteLine(" Example:");

Console.WriteLine(" ClientGetAsync http://www.contoso.com/");

}

private static void RespCallback(IAsyncResult ar)

{

// Get the RequestState object from the async result.

RequestState rs = (RequestState) ar.AsyncState;

// Get the WebRequest from RequestState.

WebRequest req = rs.Request;

// Call EndGetResponse, which produces the WebResponse object

// that came from the request issued above.

WebResponse resp = req.EndGetResponse(ar);

// Start reading data from the response stream.

Stream ResponseStream = resp.GetResponseStream();

// Store the response stream in RequestState to read

// the stream asynchronously.

rs.ResponseStream = ResponseStream;

// Pass rs.BufferRead to BeginRead. Read data into rs.BufferRead

IAsyncResult iarRead = ResponseStream.BeginRead(rs.BufferRead, 0,

BUFFER_SIZE, new AsyncCallback(ReadCallBack), rs);

}

private static void ReadCallBack(IAsyncResult asyncResult)

{

// Get the RequestState object from AsyncResult.

RequestState rs = (RequestState)asyncResult.AsyncState;

// Retrieve the ResponseStream that was set in RespCallback.

Stream responseStream = rs.ResponseStream;

// Read rs.BufferRead to verify that it contains data.

int read = responseStream.EndRead( asyncResult );

if (read > 0)

{

// Prepare a Char array buffer for converting to Unicode.

Char[] charBuffer = new Char[BUFFER_SIZE];

// Convert byte stream to Char array and then to String.

// len contains the number of characters converted to Unicode.

int len =

rs.StreamDecode.GetChars(rs.BufferRead, 0, BUFFER_SIZE, charBuffer, 0);

String str = new String(charBuffer, 0, len);

// Append the recently read data to the RequestData stringbuilder

// object contained in RequestState.

rs.RequestData.Append(

Encoding.ASCII.GetString(rs.BufferRead, 0, read));

<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt" align=lef

Published At
Categories with Web编程
Tagged with
comments powered by Disqus