前言:

有些公司不让员工上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. 为你推荐一款高效的IO组件——okio

    原文:https://mp.weixin.qq.com/s/XnNhSq8ESoslb2DQEzMbCQ,点击链接查看更多技术内容.   前不久,三方组件库上新了一批JS/eTS组件,其中就包括oki ...

  2. docker 应用篇————dockerfile[十四]

    前言 简单介绍一下dockerfile. 正文 dockerfile就是docker image的构建文件. 然后来运行一下. 然后就产生了test:1.0 这个镜像. 然后启动一下你就发现了这个镜像 ...

  3. node excel采集数据

    前言 个人写过无数的脚本,但是一直没有整理,后续整理脚本. 需求: 生成一堆激活码. 业务: 需要拿到一个token, 然后调用某个api获取激活码. 正文 思路: 1.http请求 axios 2. ...

  4. argparse命令行参数的使用

    import argparse def main(): #设置一些参数 parser = argparse.ArgumentParser() parser.add_argument('--device ...

  5. js 连接数据库 提示:ActiveXObject is not defined

    ActiveXObject is not defined 最近比较闲,上班瞎捣鼓一下,没想到报错了,提示ActiveXObject is not defined 大概是在js连接数据库时new对象使用 ...

  6. [FAQ] Member "address" not found or not visible after argument-dependent lookup in address payable.

    顾名思义,address 属性不存在,请检查调用方. 比如:msg.sender.address 会有此提示,在 Solidity Contract 中,msg.sender.balance 是存在的 ...

  7. 探索 WPF 的 ITabletManager.GetTabletCount 在 Win11 系统的底层实现

    本文将和大家介绍专为 WPF 触摸模块提供的 ITabletManager 的 GetTabletCount 方法在 Windows 11 系统的底层实现 本文属于 WPF 触摸相关系列博客,偏系统底 ...

  8. WPF 将控件放入到 UserControl 里获取 HwndSource 为空的情况

    本文记录将 WPF 控件放入到 UserControl 里,如果此 UserControl 没有被设置 Visibility 为可见过,那么放在此 UserControl 内的控件将获取不到 Hwnd ...

  9. SQL server 表字段扩展设计

    一.扩展字段表 一个表的字段可能并非一成不变,系统的运行.需求的变化等客观条件可能会需要增加其他字段,如何在不直接修改表设计的前提下满足需求呢?该扩展字段表的思想就是将列设计转化为行设计,字段的增加表 ...

  10. 005_Orcad里创建Homogeneous分裂元件

    005_Orcad里创建Homogeneous分裂元件 两种类型Homogeneous和Hetergeneous的区别,都是用来把一个复杂的元件分成多个部分来画,不同的是homogeneous画的每部 ...