Http 代理工具 实战 支持网页与QQ代理
前言:
有些公司不讓員工上Q或封掉某些網站,這時候,干著急沒辦法,只能鄱墻。
如果上網搜代理IP,很少能用,用HTTP-TunnelClient代理軟件,免費的也是經常性的掉線。
正好手頭上有N臺服務器,如果直接在上面裝個CCProxy,也顯的太明顯了。
于是自己寫個代理軟件放上去,一來包裝一下好偽裝,二來又有代理功能,看著挺好。
原理解說:
1:創建一個Socket進行本地端口監聽-》一個死循環while語句
2:收到消息時,產生一個線程處理->多線程處理并發請求
3:產生一個新的Socket負責轉發和接收
4:原來的Socket負責把新接收的消息發送回客戶端
代碼細說
說明:本次示例在控制臺程序里運行。
一:Program.cs
1:簡單函數原型
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;
usingSystem.Diagnostics;
usingSystem.Net.Sockets;
usingSystem.Threading;
namespaceTcpProxy
{
///<summary>
///by路過秋天
///http://www.cnblogs.com/cyq1162
///</summary>
classProgram
{
staticvoidMain(string[]args)
{
Listen(808);//起始監聽808和CCProxy一樣。
}
staticvoidWrite(stringmsg)//簡化消息輸出
{
Console.WriteLine(msg);
}
staticvoidListen(intport)//開始監聽
{
}
staticvoidReListen(TcpListenerlistener)//監聽失敗,需要重新換端口監聽
{
}
}
}
2:開始監聽
staticvoidListen(intport)//開始監聽
{
Write("準備監聽端口:"+port);
System.Net.IPAddressipp=System.Net.IPAddress.Parse("0.0.0.0");//監聽本地任意IP
TcpListenertcplistener=newTcpListener(ipp,port);
//端口復用,xp下可以復用[可搶占IIS80端口],win2003下無效。
tcplistener.Server.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.ReuseAddress,true);
try
{
tcplistener.Start();
}
catch(Exceptionerr)
{
Write(err.Message);
Write("該端口已被占用,請更換端口號!!!");
ReListen(tcplistener);//監聽失敗,切換端口監聽
}
//下面還有代碼,暫時省略
}
3:監聽失敗,切換端口監聽
staticvoidReListen(TcpListenerlistener)//監聽失敗,需要重新換端口監聽
{
if(listener!=null)
{
listener.Stop();
listener=null;
}
Write("請輸入監聽端口號:");
stringnewPort=Console.ReadLine();
intport;
if(int.TryParse(newPort,outport))
{
Listen(port);
}
else
{
ReListen(listener);
}
}
4:開始監聽,進入死循環
staticvoidListen(intport)//開始監聽
{
//上面代碼省略......
Write("成功監聽端口:"+port);
Socketsocket;
while(true)
{
socket=tcplistener.AcceptSocket();//獲取傳送和接收數據的Scoket實例
Proxyproxy=newProxy(socket);//Proxy類實例化
Threadthread=newThread(newThreadStart(proxy.Run));//創建線程
thread.Start();//啟動線程
}
}
作者:路過秋天
博客:http://cyq1162.cnblogs.com/
二:Proxy.cs
Proxy簡單函數原型:
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;
usingSystem.Net;
usingSystem.Net.Sockets;
usingSystem.IO;
namespaceTcpProxy
{
///<summary>
///by路過秋天
///http://www.cnblogs.com/cyq1162
///</summary>
publicclassProxy
{
SocketclientSocket;//接收和返回
byte[]read=null;//存儲來自客戶端請求數據包
byte[]sendBytes=null;//存儲中轉請求發送的數據
byte[]recvBytes=null;//存儲中轉請求返回的數據
boolisConnect=false;
byte[]qqSendBytes=newbyte[4096];//QQ發送緩沖
byte[]qqRecvBytes=newbyte[4096];//QQ接收緩沖
intsendLength=0,recvLength=0;//實際發送和接收長度
publicProxy(Socketsocket)//初始化
{
clientSocket=socket;
recvBytes=newByte[1024*1024];
clientSocket.ReceiveBufferSize=recvBytes.Length;
clientSocket.SendBufferSize=recvBytes.Length;
}
publicvoidRun(){}//主運行代碼
//從請求頭里解析出url和端口號
privatestringGetUrl(stringclientmessage,refintport){}
//接收客戶端的HTTP請求數據
privateintReadMessage(byte[]readByte,refSockets,refIPAddressipAddress,refstringhost,refintport){}
//關閉socket
privatevoidCloseSocket(Socketsocket){}
privatevoidCloseSocket(Socketsocket,boolshutdown){}
//QQ代理測試返回
privatebyte[]QQokProxyData(){}
//firfox默認會發送一些請求,很煩,所以加過濾
privateboolFilter(stringurl){}
private void Write(string msg)
{
System.Console.WriteLine(msg);
}
}
}
Run主函數
A:分解請求頭,獲取要請求的IP,端口
#region獲取客戶端請求數據
Write("-----------------------------請求開始---------------------------");
read=newbyte[clientSocket.Available];
IPAddressipAddress=IPAddress.Any;
stringhost="";//主機
intport=80;//端口
intbytes=ReadMessage(read,refclientSocket,refipAddress,refhost,refport);
if(bytes==0)
{
Write("讀取不到數據!");
CloseSocket(clientSocket);
return;
}
#endregion
Run函數分解:ReadMessage函數
ReadMessage函數
//接收客戶端的HTTP請求數據
privateintReadMessage(byte[]readByte,refSockets,refIPAddressipAddress,refstringhost,refintport)
{
try
{
intbytes=s.Receive(readByte,readByte.Length,0);
Write("收到原始請求數據:"+readByte.Length);
stringheader=Encoding.ASCII.GetString(readByte);
host=GetUrl(header,refport);
if(Filter(host))
{
Write("系統過濾:"+host);
return0;
}
Write(header);
ipAddress=Dns.GetHostAddresses(host)[0];
if(!isConnect)
{
header=header.Replace("http://"+host,"");
}
sendBytes=Encoding.ASCII.GetBytes(header);
System.Threading.Thread.Sleep(50);
Write("轉發請求數據:"+sendBytes.Length);
Write(Encoding.ASCII.GetString(sendBytes));
returnbytes;
}
catch
{
System.Threading.Thread.Sleep(300);
return0;
}
}
ReadMessage函數分解:GetUrl
GetUrl函數
//從請求頭里解析出url和端口號
privatestringGetUrl(stringclientmessage,refintport)
{
if(clientmessage.IndexOf("CONNECT")!=-1)
{
isConnect=true;
}
intindex1=clientmessage.IndexOf('');
intindex2=clientmessage.IndexOf('',index1+1);
if((index1==-1)||(index2==-1))
{
return"";
}
stringpart1=clientmessage.Substring(index1+1,index2-index1).Trim();
stringurl=string.Empty;
if(!part1.Contains("http://"))
{
if(part1.Substring(0,1)=="/")
{
part1="127.0.0.1"+part1;
}
part1="http://"+part1;
}
Uriuri=null;
try
{
uri=newUri(part1);
}
catch
{
return"";
}
url=uri.Host;
port=uri.Port;
returnurl;
}
ReadMessage函數分解:Filter
Filter函數
privateboolFilter(stringurl)
{
switch(url.ToLower())
{
case"fffocus.cn":
returntrue;
}
returnfalse;
}
Run函數分解:CloseSocket函數
CloseSocket函數
privatevoidCloseSocket(Socketsocket)
{
CloseSocket(socket,true);
}
privatevoidCloseSocket(Socketsocket,boolshutdown)
{
if(socket!=null)
{
if(shutdown)
{
socket.Shutdown(SocketShutdown.Both);
}
socket.Close();
}
}
B:創建中轉Socket及建立連接
#region創建中轉Socket及建立連接
IPEndPointipEndpoint=newIPEndPoint(ipAddress,port);
SocketIPsocket=newSocket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
try
{
IPsocket.Connect(ipEndpoint);Write("-----Socket建立連接!IP地址:"+ipAddress+"網址:http://"+host);
}
catch(Exceptionerr)
{
Write("連接失敗:"+err.Message);
Write("退出請求!!!");
CloseSocket(IPsocket,false);
return;
}
#endregion
C:QQ代理測試及網頁轉發
if(isConnect)//QQ鏈接方式
{
byte[]qqOkData=QQokProxyData();
clientSocket.Send(qqOkData,0,qqOkData.Length,0);
}
else//正常網頁,直接轉發
{
IPsocket.Send(sendBytes,0);
}
函數分解:QQokProxyData
privatebyte[]QQokProxyData()
{
stringdata="HTTP/1.0200Connectionestablished";//返回建立成功";
returnSystem.Text.Encoding.ASCII.GetBytes(data);
}
D:針對QQ需要進行重復來回的發送與接收
QQ轉發處理
#regionQQ發送/接收中轉請求
intlength=0,count=0;
if(isConnect)
{
System.Threading.Thread.Sleep(400);//關鍵時延
//循環發送客戶端請求,接收服務器返回
DateTimestart=DateTime.Now;
while(true)
{
if(IPsocket.Available==0&&clientSocket.Available==0)
{
if(((TimeSpan)(DateTime.Now-start)).TotalMinutes>15)
{
break;//掉線重拔處理
}
}
else
{
start=DateTime.Now;
}
try
{
while(clientSocket.Available!=0)
{
sendLength=clientSocket.Receive(qqSendBytes,qqSendBytes.Length,0);
IPsocket.Send(qqSendBytes,sendLength,0);
Write("發送字節數:"+sendLength.ToString());
}
System.Threading.Thread.Sleep(500);
while(IPsocket.Available!=0)
{
recvLength=IPsocket.Receive(qqRecvBytes,qqRecvBytes.Length,0);
clientSocket.Send(qqRecvBytes,recvLength,0);
Write("接收字節數:"+recvLength.ToString());
}
}
catch
{
}
}
}
else
{
try
{
do
{
length=IPsocket.Receive(recvBytes,count,IPsocket.Available,0);
count=count+length;
Write("接收轉發請求返回的數據中..."+length);
System.Threading.Thread.Sleep(200);//關鍵點,請求太快數據接收不全
}
while(IPsocket.Available>0);
clientSocket.Send(recvBytes,0,count,0);
}
catch(Exceptionerr)
{
Write(err.Message);
}
}
#endregion
E:結束請求,關閉客戶端Socket
#region結束請求,關閉客戶端Socket
Write("接收完成。返回客戶端數據..."+count);
CloseSocket(IPsocket);
CloseSocket(clientSocket);
recvBytes=null;
Write("本次請求完成,已關閉連接...");
Write("-----------------------------請求結束---------------------------");
#endregion
結言:
本QQ代理軟件在服務器上運行長達三個多月,使用過程未發現異常退出情況。當然前提就我一個人在用了~哈哈~
附以前寫的幾篇文章:
1:簡單實現Http代理工具
2:簡單實現Http代理工具--端口復用與QQ代理
3:簡單實現Http代理工具--完善支持QQ代理
4:C# 控制臺程序 不顯示在任務欄 只在進程中顯示
看本篇的時候也請支持一下我的開源框架:CYQ.Data 輕量數據層之路 框架開源系列 索引
|
版權聲明:本文原創發表于 博客園,作者為 路過秋天 本文歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則視為侵權。 |
|
個人微信公眾號 |
創業QQ群:617713515 |
Donation(掃碼支持作者):支付寶: |
Donation(掃碼支持作者):微信: |
總結
以上是生活随笔為你收集整理的Http 代理工具 实战 支持网页与QQ代理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql+导出当前配置,mysql 查
- 下一篇: Vijos 1385盗窃-月之眼