前言:

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

 //接收客户端的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

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函数

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

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# 控制台程序 不显示在任务栏 只在进程中显示

看本篇的时候也请支持一下我的开源框架:CYQ.Data 轻量数据层之路 框架开源系列 索引

Http 代理工具 实战 支持网页与QQ代理相关推荐

  1. 简单实现Http代理工具--完善支持QQ代理

    昨天用上次文章里的代理,测试代理访问Web.QQ.com,发现访问不了,总是返回400错误. 于是开始测试: 1.检测请求头->去掉代理头->无效 2.用CCProxy->访问web ...

  2. 软件测试 | 常见代理工具

    1.代理工具简介 各种功能强大的代理工具在接口测试中发挥着作用,如Charles.Burpsuite.Mitmproxy等.这些代理工具可以帮助我们构造各种测试场景,以便我们更好地完成测试工作.下面的 ...

  3. 002--使用代理工具实现纵向渗透

    利用代理工具将内网的流量代理到本地进行访问,这样方便我们对内网进行纵向渗透.代理工具区分为正向代理和反向代理.正向代理就是将流量发送代理设备,由他代替本地主机去访问内网目标:一般情况下防火墙不会允许外 ...

  4. 网页爬虫使用代理IP的几种方案,爬虫如何设置代理?

    不少网络公司在进行爬虫数据业务的时候,都会选择代理IP,网页爬虫在现如今非常常见,尤其是一些大数据处理公司,都会使用爬虫的方式来进行信息的抓取,而要想进行信息的精准抓取,那就必须使用靠谱且稳定的代理I ...

  5. 【推荐阅读】最强网页视频下载工具,支持2000+站点

    软件介绍 以前也向大家推荐过视频下载工具,但是都比较单一,一款工具无法解决多个平台,而且还不能高效的批量下载!为解决大家下载视频的难题,今天就和大家分享一个超级强大的万能视频下载器,它几乎支持所有网站 ...

  6. 使用Charles代理工具,导致浏览器无法打开网页

    很多开发者都需要使用代理工具来调试接口,查看数据等等,但是有时候发现打开代理工具之后,代理工具同时也拦截了电脑的所有网络请求,导致电脑访问网站时提示(您的连接不是私密连接)... 造成这种问题的原因就 ...

  7. 别用XShell了,这款SSH工具绝对惊艳,还支持网页版...

    后端程序员,ssh工具几乎是每天都会用到的工具,之前给大家推荐过多款好用的ssh工具:其中有一款工具叫Tabby,因为其支持网页版的,使得年初春节期间,和他还发生了一段小小的故事: 程序员平常虽说放假 ...

  8. Windows截图工具,QQ截图独立版,QQ截图独立运行版,不需要登录QQ,体积小巧,独立运行的高效截图工具,支持截图文字识别和截图搜索,支持截图涂鸦和标记

    QQ自带的截图功能真的很强大,而且非常方便,包含了多种实用的功能,可以在截图上进行标记,可以截图进行文字提取等.现在有人把这个功能从QQ上分离出来了,在没有网络不登录QQ的情况下也可以使用这个截图工具 ...

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

    前言 我们之前的爬虫都是模拟成浏览器后直接爬取,并没有动态设置IP代理以及UserAgent标识,这样很容易被服务器封IP,因此需要设置IP代理,但又不想花钱买,网上有免费IP代理,但大多都数都是不可 ...

最新文章

  1. conda 和 pip 安装本地包
  2. 6.4高级查询:分组查询 链接查询 子查询 联合查询
  3. dp_c_区间dp_g
  4. SVM学习(三):线性分类器的求解
  5. 如何用Python进行数据探索,探索竞赛优胜方案?
  6. C语言 用传统流程图表示分段函数,C语言程序设计习题答案
  7. 如何启用“锁定内存页”选项 (Windows)
  8. python中response对象的属性_关于python:AttributeError:’HTTPResponse’对象没有属性’split’...
  9. 7.Kong入门与实战 基于Nginx和OpenResty的云原生微服务网关 --- 日志收集与分析
  10. python 自动交易_Python自动化交易入门
  11. Vmware vcenter未授权任意文件上传(CVE-2021-21972)复现
  12. 解决mysql主从 The slave IO thread stops because the master has @@GLOBAL.GTID_MODE OFF and this server
  13. 三阶魔方与四阶魔方总结
  14. 23种设计模式都适用于哪些场景?
  15. SQL语句把一个表中的a字段的值赋值到另一个字段b
  16. Excel 阅读模式 高亮标记 聚光灯效果 “完美“解决方案
  17. 无线测温装置在变压器中的设计与应用
  18. JAVA图形面积与周长(抽象类)
  19. python取得两个文件的交集、并集和差集。
  20. 软路由的正确组网姿势(上篇)

热门文章

  1. linux内存与扇区,磁盘的基础知识——扇区、柱面、磁道、族
  2. 如何运行vue项目(详细步骤)
  3. 判断两个区间有无交集
  4. oracle冲账语句_ORA-00xx问题 -oracle卸载不成功
  5. zblogphp 广告联盟_天兴工作室:广告位大全插件(网站各种广告位集合效果)
  6. 浪潮之巅第十三章 — 高科技公司的摇篮:斯坦福大学
  7. python异常常见处理
  8. postgresql 密码修改,忘记密码进行修改重置
  9. 2019最新《传智教育黑马java项目实战》
  10. Armadillo | 复数小记