实现异步请求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 资源的异步请求,并将结果响应写到控制台。此类包含以下列表中描述的方法和属性。
注意 关闭所有网络流至关重要。如果没有将所有的请求和响应流都关闭,应用程序将用完服务器连接,而无法处理其他请求。 [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)); // Continue reading data until // responseStream.EndRead returns –1. IAsyncResult ar = responseStream.BeginRead( rs.BufferRead, 0, BUFFER_SIZE, new AsyncCallback(ReadCallBack), rs); } else { if(rs.RequestData.Length>0) { // Display data to the console. string strContent; strContent = rs.RequestData.ToString(); } // Close down the response stream. responseStream.Close(); // Set the ManualResetEvent so the main thread can exit. allDone.Set(); } return; } } 使用应用程序协议.NET 框架支持 Internet 上通用的应用程序协议。本节内容包括关于在 .NET 框架中使用 HTTP、TCP 和 UDP 支持的信息,和关于使用 Windows 套接字接口实现自定义协议的信息。 HTTP.NET 框架使用 HttpWebRequest 和 HttpWebResponse 类来提供对 HTTP 协议的全面支持,而 HTTP 协议构成了大部分的 Internet 通信量。每当静态方法 WebRequest.Create 遇到以“http”或“https”开头的 URI 时,在默认情况下将返回这些从 WebRequest 和 WebResponse 派生的类。多数情况下,WebRequest 和 WebResponse 类提供生成请求所需的一切,但如果需要访问作为属性公开的 HTTP 特定功能,则可以将这些类的类型转换为 HttpWebRequest 或 HttpWebResponse。 HttpWebRequest 和 HttpWebResponse 封装“标准 HTTP 请求和响应”事务,并提供对通用 HTTP 标头的访问。这些类还支持大部分的 HTTP 1.1 功能,其中包括管线、块区、身份验证、预身份验证、加密、代理支持、服务器证书验证以及连接管理。自定义标头和不是通过属性提供的标头可存储在 Headers 属性中并可通过此属性访问。 以下示例显示如何访问 HTTP 特定的属性,在本例中为关闭 HTTP Keep-alive 行为并从 Web 服务器获取协议版本号。 [C#] HttpWebRequest HttpWReq = (HttpWebRequest)WebRequest.Create("http://www.contoso.com"); // Turn off connection keep-alives. HttpWReq.KeepAlive = false; HttpWebResponse HttpWResp = (HttpWebResponse)HttpWReq.GetResponse(); // Get the HTTP protocol version number returned by the server. String ver = HttpWResp.ProtocolVersion.ToString(); HttpWResp.Close(); HttpWebRequest 是 WebRequest 使用的默认类,不需要注册它就可以将 URI 传递给 WebRequest.Create 方法。 可以通过将 AllowAutoRedirect 属性设置为 true(默认值)使应用程序自动遵循 HTTP 重定向。应用程序将重定向请求,而 HttpWebResponse 的 ResponseURI 属性则将包含响应请求的实际 Web 资源。如果将 AllowAutoRedirect 设置为 false,则应用程序必须能够将重定向作为 HTTP 协议错误处理。 应用程序通过捕捉 Status 设置为 WebExceptionStatus.ProtocolError 的 WebException 来接收 HTTP 协议错误。Response 属性包含由服务器发送的WebResponse,并指示遇到的实 |