前言:
有些公司不让员工上Q或封掉某些网站,这时候,干着急没办法,只能鄱墙。
如果上网搜代理IP,很少能用,用HTTP-Tunnel Client代理软件,免费的也是经常性的掉线。
正好手头上有N台服务器,如果直接在上面装个CCProxy,也显的太明显了。
于是自己写个代理软件放上去,一来包装一下好伪装,二来又有代理功能,看着挺好。
如果上网搜代理IP,很少能用,用HTTP-Tunnel Client代理软件,免费的也是经常性的掉线。
正好手头上有N台服务器,如果直接在上面装个CCProxy,也显的太明显了。
于是自己写个代理软件放上去,一来包装一下好伪装,二来又有代理功能,看着挺好。
原理解说:
1:创建一个Socket进行本地端口监听-》一个死循环while语句
2:收到消息时,产生一个线程处理->多线程处理并发请求
3:产生一个新的Socket负责转发和接收
4:原来的Socket负责把新接收的消息发送回客户端
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) // 监听失败,需要重新换端口监听
{
}
}
}
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); // 监听失败,切换端口监听
}
// 下面还有代码,暂时省略
}
{
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);
}
}
{
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(); // 启动线程
}
}
{
// 上面代码省略......
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 = 0 , recvLength = 0 ; // 实际发送和接收长度
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);
}
}
}
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 = 0 , recvLength = 0 ; // 实际发送和接收长度
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 == 0 )
{
Write( " 读取不到数据! " );
CloseSocket(clientSocket);
return ;
}
#endregion
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 == 0 )
{
Write( " 读取不到数据! " );
CloseSocket(clientSocket);
return ;
}
#endregion
Run函数分解:ReadMessage函数
ReadMessage函数
ReadMessage函数分解:GetUrl
GetUrl函数
ReadMessage函数分解:Filter
Filter函数
private
bool
Filter(
string
url)
{
switch (url.ToLower())
{
case " fffocus.cn " :
return true ;
}
return false ;
}
{
switch (url.ToLower())
{
case " fffocus.cn " :
return true ;
}
return false ;
}
Run函数分解:CloseSocket函数
CloseSocket函数
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
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, 0 , qqOkData.Length, 0 );
}
else // 正常网页,直接转发
{
IPsocket.Send(sendBytes, 0 );
}
{
byte [] qqOkData = QQokProxyData();
clientSocket.Send(qqOkData, 0 , qqOkData.Length, 0 );
}
else // 正常网页,直接转发
{
IPsocket.Send(sendBytes, 0 );
}
函数分解:QQokProxyData
private
byte
[] QQokProxyData()
{
string data = " HTTP/1.0 200 Connection established " ; // 返回建立成功";
return System.Text.Encoding.ASCII.GetBytes(data);
}
{
string data = " HTTP/1.0 200 Connection established " ; // 返回建立成功";
return System.Text.Encoding.ASCII.GetBytes(data);
}
D:针对QQ需要进行重复来回的发送与接收
QQ转发处理
E:结束请求,关闭客户端Socket
#region
结束请求,关闭客户端Socket
Write( " 接收完成。返回客户端数据... " + count);
CloseSocket(IPsocket);
CloseSocket(clientSocket);
recvBytes = null ;
Write( " 本次请求完成,已关闭连接... " );
Write( " -----------------------------请求结束--------------------------- " );
#endregion
Write( " 接收完成。返回客户端数据... " + count);
CloseSocket(IPsocket);
CloseSocket(clientSocket);
recvBytes = null ;
Write( " 本次请求完成,已关闭连接... " );
Write( " -----------------------------请求结束--------------------------- " );
#endregion
结言:
本QQ代理软件在服务器上运行长达三个多月,使用过程未发现异常退出情况。当然前提就我一个人在用了
~
哈哈
~
附以前写的几篇文章:
看本篇的时候也请支持一下我的开源框架:CYQ.Data 轻量数据层之路 框架开源系列 索引
版权声明:本文原创发表于博客园,作者为路过秋天,原文链接:
http://www.cnblogs.com/cyq1162/archive/2010/09/21/1832329.html