淺談C#實(shí)現(xiàn)Web代理服務(wù)器的幾大步驟
代理服務(wù)程序是一種廣泛使用的網(wǎng)絡(luò)應(yīng)用程序。代理程序的種類非常多,根據(jù)協(xié)議不同可以分成HTTP代理服務(wù)程序、FTP代理服務(wù)程序等,而運(yùn)行代理服務(wù)程序的服務(wù)器也就相應(yīng)稱為HTTP代理服務(wù)器和FTP代理服務(wù)器。本文將介紹用C#的Web代理服務(wù)程序代理的是HTTP協(xié)議。
一、網(wǎng)絡(luò)代理程序的優(yōu)點(diǎn)
代理服務(wù)所起的是一個(gè)橋的作用,它是網(wǎng)絡(luò)信息的中轉(zhuǎn)站。在網(wǎng)絡(luò)中應(yīng)用代理服務(wù)一般是基于以下幾個(gè)原因:
(1)充分利用IP地址資源。在局域網(wǎng)中,一般對外的IP地址都是非常有限的,為了保證局域網(wǎng)內(nèi)部的主機(jī)都能夠訪問互聯(lián)網(wǎng)資源,通過網(wǎng)絡(luò)代理就可以實(shí)現(xiàn)。
(2)能夠保證網(wǎng)絡(luò)安全。網(wǎng)絡(luò)代理可以充當(dāng)內(nèi)部網(wǎng)和互聯(lián)網(wǎng)之間的防火墻,通過過濾IP地址,限定某些IP地址對外部資源的訪問。
(3)能夠有效地隱藏自己的IP地址和主機(jī)名。由于所有對外網(wǎng)的請求都是通過代理服務(wù)器實(shí)現(xiàn)的,所以目的主機(jī)只能知道代理服務(wù)器的IP地址。
(4)提高網(wǎng)絡(luò)速度。通常代理服務(wù)器都設(shè)有一個(gè)較大的硬盤緩沖區(qū),它存儲界數(shù)據(jù),當(dāng)你再訪問相同的數(shù)據(jù)時(shí),則可以直接從緩沖區(qū)中取出信息,從而提高訪問速度。
二、網(wǎng)絡(luò)代理的類型及實(shí)現(xiàn)原理
網(wǎng)絡(luò)代理服務(wù)根據(jù)工作層次,一般可分為應(yīng)用層代理、傳輸層代理和SOCKS代理。應(yīng)用層代理是工作在TCP/IP參考模型的應(yīng)用層之上,它支持對應(yīng)用層協(xié)議(如HTTP、FTP)的代理。它提供的控制最多,但是不靈活,必須要有相應(yīng)的協(xié)議支持。如果協(xié)議不支持代理(如SMTP和POP),那就只能在應(yīng)用層以下代理,也即傳輸層代理。
傳輸層代理直接與TCP層交互,更加靈活。要求代理服務(wù)器具有部分真正服務(wù)器的功能:監(jiān)聽特定TCP或UDP端口,接收客戶端的請求同時(shí)向客戶端發(fā)出相應(yīng)的響應(yīng)。另一種代理需要改變客戶端的IP棧,即SOCKS代理。它是可用的最強(qiáng)大、最靈活的代理標(biāo)準(zhǔn)協(xié)議。SOCK V4允許代理服務(wù)器內(nèi)部的客戶端完全地連接到外部的服務(wù)器,SOCK V5增加了對客戶端的授權(quán)和認(rèn)證,因此它是一種安全性較高的代理。本節(jié)后面介紹的代理是一種應(yīng)用層上面的代理,所代理的協(xié)議是HTTP,也就是經(jīng)常見到的Web代理服務(wù)器。
正如上面所說,網(wǎng)絡(luò)代理就是一個(gè)連接客戶端(需要代理的計(jì)算機(jī))和服務(wù)器端(提供訪問資源的服務(wù)器)的橋。要實(shí)現(xiàn)這種橋的功能,網(wǎng)絡(luò)代理就必須滿足下列條件,其實(shí)也是代理服務(wù)的運(yùn)行的流程:
(1)接收并解析客戶端的請求。
(2)創(chuàng)建到服務(wù)器的新連接,并轉(zhuǎn)發(fā)客戶端的請求信息。
(3)接收服務(wù)器反饋的信息。
(4)解釋服務(wù)器的響應(yīng)并將該響應(yīng)傳回給客戶端。
網(wǎng)絡(luò)代理雖然有很多優(yōu)點(diǎn),但由于使用代理后,自己對網(wǎng)絡(luò)的所有請求都是通過代理服務(wù)器這個(gè)中間人來實(shí)現(xiàn)的,所以有可能碰上存有惡意的人監(jiān)聽你的輸入的內(nèi)容。同樣,如果選擇的代理服務(wù)器的帶寬比較小,使用代理還會降低網(wǎng)速。
總而言之,使用代理有利有弊,使用者要根據(jù)自身的情況來決定。但無論如何,選擇一個(gè)好的代理服務(wù)器是非常重要的。
三、C#實(shí)現(xiàn)Web代理服務(wù)器程序
經(jīng)過了上面的介紹,我想大家對代理服務(wù)應(yīng)該有了一個(gè)基本的認(rèn)識,下面就讓我們通過一個(gè)實(shí)例來深入體會一下如何用C#實(shí)現(xiàn)Web代理服務(wù)器。Web代理服務(wù)的功能順序是這樣的:
(1)偵聽端口,等待客戶端瀏覽器發(fā)送來的Web請求信息。
(2)接收到客戶端Web請求信息后,解析出目標(biāo)Web服務(wù)器的地址,并創(chuàng)建一個(gè)Socket實(shí)例,并以此實(shí)例連接Web服務(wù)器上。
(3)通過創(chuàng)建的Socket傳送客戶端的Web請求數(shù)據(jù)包到Web服務(wù)器的80端口。
(4)接收Web服務(wù)器返回的頁面數(shù)據(jù)。
(5)把接收來的數(shù)據(jù)傳送到客戶端,從而實(shí)現(xiàn)Web代理。
客戶端對某個(gè)Web地址的瀏覽,可能要傳送很多的Web請求信息(比如網(wǎng)頁中的圖像、Flash等),為了更快更準(zhǔn)確地處理這些信息,Web代理服務(wù)程序通常采用多線程來處理每一個(gè)Web請求。細(xì)心的讀者可能會發(fā)現(xiàn),處理每一個(gè)客戶端的Web請求信息,代理服務(wù)器軟件都要使用二個(gè)Socket,一個(gè)是用來接收/傳送客戶機(jī)的信息,一個(gè)是和Web服務(wù)器進(jìn)行交流。為了區(qū)分這二個(gè)Socket,我們把和服務(wù)器對話的稱為“服務(wù)Socket”,和客戶端機(jī)器對話的稱為“客戶Socket”。
下面就開始C#實(shí)現(xiàn)Web代理服務(wù)器的編寫工作。這個(gè)實(shí)例包含三個(gè)部分內(nèi)容:
1.創(chuàng)建一個(gè)Web代理類。
2.Web代理服務(wù)的類的實(shí)例化。
3.如何通過這個(gè)Web代理類的實(shí)例實(shí)現(xiàn)Web代理服務(wù)。
(一)創(chuàng)建一個(gè)Web代理類
具體操作步驟如下:
1.啟動Visual Studio.Net,依次選擇“文件”、“新建”、“項(xiàng)目”菜單后,在彈出“新建項(xiàng)目”對話框中將“項(xiàng)目類型”設(shè)置為“Visual C#項(xiàng)目”,將“模板”設(shè)置為“Windows應(yīng)用程序”,在“名稱”文本框中輸入“WebProxy”,在“位置”文本框中輸入“E:VS.NET項(xiàng)目”,然后單擊“確定”按鈕,這樣項(xiàng)目便建立好了。
2.依次選擇菜單“項(xiàng)目”、“添加類”,將彈出“添加新項(xiàng)”對話框。
3.將“模板”設(shè)置為“類”。
4.在“名稱”文本框中輸入“Proxy”,單擊“打開”按鈕
5.在“解決方案資源管理器”窗口中,雙擊Proxy.cs文件,進(jìn)入Proxy.cs文件的編輯界
6.在Proxy.cs源文件的開頭,添加下列代碼,下列代碼是導(dǎo)入Proxy.cs中要使用到的命名空間:
- using System;
- using System.Net;
- using System.Net.Sockets;
- using System.Text;
- using System.IO;
7.用下列構(gòu)造函數(shù)替代默認(rèn)的構(gòu)造函數(shù)。下面的代碼是在Proxy類中創(chuàng)建一個(gè)構(gòu)造函數(shù)。Proxy類只有一個(gè)構(gòu)造函數(shù),并且這個(gè)構(gòu)造函數(shù)只有一個(gè)參數(shù),這個(gè)參數(shù)是Socket對象,它主要用來和客戶端進(jìn)行數(shù)據(jù)交換,是一個(gè)“客戶Socket”:
- public Proxy(Socket socket)
- {
- //
- // TODO: 在此處添加構(gòu)造函數(shù)邏輯
- //
- this.clientSocket = socket ;
- }
8.在定義Proxy類代碼區(qū)中加入下列代碼,下列代碼是定義Proxy類中的使用的一些變量,這些變量主要是在后面的定義Run方法中使用。
- Socket clientSocket;
- Byte[] read = new byte[1024];
- //定義一個(gè)空間,存儲來自客戶端請求數(shù)據(jù)包
- Byte [] Buffer = null;
- Encoding ASCII = Encoding.ASCII;
- //設(shè)定編碼
- Byte[] RecvBytes = new Byte[4096];
- //定義一個(gè)空間,存儲Web服務(wù)器返回的數(shù)據(jù)
9.創(chuàng)建Proxy類中的Run方法。Run方法是Proxy類中唯一的方法。其功能是從客戶端接收HTTP請求,并傳送到Web服務(wù)器,然后從Web服務(wù)器接收反饋來的數(shù)據(jù),并傳送到客戶端。為了實(shí)現(xiàn)這二個(gè)不同方面的數(shù)據(jù)傳送,Run方法中是通過兩個(gè)Socket實(shí)例來實(shí)現(xiàn)的。在編寫Run方法的時(shí)候,要注意下面兩點(diǎn):
(1)由于HTTP建立于TCP協(xié)議之上,所以創(chuàng)建的Socket實(shí)例應(yīng)該使用TCP協(xié)議。下面代碼是創(chuàng)建可以傳送HTTP請求命令到Web服務(wù)器和接收來自Web服務(wù)器反饋來信息的Socket實(shí)例:
- Socket IPsocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
(2)另外一個(gè)Socket是在代理服務(wù)程序偵聽端口號,接收連接請求時(shí)候得到的,所以應(yīng)該以此Socket為參數(shù),利用Proxy類中的構(gòu)造函數(shù)來創(chuàng)建一個(gè)Proxy實(shí)例。此Socket實(shí)現(xiàn)從客戶端接收HTTP請求信息,并傳送數(shù)據(jù)到客戶端。
Socket創(chuàng)建和使用是實(shí)現(xiàn)Web代理軟件的關(guān)鍵。在構(gòu)造函數(shù)代碼后面,輸入下列代碼:
- 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("遠(yuǎn)程主機(jī)名: " + IPHost.HostName);
- string [] aliases = IPHost.Aliases;
- IPAddress[] address = IPHost.AddressList;
- Console.WriteLine("Web服務(wù)器IP地址:" + address[0]);
- //解析出要訪問的服務(wù)器地址
- IPEndPoint ipEndpoint = new IPEndPoint(address[0], 80);
- Socket IPsocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- //創(chuàng)建連接Web服務(wù)器端的Socket對象
- IPsocket.Connect(ipEndpoint);
- //Socket連Web接服務(wù)器
- if (IPsocket.Connected)
- Console.WriteLine("Socket 正確連接!");
- string GET = clientmessage;
- Byte[] ByteGet = ASCII.GetBytes(GET);
- IPsocket.Send(ByteGet, ByteGet.Length, 0);
- //代理訪問軟件對服務(wù)器端傳送HTTP請求命令
- Int32 rBytes = IPsocket.Receive(RecvBytes, RecvBytes.Length, 0);
- //代理訪問軟件接收來自Web服務(wù)器端的反饋信息
- Console.WriteLine("接收字節(jié)數(shù):" + rBytes.ToString());
- String strRetPage = null;
- strRetPagestrRetPage = strRetPage + ASCII.GetString(RecvBytes, 0, rBytes);
- while (rBytes > 0)
- {
- rBytes = IPsocket.Receive(RecvBytes, RecvBytes.Length, 0);
- strRetPagestrRetPage = strRetPage + ASCII.GetString(RecvBytes, 0, rBytes);
- }
- IPsocket.Shutdown(SocketShutdown.Both);
- IPsocket.Close();
- SendMessage(clientSocket, strRetPage);
- //代理服務(wù)軟件往客戶端傳送接收到的信息
- }
- catch (Exception exc2)
- }
//接收客戶端的HTTP請求數(shù)據(jù)
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服務(wù)器反饋的數(shù)據(jù)到客戶端
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é)數(shù):" + length.ToString());
s.Send(Buffer, length, 0);
}
至此,Proxy類的定義過程就完成了。
(二)利用Proxy類,實(shí)現(xiàn)Web代理
下面是利用Proxy類實(shí)現(xiàn)Web代理程序的具體實(shí)現(xiàn)步驟,Proxy類被定義在命名空間WebProxy中:
1.在Visual Studio .Net的代碼編輯器中打開Class1.cs文件,進(jìn)入Class1.cs的代碼編輯界面。
2.在Class1.cs源文件的開頭導(dǎo)入下列命名空間:
- using System;
- using System.Net;
- using System.Net.Sockets;
- using System.Text;
- using System.IO;
- using System.Threading;
- using WebProxy;
3.在Main函數(shù)中添加下列代碼,下列代碼是利用Proxy類,來實(shí)現(xiàn)Web代理程序:
- const int port = 8000 ;
- //定義端口號
- TcpListener tcplistener = new TcpListener(port);
- Console.WriteLine("偵聽端口號: " + port.ToString());
- tcplistener.Start();
- //偵聽端口號
- while (true)
- {
- Socket socket = tcplistener.AcceptSocket();
- //并獲取傳送和接收數(shù)據(jù)的Scoket實(shí)例
- Proxy proxy = new Proxy(socket);
- //Proxy類實(shí)例化
- Thread thread = new Thread(new ThreadStart(proxy.Run));
- //創(chuàng)建線程
- thread.Start();
- //啟動線程
- }
保存上面的所有步驟,這樣一個(gè)簡單Web代理程序就算是完成了。此Web代理程序偵聽的是8000端口號。
(三)測試Web代碼程序
Web代理程序要通過二臺計(jì)算機(jī)才能夠?qū)崿F(xiàn),其中的一臺計(jì)算機(jī)運(yùn)行Web代理程序充當(dāng)Web代理服務(wù)器,另外一臺計(jì)算機(jī)充當(dāng)客戶機(jī),通過Web代理服務(wù)器來瀏覽網(wǎng)頁。在確定Web代理軟件運(yùn)行后,需要對客戶機(jī)進(jìn)行進(jìn)行必要的設(shè)置:
1.打開IE瀏覽器。
2.依次選擇“工具”、“Internet選項(xiàng)”,在彈出的“Internet選項(xiàng)”對話框中選擇“連接”頁面,單擊其中的“局域網(wǎng)設(shè)置”按鈕,在彈出的“局域網(wǎng)(LAN)設(shè)置”對話框,選擇“為LAN使用代理服務(wù)器(X),(這些設(shè)置不會應(yīng)用于撥號和VPN連接)”多選框,并在其中的“地址”文本框中輸入代理服務(wù)器的IP地址,比如“10.138.198.213”,在“端口”文本框中輸入“8000”。
此時(shí)客戶端的設(shè)置就完成了。在確定IP地址為“10.138.198.213”的這臺計(jì)算機(jī)已經(jīng)運(yùn)行上面介紹的Web代理程序后,打開客戶端的IE瀏覽器,并輸入要瀏覽的網(wǎng)址,就可以通過Web代理服務(wù)器來瀏覽網(wǎng)頁了。
四、C#實(shí)現(xiàn)Web代理服務(wù)器總結(jié)
至此一個(gè)簡單的C#實(shí)現(xiàn)Web代理服務(wù)器軟件就算基本完成了。雖然Web代理服務(wù)器的實(shí)現(xiàn)原理相對簡單,但具體實(shí)現(xiàn)還是很繁瑣的。網(wǎng)絡(luò)代理是一個(gè)內(nèi)容豐富,實(shí)現(xiàn)復(fù)雜的論題,本節(jié)介紹的代理服務(wù)軟件,無論在實(shí)現(xiàn)的協(xié)議種類,還是實(shí)現(xiàn)的功能,都只能算很小的一部分。希望各位能夠通過本文的介紹,結(jié)合其他相關(guān)的知識,創(chuàng)造出功能更強(qiáng)大、安全性更高,使用更穩(wěn)定的網(wǎng)絡(luò)代理服務(wù)程序來。
【編輯推薦】