前言:
有些公司不让员工上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 = 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
Run函数分解:ReadMessage函数
ReadMessage函数
ReadMessage函数分解:GetUrl
GetUrl函数
ReadMessage函数分解:Filter
Filter函数 private bool Filter( string url) { 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
C:QQ代理测试及网页转发
if (isConnect) // QQ链接方式 { 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); }
D:针对QQ需要进行重复来回的发送与接收
QQ转发处理
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
相关资源:敏捷开发V1.0.pptx