首页 > 编程 > .NET > 正文

使用.NET访问 Internet(2) Paul_Ni(原作)

2024-07-10 12:58:29
字体:
来源:转载
供稿:网友

实现异步请求


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 框架中使用 httptcpudp 支持的信息,和关于使用 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 错误。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表