前言:

有些公司不让员工上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函数


 //接收客户端的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, 0);                Write("收到原始请求数据:" + readByte.Length);                string header = Encoding.ASCII.GetString(readByte);                host = GetUrl(header, ref port);                if (Filter(host))                {                    Write("系统过滤:" + host);                    return 0;                }                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));                return bytes;            }            catch            {                System.Threading.Thread.Sleep(300);                return 0;            }        }

ReadMessage函数分解: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(0, 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函数


        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, 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需要进行重复来回的发送与接收


          #region QQ发送/接收中转请求             int length = 0, count = 0;            if (isConnect)            {                System.Threading.Thread.Sleep(400);//关键时延                //循环发送客户端请求,接收服务器返回                DateTime start = 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(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# 控制台程序 不显示在任务栏 只在进程中显示

Http 代理工具 实战 支持网页与QQ代理的更多相关文章

  1. 跨平台web调试代理工具---whistle

    whistle是基于Node实现的跨平台web调试代理工具,支持windows.mac.linux等所有安装了Node的操作系统,可以部署在本地机器.虚拟机或远程服务器,并通过本地网页查看或修改HTT ...

  2. 免费IP代理池定时维护,封装通用爬虫工具类每次随机更新IP代理池跟UserAgent池,并制作简易流量爬虫

    前言 我们之前的爬虫都是模拟成浏览器后直接爬取,并没有动态设置IP代理以及UserAgent标识,本文记录免费IP代理池定时维护,封装通用爬虫工具类每次随机更新IP代理池跟UserAgent池,并制作 ...

  3. 内网代理工具--reGeorg

    一.简介 reGeorg是reDuh的继承者,利用了会话层的socks5协议,效率更高结合Proxifier使用 Proxifier是一款功能非常强大的socks5客户端,可以让不支持通过代理服务器工 ...

  4. 【转】fiddler-http协议调试代理工具

    题目有一些激进.但是在前端界打滚了这么多年,fiddler一直都是陪着我走过来了.它就是一个抓包神奇,代理神器.它的厉害之处,我简单地说一下,希望你们看了以后,能点上32个赞. 1.fiddler为何 ...

  5. Atitit 项目管理(5)----------后勤管理与工具链支持管理

    Atitit 项目管理(5)----------后勤管理与工具链支持管理 1.1. keyword1 1.2. 15个辅助软件1 1.3. 公共模块管理(100个即可)2 1.4. 第三方类库表2 1 ...

  6. 爬虫 Http请求,urllib2获取数据,第三方库requests获取数据,BeautifulSoup处理数据,使用Chrome浏览器开发者工具显示检查网页源代码,json模块的dumps,loads,dump,load方法介绍

    爬虫 Http请求,urllib2获取数据,第三方库requests获取数据,BeautifulSoup处理数据,使用Chrome浏览器开发者工具显示检查网页源代码,json模块的dumps,load ...

  7. 代理工具Charles使用

    代理工具Charles使用 分类: MAC 2014-03-27 20:41 7810人阅读 评论(2) 收藏 举报 手机开发 一.跟踪HTTPS 1.下载官方的证书ssl.zip证书,解压成*.cr ...

  8. 性能测试专题:Locust工具实战之“蝗虫”降世

    阅读全文需5分钟. 1. 前言 在上一篇文章中,我们已经为大家介绍了什么是Locust,具体可参照:性能专题:Locust工具实战之开篇哲学三问,简单来说,Locust 是基于 Python 语言下的 ...

  9. http代理工具delphi源码

    http://www.caihongnet.com/content/xingyexinwen/2013/0721/730.html http代理工具delphi源码 以下代码在 DELPHI7+IND ...

  10. web调试代理工具Whistle

    由于最近在学习微信小程序开发,项目中用到了https代理请求,所以用到了基于Node实现的跨平台web调试代理工具Whistle,在此做一记录. 完成https代理请求总共需要5个步骤. 一.安装No ...

随机推荐

  1. Luogu P3007 奶牛议会

    观前须知 本题解使用 CC BY-NC-SA 4.0 许可. 同步发布于 Luogu 题解区. 更好的观看体验 请点这里. 笔者的博客主页 正文 Luogu P3007 [USACO11JAN] Th ...

  2. CTFshow Reverse 逆向4 学习记录

    题目 分析过程 是一个无壳,64位的文件 丢到IDA里面,找到main函数 1 int __cdecl __noreturn main(int argc, const char **argv, con ...

  3. mysql 必知必会整理—sql 排序与过滤[三]

    前言 简单整理一下MySQL的排序与过滤. 正文 我们查询出来的结果有时候是希望进行排序的,比如说: select product_name from products order by prod_n ...

  4. mysql 必知必会整理——mysql 介绍[一]

    前言 对mysql 进行简介. 正文 mysql 是一种数据库,那么什么是数据库呢? 数据库是一个以某种有组织的方式存储的数据集合. 也就是说数据有某种组织规律的就叫做数据库. 数据库(databas ...

  5. 力扣636(java)-函数的独占时间(中等)

    题目: 有一个 单线程 CPU 正在运行一个含有 n 道函数的程序.每道函数都有一个位于  0 和 n-1 之间的唯一标识符. 函数调用 存储在一个 调用栈 上 :当一个函数调用开始时,它的标识符将会 ...

  6. 力扣150(java)-逆波兰表达式求值(中等)

    题目: 根据 逆波兰表示法,求表达式的值. 有效的算符包括 +.-.*./ .每个运算对象可以是整数,也可以是另一个逆波兰表达式. 注意 两个整数之间的除法只保留整数部分. 可以保证给定的逆波兰表达式 ...

  7. EasyNLP集成K-BERT算法,借助知识图谱实现更优Finetune

    导读 知识图谱(Knowledge Graph)的概念⾸次出现2012年,由Google提出,它作为⼀种⼤规模语义⽹络, 准确地描述了实体以及实体之间的关系.知识图谱最早应⽤于搜索引擎,⽤于准备返回⽤ ...

  8. 服务网格 ASM 年终总结:最终用户如何使用服务网格?

    ​简介:本文不打算回顾 Istio 或是阿里云服务网格 ASM 的变化或趋势,我们来聊一聊阿里云 ASM 服务网格,它的最终用户是如何使用服务网格的. 作者:叶剑宏 背景 阿里云服务网格 ASM 于 ...

  9. 双11特刊|购物车实时显示到手价,看云原生内存数据库Tair如何提升用户体验?

    ​阿里云自研内存数据库Tair诞生于2009年,是一种支持高并发低延迟访问的云原生内存数据库,完全兼容Redis,已历经多年双11大促考验,提供核心在线访问加速能力,显著提升系统吞吐量. 作为双11大 ...

  10. Inclavare Containers:云原生机密计算的未来

    ​简介:本文为你详细的梳理一次 Inclavare Containers 项目的发展脉络,解读它的核心思想和创新技术. ​ 作为业界首个面向机密计算场景的开源容器运行时,Inclavare Conta ...