使用.NET訪問 Internet(2)

來源:互聯網
上載者:User
實現非同步請求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));        

         // 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 派生的類。多數情況下,WebRequestWebResponse 類提供產生請求所需的一切,但如果需要訪問作為屬性公開的 HTTP 特定功能,則可以將這些類的類型轉換為 HttpWebRequestHttpWebResponse
HttpWebRequestHttpWebResponse 封裝“標準 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();
HttpWebRequestWebRequest 使用的預設類,不需要註冊它就可以將 URI 傳遞給 WebRequest.Create 方法。
可以通過將 AllowAutoRedirect 屬性設定為 true(預設值)使應用程式自動遵循 HTTP 重新導向。應用程式將重新導向請求,而 HttpWebResponse 的 ResponseURI 屬性則將包含響應請求的實際 Web 資源。如果將 AllowAutoRedirect 設定為 false,則應用程式必須能夠將重新導向作為 HTTP 協議錯誤處理。
應用程式通過捕捉 Status 設定為 WebExceptionStatus.ProtocolError 的 WebException 來接收 HTTP 協議錯誤。Response 屬性包含由伺服器發送的WebResponse,並指示遇到的實際 HTTP 錯誤。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.