前言:

有些公司不让员工上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. Docker之离线安装和在线安装

    一.离线安装 1.软件包下载 https://download.docker.com/linux/static/stable/x86_64/ 2.安装docker tar xvf /opt/docke ...

  2. 重新点亮linux 命令树————网络管理和网络配置文件[十一六]

    前言 简单整理一下网络管理和网络配置文件. 正文 网络服务程序分为两种:分别是SysV和systemd service network start|stop|restart chkconfig --l ...

  3. Web前端 - Vue

    <!-- id标识vue作用的范围 --> <div id="app"> <!-- {{}} 插值表达式,绑定vue中的data数据 --> { ...

  4. 【SQL】IN和EXISTS谁的效率更高

    [SQL]IN和EXISTS谁的效率更高 总结: 索引设置好的情况下 子查询数据量大的,用exists 子查询数据量小的,用in 原文连接:https://zhuanlan.zhihu.com/p/4 ...

  5. 单元测试必备:Asp.Net Core代码覆盖率实战,打造可靠应用 !

    引言 在前几章我们深度讲解了单元测试和集成测试的基础知识,这一章我们来讲解一下代码覆盖率,代码覆盖率是单元测试运行的度量值,覆盖率通常以百分比表示,用于衡量代码被测试覆盖的程度,帮助开发人员评估测试用 ...

  6. 力扣367(java&python)-有效的完全平方数(简单)

    题目: 给定一个 正整数 num ,编写一个函数,如果 num 是一个完全平方数,则返回 true ,否则返回 false . 进阶:不要 使用任何内置的库函数,如  sqrt . 示例 1: 输入: ...

  7. 开源小白到核心开发——我与 sealer 的成长故事

    简介: 下面将以作者本人与 sealer 的一段成长故事来带领大家体验从小白到核心功能开发者的开源之旅,同时本文也作为一篇引领开源小白入门的文章供大家参考. 作者:周欣元 个人简介   大家好,我是周 ...

  8. PolarDB-X拆分键推荐

    简介: PolarDB-X 2.0提供了透明分布式的能力,默认进行主键的哈希拆分,让用户无感知的从单机数据库迁移到分布式数据库.拆分键的选择是学术界和工业界研究已久的问题,一个重要选型是tp优先还是a ...

  9. 业界首个机密计算容器运行时—Inclavare Containers正式进入CNCF!

    ​简介: Inclavare Containers 通过云原生计算基金会(CNCF)TOC 投票正式成为 CNCF 官方沙箱项目. 作者|彦荣 ​ 2021 年 9月 15 日,Inclavare C ...

  10. linux 下jq的使用

    安装: yum install jq -y 文档: https://stedolan.github.io/jq/manual/ 更多: https://blog.csdn.net/Cheat11730 ...