您的位置:首页 > 理论基础 > 计算机网络

Http 代理工具 实战 支持网页与QQ代理

2012-03-09 00:00 369 查看
前言:


有些公司不让员工上Q或封掉某些网站,这时候,干着急没办法,只能鄱墙。
如果上网搜代理IP,很少能用,用HTTP-Tunnel Client代理软件,免费的也是经常性的掉线。

正好手头上有N台服务器,如果直接在上面装个CCProxy,也显的太明显了。
于是自己写个代理软件放上去,一来包装一下好伪装,二来又有代理功能,看着挺好。

原理解说:


1:创建一个Socket进行本地端口监听-》一个死循环while语句

2:收到消息时,产生一个线程处理->多线程处理并发请求

3:产生一个新的Socket负责转发和接收

4:原来的Socket负责把新接收的消息发送回客户端

代码细说


说明:本次示例在控制台程序里运行。

一:Program.cs

1:简单函数原型






using
System;

using
System.Collections.Generic;

using
System.Text;

using
System.Diagnostics;

using
System.Net.Sockets;

using
System.Threading;

namespace
TcpProxy
{

///

<summary>

///
by 路过秋天

///
http://www.cnblogs.com/cyq1162
///

</summary>

class
Program
{

static

void
Main(
string
[] args)
{
Listen(
808
);
//
起始监听808和CCProxy一样。

}

static

void
Write(
string
msg)
//
简化消息输出

{
Console.WriteLine(msg);
}

static

void
Listen(
int
port)
//
开始监听

{

}

static

void
ReListen(TcpListener listener)
//
监听失败,需要重新换端口监听

{

}
}
}

2:开始监听







static

void
Listen(
int
port)
//
开始监听

{
Write(
"
准备监听端口:
"

+
port);
System.Net.IPAddress ipp
=
System.Net.IPAddress.Parse(
"
0.0.0.0
"
);
//
监听本地任意IP

TcpListener tcplistener
=

new
TcpListener(ipp, port);

//
端口复用,xp下可以复用[可抢占IIS80端口],win2003下无效。

tcplistener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress,
true
);

try

{
tcplistener.Start();
}

catch
(Exception err)
{
Write(err.Message);
Write(
"
该端口已被占用,请更换端口号!!!
"
);
ReListen(tcplistener);
//
监听失败,切换端口监听

}

//
下面还有代码,暂时省略

}

3:监听失败,切换端口监听







static

void
ReListen(TcpListener listener)
//
监听失败,需要重新换端口监听

{

if
(listener
!=

null
)
{
listener.Stop();
listener
=

null
;
}
Write(
"
请输入监听端口号:
"
);

string
newPort
=
Console.ReadLine();

int
port;

if
(
int
.TryParse(newPort,
out
port))
{
Listen(port);
}

else

{
ReListen(listener);
}
}

4:开始监听,进入死循环







static

void
Listen(
int
port)
//
开始监听

{

//
上面代码省略......

Write(
"
成功监听端口:
"

+
port);
Socket socket;

while
(
true
)
{
socket
=
tcplistener.AcceptSocket();
//
获取传送和接收数据的Scoket实例

Proxy proxy
=

new
Proxy(socket);
//
Proxy类实例化

Thread thread
=

new
Thread(
new
ThreadStart(proxy.Run));
//
创建线程

thread.Start();
//
启动线程

}
}

作者:路过秋天

博客:http://cyq1162.cnblogs.com/

二:Proxy.cs

Proxy简单函数原型:






using
System;

using
System.Collections.Generic;

using
System.Text;

using
System.Net;

using
System.Net.Sockets;

using
System.IO;

namespace
TcpProxy
{

///

<summary>

///
by 路过秋天

///
http://www.cnblogs.com/cyq1162
///

</summary>

public

class
Proxy
{
Socket clientSocket;
//
接收和返回

byte
[] read
=

null
;
//
存储来自客户端请求数据包

byte
[] sendBytes
=

null
;
//
存储中转请求发送的数据

byte
[] recvBytes
=

null
;
//
存储中转请求返回的数据

bool
isConnect
=

false
;

byte
[] qqSendBytes
=
new

byte
[
4096
];
//
QQ发送缓冲

byte
[] qqRecvBytes
=

new

byte
[
4096
];
//
QQ接收缓冲

int
sendLength
=

, recvLength
=

;
//
实际发送和接收长度

public
Proxy(Socket socket)
//
初始化

{
clientSocket
=
socket;
recvBytes
=

new
Byte[
1024

*

1024
];
clientSocket.ReceiveBufferSize
=
recvBytes.Length;
clientSocket.SendBufferSize
=
recvBytes.Length;
}

public

void
Run(){}
//
主运行代码

//
从请求头里解析出url和端口号

private

string
GetUrl(
string
clientmessage,
ref

int
port){}

//
接收客户端的HTTP请求数据

private

int
ReadMessage(
byte
[] readByte,
ref
Socket s,
ref
IPAddress ipAddress,
ref

string
host,
ref

int
port){}

//
关闭socket

private

void
CloseSocket(Socket socket){}

private

void
CloseSocket(Socket socket,
bool
shutdown){}

//
QQ代理测试返回

private

byte
[] QQokProxyData(){}

//
firfox默认会发送一些请求,很烦,所以加过滤

private

bool
Filter(
string
url){ }
private void Write(string msg)
{
System.Console.WriteLine(msg);
}

}
}

Run主函数

A:分解请求头,获取要请求的IP,端口







#region
获取客户端请求数据

Write(
"
-----------------------------请求开始---------------------------
"
);

read
=

new

byte
[clientSocket.Available];
IPAddress ipAddress
=
IPAddress.Any;

string
host
=

""
;
//
主机

int
port
=

80
;
//
端口

int
bytes
=
ReadMessage(read,
ref
clientSocket,
ref
ipAddress,
ref
host,
ref
port);

if
(bytes
==

)
{
Write(
"
读取不到数据!
"
);
CloseSocket(clientSocket);

return
;
}

#endregion

Run函数分解:ReadMessage函数





ReadMessage函数



//
接收客户端的HTTP请求数据

private

int
ReadMessage(
byte
[] readByte,
ref
Socket s,
ref
IPAddress ipAddress,
ref

string
host,
ref

int
port)
{

try

{

int
bytes
=
s.Receive(readByte, readByte.Length,

);
Write(
"
收到原始请求数据:
"

+
readByte.Length);

string
header
=
Encoding.ASCII.GetString(readByte);

host
=
GetUrl(header,
ref
port);

if
(Filter(host))
{
Write(
"
系统过滤:
"

+
host);

return

;
}
Write(header);
ipAddress
=
Dns.GetHostAddresses(host)[

];

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));

return
bytes;
}

catch

{
System.Threading.Thread.Sleep(
300
);

return

;
}
}

ReadMessage函数分解:GetUrl





GetUrl函数



//
从请求头里解析出url和端口号

private

string
GetUrl(
string
clientmessage,
ref

int
port)
{

if
(clientmessage.IndexOf(
"
CONNECT
"
)
!=

-
1
)
{
isConnect
=

true
;
}

int
index1
=
clientmessage.IndexOf(
'

'
);

int
index2
=
clientmessage.IndexOf(
'

'
, index1
+

1
);

if
((index1
==

-
1
)
||
(index2
==

-
1
))
{

return

""
;
}

string
part1
=
clientmessage.Substring(index1
+

1
, index2
-
index1).Trim();

string
url
=

string
.Empty;

if
(
!
part1.Contains(
" http:// "
))
{

if
(part1.Substring(

,
1
)
==

"
/
"
)
{
part1
=

"
127.0.0.1
"

+
part1;
}
part1
=

" http:// "

+
part1;
}
Uri uri
=

null
;

try

{
uri
=

new
Uri(part1);
}

catch

{

return

""
;
}
url
=
uri.Host;
port
=
uri.Port;

return
url;
}

ReadMessage函数分解:Filter





Filter函数



private

bool
Filter(
string
url)
{

switch
(url.ToLower())
{

case

"
fffocus.cn
"
:

return

true
;
}

return

false
;
}

Run函数分解:CloseSocket函数





CloseSocket函数



private

void
CloseSocket(Socket socket)
{
CloseSocket(socket,
true
);
}

private

void
CloseSocket(Socket socket,
bool
shutdown)
{

if
(socket
!=

null
)
{

if
(shutdown)
{
socket.Shutdown(SocketShutdown.Both);
}
socket.Close();
}
}

B:创建中转Socket及建立连接







#region
创建中转Socket及建立连接

IPEndPoint ipEndpoint
=

new
IPEndPoint(ipAddress, port);
Socket IPsocket
=

new
Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

try

{
IPsocket.Connect(ipEndpoint); Write(
"
-----Socket 建立连接! IP地址:
"

+
ipAddress
+

"
网址:http://
"

+
host);
}

catch
(Exception err)
{
Write(
"
连接失败 :
"

+
err.Message);
Write(
"
退出请求!!!
"
);
CloseSocket(IPsocket,
false
);

return
;
}

#endregion

C:QQ代理测试及网页转发







if
(isConnect)
//
QQ链接方式

{

byte
[] qqOkData
=
QQokProxyData();
clientSocket.Send(qqOkData,

, qqOkData.Length,

);
}

else
//
正常网页,直接转发

{
IPsocket.Send(sendBytes,

);
}

函数分解:QQokProxyData



private

byte
[] QQokProxyData()
{

string
data
=

"
HTTP/1.0 200 Connection established
"
;
//
返回建立成功";

return
System.Text.Encoding.ASCII.GetBytes(data);
}

D:针对QQ需要进行重复来回的发送与接收





QQ转发处理



#region
QQ发送/接收中转请求

int
length
=

, count
=

;

if
(isConnect)
{

System.Threading.Thread.Sleep(
400
);
//
关键时延

//
循环发送客户端请求,接收服务器返回

DateTime start
=
DateTime.Now;

while
(
true
)

{

if
(IPsocket.Available
==

&&
clientSocket.Available
==

)
{

if
(((TimeSpan)(DateTime.Now
-
start)).TotalMinutes
>

15
)
{

break
;
//
掉线重拔处理

}
}

else

{
start
=
DateTime.Now;
}

try

{

while
(clientSocket.Available
!=

)
{
sendLength
=
clientSocket.Receive(qqSendBytes, qqSendBytes.Length,

);
IPsocket.Send(qqSendBytes, sendLength,

);
Write(
"
发送字节数:
"

+
sendLength.ToString());
}

System.Threading.Thread.Sleep(
500
);

while
(IPsocket.Available
!=

)
{
recvLength
=
IPsocket.Receive(qqRecvBytes, qqRecvBytes.Length,

);
clientSocket.Send(qqRecvBytes, recvLength,

);
Write(
"
接收字节数:
"

+
recvLength.ToString());

}
}

catch

{
}
}
}

else

{

try

{

do

{
length
=
IPsocket.Receive(recvBytes, count, IPsocket.Available,

);
count
=
count
+
length;
Write(
"
接收转发请求返回的数据中...
"

+
length);
System.Threading.Thread.Sleep(
200
);
//
关键点,请求太快数据接收不全

}

while
(IPsocket.Available
>

);
clientSocket.Send(recvBytes,

, count,

);
}

catch
(Exception err)
{
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 轻量数据层之路 框架开源系列 索引

原文链接:
http://www.cnblogs.com/cyq1162/archive/2010/09/21/1832329.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: