明輝手游網中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

完成Web代理技巧

[摘要]C#網絡編程之十二——實現(xiàn)Web代理功能  代理服務程序是一種廣泛使用的網絡應用程序。代理程序的種類非常多,根據協(xié)議不同可以分成HTTP代理服務程序、FTP代理服務程序等,而運行代理服務程序的服務器也就相應稱為HTTP代理服務器和FTP代理服務器。本文將介紹的Web代理服務程序代理的是HTTP協(xié)議...

C#網絡編程之十二——實現(xiàn)Web代理功能


  代理服務程序是一種廣泛使用的網絡應用程序。代理程序的種類非常多,根據協(xié)議不同可以分成HTTP代理服務程序、FTP代理服務程序等,而運行代理服務程序的服務器也就相應稱為HTTP代理服務器和FTP代理服務器。本文將介紹的Web代理服務程序代理的是HTTP協(xié)議。
  一、網絡代理程序的優(yōu)點
  代理服務所起的是一個橋的作用,它是網絡信息的中轉站。在網絡中應用代理服務一般是基于以下幾個原因:
 。1)充分利用IP地址資源。在局域網中,一般對外的IP地址都是非常有限的,為了保證局域網內部的主機都能夠訪問互聯(lián)網資源,通過網絡代理就可以實現(xiàn)。
 。2)能夠保證網絡安全。網絡代理可以充當內部網和互聯(lián)網之間的防火墻,通過過濾IP地址,限定某些IP地址對外部資源的訪問。
  (3)能夠有效地隱藏自己的IP地址和主機名。由于所有對外網的請求都是通過代理服務器實現(xiàn)的,所以目的主機只能知道代理服務器的IP地址。
 。4)提高網絡速度。通常代理服務器都設有一個較大的硬盤緩沖區(qū),它存儲界數據,當你再訪問相同的數據時,則可以直接從緩沖區(qū)中取出信息,從而提高訪問速度。
  二、網絡代理的類型及實現(xiàn)原理
  網絡代理服務根據工作層次,一般可分為應用層代理、傳輸層代理和SOCKS代理。應用層代理是工作在TCP/IP參考模型的應用層之上,它支持對應用層協(xié)議(如HTTP、FTP)的代理。它提供的控制最多,但是不靈活,必須要有相應的協(xié)議支持。如果協(xié)議不支持代理(如SMTP和POP),那就只能在應用層以下代理,也即傳輸層代理。傳輸層代理直接與TCP層交互,更加靈活。要求代理服務器具有部分真正服務器的功能:監(jiān)聽特定TCP或UDP端口,接收客戶端的請求同時向客戶端發(fā)出相應的響應。另一種代理需要改變客戶端的IP棧,即SOCKS代理。它是可用的最強大、最靈活的代理標準協(xié)議。SOCK V4允許代理服務器內部的客戶端完全地連接到外部的服務器,SOCK V5增加了對客戶端的授權和認證,因此它是一種安全性較高的代理。本節(jié)后面介紹的代理是一種應用層上面的代理,所代理的協(xié)議是HTTP,也就是經常見到的Web代理。
  正如上面所說,網絡代理就是一個連接客戶端(需要代理的計算機)和服務器端(提供訪問資源的服務器)的橋。要實現(xiàn)這種橋的功能,網絡代理就必須滿足下列條件,其實也是代理服務的運行的流程:
 。1)接收并解析客戶端的請求。
 。2)創(chuàng)建到服務器的新連接,并轉發(fā)客戶端的請求信息。
 。3)接收服務器反饋的信息。
  (4)解釋服務器的響應并將該響應傳回給客戶端。
  圖1是網絡代理服務的一個典型模型圖:

  實現(xiàn)Web代理功能
  網絡代理雖然有很多優(yōu)點,但由于使用代理后,自己對網絡的所有請求都是通過代理服務器這個中間人來實現(xiàn)的,所以有可能碰上存有惡意的人監(jiān)聽你的輸入的內容。同樣,如果選擇的代理服務器的帶寬比較小,使用代理還會降低網速。
總而言之,使用代理有利有弊,使用者要根據自身的情況來決定。但無論如何,選擇一個好的代理服務器是非常重要的。
  三、C#實現(xiàn)Web代理服務程序
  經過了上面的介紹,我想大家對代理服務應該有了一個基本的認識,下面就讓我們通過一個實例來深入體會一下如何用C#實現(xiàn)Web代理服務。Web代理服務的功能順序是這樣的:
  (1)偵聽端口,等待客戶端瀏覽器發(fā)送來的Web請求信息。
 。2)接收到客戶端Web請求信息后,解析出目標Web服務器的地址,并創(chuàng)建一個Socket實例,并以此實例連接Web服務器上。
  (3)通過創(chuàng)建的Socket傳送客戶端的Web請求數據包到Web服務器的80端口。
 。4)接收Web服務器返回的頁面數據。
  (5)把接收來的數據傳送到客戶端,從而實現(xiàn)Web代理。
  客戶端對某個Web地址的瀏覽,可能要傳送很多的Web請求信息(比如網頁中的圖像、Flash等),為了更快更準確地處理這些信息,Web代理服務程序通常采用多線程來處理每一個Web請求。細心的讀者可能會發(fā)現(xiàn),處理每一個客戶端的Web請求信息,代理服務器軟件都要使用二個Socket,一個是用來接收/傳送客戶機的信息,一個是和Web服務器進行交流。為了區(qū)分這二個Socket,我們把和服務器對話的稱為“服務Socket”,和客戶端機器對話的稱為“客戶Socket”。
  下面就開始Web代理服務程序的編寫工作。這個實例包含三個部分內容:
  1.創(chuàng)建一個Web代理類。
  2.Web代理服務的類的實例化。
  3.如何通過這個Web代理類的實例實現(xiàn)Web代理服務。
  (一)創(chuàng)建一個Web代理類
  具體操作步驟如下:
  1.啟動Visual Studio.Net,依次選擇“文件”、“新建”、“項目”菜單后,在彈出“新建項目”對話框中將“項目類型”設置為“Visual C#項目”,將“模板”設置為“Windows應用程序”,在“名稱”文本框中輸入“WebProxy”,在“位置”文本框中輸入“E:\VS.NET項目”,然后單擊“確定”按鈕,這樣項目便建立好了。
  2.依次選擇菜單“項目”、“添加類”,將彈出“添加新項”對話框。
  3.將“模板”設置為“類”。
  4.在“名稱”文本框中輸入“Proxy”,單擊“打開”按鈕,具體如圖2所示:
  實現(xiàn)Web代理功能
  5.在“解決方案資源管理器”窗口中,雙擊Proxy.cs文件,進入Proxy.cs文件的編輯界
  6.在Proxy.cs源文件的開頭,添加下列代碼,下列代碼是導入Proxy.cs中要使用到的命名空間:
  using System;
  using System.Net;
  using System.Net.Sockets;
  using System.Text;
  using System.IO;
  7.用下列構造函數替代默認的構造函數。下面的代碼是在Proxy類中創(chuàng)建一個構造函數。Proxy類只有一個構造函數,并且這個構造函數只有一個參數,這個參數是Socket對象,它主要用來和客戶端進行數據交換,是一個“客戶Socket”:
  public Proxy(Socket socket)
  {
  //
  // TODO: 在此處添加構造函數邏輯
  //
  this.clientSocket = socket ;
  }


[page_break]  8.在定義Proxy類代碼區(qū)中加入下列代碼,下列代碼是定義Proxy類中的使用的一些變量,這些變量主要是在后面的定義Run方法中使用。
  Socket clientSocket;
  Byte[] read = new byte[1024];
  //定義一個空間,存儲來自客戶端請求數據包
  Byte [] Buffer = null;
  Encoding ASCII = Encoding.ASCII;
  //設定編碼
  Byte[] RecvBytes = new Byte[4096];
  //定義一個空間,存儲Web服務器返回的數據
  9.創(chuàng)建Proxy類中的Run方法。Run方法是Proxy類中唯一的方法。其功能是從客戶端接收HTTP請求,并傳送到Web服務器,然后從Web服務器接收反饋來的數據,并傳送到客戶端。為了實現(xiàn)這二個不同方面的數據傳送,Run方法中是通過兩個Socket實例來實現(xiàn)的。在編寫Run方法的時候,要注意下面兩點:
 。1)由于HTTP建立于TCP協(xié)議之上,所以創(chuàng)建的Socket實例應該使用TCP協(xié)議。下面代碼是創(chuàng)建可以傳送HTTP請求命令到Web服務器和接收來自Web服務器反饋來信息的Socket實例:
  Socket IPsocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 。2)另外一個Socket是在代理服務程序偵聽端口號,接收連接請求時候得到的,所以應該以此Socket為參數,利用Proxy類中的構造函數來創(chuàng)建一個Proxy實例。此Socket實現(xiàn)從客戶端接收HTTP請求信息,并傳送數據到客戶端。
  Socket創(chuàng)建和使用是實現(xiàn)Web代理軟件的關鍵。在構造函數代碼后面,輸入下列代碼:
  public void Run()
  {
  string clientmessage = " " ;
  //存放來自客戶端的HTTP請求字符串
  string URL = " " ;
  //存放解析出地址請求信息
  int bytes = ReadMessage(read, ref clientSocket, ref clientmessage);
  if (bytes == 0)
  {
  return ;
  }
  int index1 = clientmessage.IndexOf(' ');
  int index2 = clientmessage.IndexOf(' ', index1 + 1);
  if ((index1 == -1) (index2 == -1))
  {
  throw new IOException();
  }
  string part1 = clientmessage.Substring(index1 + 1, index2 - index1);
  int index3 = part1.IndexOf('/', index1 + 8);
  int index4 = part1.IndexOf(' ', index1 + 8);
  int index5 = index4 - index3;
  URL = part1.Substring(index1 + 4, (part1.Length - index5) - 8);
  try
  {
  IPHostEntry IPHost = Dns.Resolve(URL);
  Console.WriteLine("遠程主機名: " + IPHost.HostName);
  string [] aliases = IPHost.Aliases;
  IPAddress[] address = IPHost.AddressList;
  Console.WriteLine("Web服務器IP地址:" + address[0]);
  //解析出要訪問的服務器地址
  IPEndPoint ipEndpoint = new IPEndPoint(address[0], 80);
  Socket IPsocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  //創(chuàng)建連接Web服務器端的Socket對象
  IPsocket.Connect(ipEndpoint);
  //Socket連Web接服務器
  if (IPsocket.Connected)
  Console.WriteLine("Socket 正確連接!");
  string GET = clientmessage;
  Byte[] ByteGet = ASCII.GetBytes(GET);
  IPsocket.Send(ByteGet, ByteGet.Length, 0);
  //代理訪問軟件對服務器端傳送HTTP請求命令
  Int32 rBytes = IPsocket.Receive(RecvBytes, RecvBytes.Length, 0);
  //代理訪問軟件接收來自Web服務器端的反饋信息
  Console.WriteLine("接收字節(jié)數:" + rBytes.ToString());
  String strRetPage = null;
  strRetPage = strRetPage + ASCII.GetString(RecvBytes, 0, rBytes);
  while (rBytes > 0)
  {
  rBytes = IPsocket.Receive(RecvBytes, RecvBytes.Length, 0);
  strRetPage = strRetPage + ASCII.GetString(RecvBytes, 0, rBytes);
  }
  IPsocket.Shutdown(SocketShutdown.Both);
  IPsocket.Close();
  SendMessage(clientSocket, strRetPage);
  //代理服務軟件往客戶端傳送接收到的信息
  }
  catch (Exception exc2)
  {
  Console.WriteLine(exc2.ToString());
  }
  }
  
  //接收客戶端的HTTP請求數據
  private int ReadMessage(byte [] ByteArray, ref Socket s, ref String clientmessage)
  {
  int bytes = s.Receive(ByteArray, 1024, 0);
  string messagefromclient = Encoding.ASCII.GetString(ByteArray);
  clientmessage = (String)messagefromclient;
  return bytes;
  }
  
  //傳送從Web服務器反饋的數據到客戶端
  private void SendMessage(Socket s, string message)
  {
  Buffer = new Byte[message.Length + 1];
  int length = ASCII.GetBytes(message, 0, message.Length, Buffer, 0);
  Console.WriteLine("傳送字節(jié)數:" + length.ToString());
  s.Send(Buffer, length, 0);
  }
  至此,Proxy類的定義過程就完成了。




相關文章