前言

  • 前段时间写了一个爬虫,用来收集资源,但是遇到了一个问题,也即是目标网站会通过每个IP每秒请求次数来禁止ip,这样的话,就限制了速度。

  • 那么,我的解决方案就是传统的方法,使用代理,但是我哪里有那么多代理呢?此时通过百度就能找到一大堆的免费代理。经过测试,这些代理1000个里面能用的估计就30多个,但是似乎已经很好了是吗?

  • 问题还是有的,他们不稳定而且速度太慢了。

  • 所以,我就想到了以前我反向代理学校内网免费使用知网的套路。那时候我是这么做的:

  • 在内网的电脑上安装CProxy软件,设置代理端口是808

  • 然后通过frp软件将808端口转发到我服务器的7000 端口,那么我只需要将我的笔记本代理设置成服务器的7000端口就可以了。

  • 现在,如果我能写一个软件,能够实现上面两个软件的作用,那就太棒了。我只要把一个程序发给我的朋友,让他打开,然后我就可以借用他的IP作为代理了!

考虑到如果我让人帮忙的话,肯定麻烦别人越少越好,所以客户端使用了纯C/C++开发,体积最小。

而服务端因为我有连个服务器,一个windows,一个linux,似乎有跨平台需求,所以选用了Python来做(Python代码是真的爽呀)。

代理原理

代理简单的来说就是流量转发,从大的角度来说是没有问题的,但是,细究的话还是会有协议的问题的,下面将会简短的说明一下两个代理方式 http和https代理。

http代理

​ 这种代理方式比较简单,首先一个普通的http请求是下面这样的来源

  • 注意看,POST后面的路径是不带主机名的

  • 但是,看下面对代理请求的请求头,就能看到是带了主机名的

所以,对于http流量代理,初步来看,只是需要将浏览器或者程序发出的http头重写一下,将主机部分去掉,再无脑转发即可。

https代理

对于https代理,就稍微麻烦一些(其实更简单了),虽然https流量是加密的的,但是我们不需要解密,只是做无脑转发,所以不涉及解密过程。https的安全性依旧是能保障的。

  • 首先,请求程序会先发出一个 CONNECT 方法的请求,表示目标服务器是哪个

  • 然后,代理服务器就应该回复,表示已经建立了一个tcp连接

    • HTTP/1.1 200 Connection established\r\n\r\n
  • 当代理程序得到可行的回复之后,就开始将https的加密数据发送给代理服务器,然后代理服务器将这些流量无脑提交给目标http服务器即可。

  • 目标https服务器的响应交给代理服务器,代理服务器再把流量给请求程序即可。之后就一直循环,直到https服务器关闭连接。

此时就会有一个问题,也就是http长连接的问题

众所周知,http是不会保持tcp连接的,但是这个说法其实是http协议1.0的情况了

对于http 1.1版本,默认请求头是 connection选项的值是keep-alive,会保持一段时间的tcp连接,具体时常由max-age选项决定。

问题就在于一个请求结束之后,并不会立马断开,此时依旧占用连接。所以,要么修改请求头中的connecion的值为close,要么主动断开与服务器的连接。

实现

实现的功能是这样的

整体分为客户端和服务端,我将会在服务器上运行服务端,它会监听7201端口

然后将客户端分发给闲置的电脑,注意,根据设想,这里会有多个客户端,都连接上7201端口,并且将自己认证为客户端

服务端接收到多个连接之后,对每个客户端都开放监听一个端口,依次是7202、7203

这样,我要使用他们的时候,先请求7201端口,获取一下可用主机,只要请求服务器的7202端口就好了

客户端

这次开发的客户端支持两种模式,也即是 正向代理反向代理

  • 正向代理

对于正向代理,只需要打开一个监听端口,然后等待浏览器或者请求程序连接即可,然后根据两个代理协议,分别处理就好了

  • 反向代理

反向代理是这次的核心

首先,需要指定服务器的ip和工作端口,然后连接上服务器

之后,对服务器发送过来的请求依次转发给代理服务器即可

服务端

我一直觉得服务端的开发应该不难的才对,毕竟只是一个流量转发,结果后来才发现,没有我想的那么简单。

整个过程其实不太顺利,重写了一遍,现在这个版本依旧有bug,不满意,准备重构。

遇到的所有问题记录

Python对于回复不响应

  • 刚遇到这个问题的时候,着实吓了一跳,然后通过抓包,才注意到最后还有 \r\n\r\n(两个,我只有一个)

  • 此时就正常了

接受的数据只有4字节

  • 通过C++接收到了数据,输出的时候只输出一点,通过strlen函数得到的长度只有4,诧异了一会儿。

  • 通过抓包发现数据是发了过来的

  • 确实是接收到了,但是因为00的关系,输出被截断了

因为在C/C++里面 一个字符串的结束用\0表示,所以会出现这种情况,由上图能看出 bytes变量值是正常的。

最终数据已经发给Python了 但是Python还是阻塞状态

可能是因为,先传输了证书,然后还有一段信息 参考https://imququ.com/post/web-proxy.html

  • 由上面跟踪的数据流能看出,除了最开始数据,还有后面几个不同的数据段。猜测最上面的是证书部分,然后是hello响应,最终从https://imququ.com/post/web-proxy.html这里证实了我的想法

子线程中recv阻塞,卡死

对于每个请求都会开一个线程来转发数据,分别有两个转发,从客户端转发到代理请求,从代理请求转发到客户端。那么,其中就会遇到一个问题:当连接请求端的请求断开之后,中转服务器与客户端的连接没有断开,那么新的请求来了之后,旧的线程会先接收到客户端发来的信息,但是这个线程与代理请求已经断开了,就没办法发送,此时会异常。与此同时新的线程并没有接收到数据,也就无从转发

几种不完美的解决方案

  • 与代理请求通讯的套接字设为全局

    • 这样就不能同时实现多个请求同时处理了
  • 每次重连

    • 这样不能保证每次都能是同一个端口
  • 杀死线程

    • 太暴力了,会导致数据不安全,并且杀死线程不是简单的事情

还有几种尝试过但失败的方法

  • 为套接字设置超时时间

    • 虽然可以终止线程,但是太慢了
  • 使用结束标志
    • 当进程中recv结束阻塞的时候,正是他已经接受了数据之后。。。

因为中间只有一个通道,所以,想要完成多线程同时转发还需要额外的设计

可以预见,将会对每个请求标记一个id,以防止流量混乱的问题,目前版本仅能实现正向代理,以及请求速度不高的反向代理。。。

重构!!!!!

额外的想法

  • 我想研究一下frp这个软件的通信协议,这样我就能直接使用他的流量转发功能,而不用自己再运行一个服务端了!

源码: https://gitee.com/EasyWord/rProxy

参考: https://www.cnblogs.com/airoot/p/7851227.html

这个小项目对我帮助巨大,虽然这个只能在linux上跑,但是一些代码设计方法真的是学到了,不过其中用到了大量的全局变量,我感觉不利于代码复用。

[程序] C++实现 http和https的反向代理程序的更多相关文章

  1. 简单的php基于curl的反向代理程序

    起因: 经理:需要实现一个反向代理? 我:  简单,nginx分分钟配置好. 经理:嗯?没有nginx? 我: nodejs也行啊,网上有例子分分钟搞定. 经理:嗯?只有虚拟主机,只能上传php程序? ...

  2. Asp反向代理程序,调用远程站点全站数据,一款脚本级反向代理程序.

    前些天临时写的一脚本级反向代理程序,用法很简单,设置好目标站地址,然后放到你网站根目录:index.asp,再将404页面自定义为:index.asp,即可. 由于暂时没有 url 替换需要,所以没有 ...

  3. NC 使用Nginx实现https的反向代理

    summary: [通过Nginx实现NCC的https访问,并解决UClient应用的问题] 1 概述 通过Nginx 安装配置反向代理,实现NC.NCC的https访问. 本文以NCC2005为例 ...

  4. nginx通过https方式反向代理多实例tomcat

    案例说明:前面一层nginx+Keepalived部署的LB,后端两台web服务器部署了多实例的tomcat,通过https方式部署nginx反向代理tomcat请求.配置一如下: 1)LB层的ngi ...

  5. nginx证书制作以及配置https并设置访问http自动跳转https(反向代理转发jboss)

    nginx证书制作以及配置https并设置访问http自动跳转https 默认情况下ssl模块并未被安装,如果要使用该模块则需要在编译时指定–with-http_ssl_module参数,安装模块依赖 ...

  6. NGINX之——配置HTTPS加密反向代理訪问–自签CA

    转载请注明出处:http://blog.csdn.net/l1028386804/article/details/46695495 出于公司内部訪问考虑,採用的CA是本机Openssl自签名生成的,因 ...

  7. Nginx中配置http和https做反向代理

    参考:http://www.zslin.com/web/article/detail/73 1.安装 sudo apt-get install nginx 2.配置: http_demo.conf # ...

  8. docker使用nginx实现ssl(https)反向代理其他容器应用

    安装nginx容器 搜索nginx镜像 docker search nginx 拉取最新版nginx docker pull nginx:latest 运行容器 docker run --name=n ...

  9. Nginx设置Https反向代理,指向Docker Gitlab11.3.9 Https服务

    目录 目录 1.GitLab11.3.9的安装 2.域名在阿里云托管,申请免费的1年证书 3.Gitlab 的 https 配置 4.Nginx 配置 https,反向代理指向 Gitlab 配置 目 ...

  10. Nginx学习笔记(反向代理&搭建集群)

    一.前言 1.1 大型互联网架构演变历程 1.1.1 淘宝技术 淘宝的核心技术(国内乃至国际的 Top,这还是2011年的数据) 拥有全国最大的分布式 Hadoop 集群(云梯,2000左右节点,24 ...

随机推荐

  1. 巧用GenericObjectPool创建自定义对象池

    作者:京东物流 高圆庆 1 前言 通常一个对象创建.销毁非常耗时的时候,我们不会频繁的创建和销毁它,而是考虑复用.复用对象的一种做法就是对象池,将创建好的对象放入池中维护起来,下次再用的时候直接拿池中 ...

  2. 关于git的几点疑问

    git rename后查看之前的记录 对于某个文件进行rename之后,使用show log命令查看之前的修改记录都会丢失,通过命令行方式进行mv之后,在tortoisegit中查看记录还是丢失的 g ...

  3. github clone或访问慢

    做技术的我们经常会访问github.com,有时出现github访问非常慢或者git clone速度很慢,git push也很慢 原因很简单:github被高高的墙屏蔽了. 所以解决方案就是手动把 c ...

  4. Java多线程-ThreadPool线程池-3(五)

    除了可以通过ThreadPoolExecutor自定义线程池外,同Stream API中的Collectors一样,多线程里的Executors类也提供了一组相关的线程池工具,可以直接拿来用,不用考虑 ...

  5. .NET 云原生架构师训练营(模块二 基础巩固 EF Core 查询)--学习笔记

    2.4.5 EF Core -- 查询 关联数据加载 客户端与服务端运算 跟踪与不跟踪 复杂查询运算 原生 SQL 查询 全局查询筛选器 关联数据加载 学员和助教都在项目分组中,调整模型,删除 Ass ...

  6. Linux-grep或和与操作

    一.或(or)操作1.使用选项 -Egrep -E 'a1|a2'filename // 找出文件(filename)中包含a1或者包含a2的行 2.使用egrepegrep 'a1|a2' file ...

  7. 【译】.NET 8 网络改进(二)

    原文 | Máňa,Natalia Kondratyeva 翻译 | 郑子铭 修改 HttpClient 日志记录 自定义(甚至简单地关闭)HttpClientFactory 日志记录是长期请求的功能 ...

  8. Python树与树算法

    Python树与树算法 树的概念 树(英语:tree)是一种抽象数据类型(ADT)或是实作这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合.它是由n(n>=1)个有限节点组成一个具 ...

  9. 从零开始学正则(七:终章),详解常用正则API与你可能不知道的正则坑

     壹 ❀ 引 花了差不多半个月的晚上时间,正则入门学习也步入尾声了,当然正则的学习还将继续.不得不说学习成效非常明显,已能看懂大部分正则以及写出不太复杂的正则,比如帮组长写正则验证文件路径正确性,再如 ...

  10. NC16466 [NOIP2015]信息传递

    题目链接 题目 题目描述 有 n 个同学(编号为 1 到 n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为 i 的同学的信息传递对象是编号为Ti的同学. 游戏开始时, ...