前言

  • 前段时间写了一个爬虫,用来收集资源,但是遇到了一个问题,也即是目标网站会通过每个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. TortoiseGit 常见问题汇总

    1.test分支修改后合并到master分支 1)切换本地分支到master分支 2)TortoiseGit --->  merge,选择远程分支test 提交到远程分支master 2.将远程 ...

  2. TienChin 项目改造完善&项目结构分析

    项目改造完善 更改 Banner Banner 生成网站:https://bootschool.net/ascii 更改启动类中的 Banner !> 如果不生效,需要重新编译一下项目工程(出现 ...

  3. 超级AI助手:全新提升!中文NLP训练框架,快速上手,海量训练数据

    "超级AI助手:全新提升!中文NLP训练框架,快速上手,海量训练数据,ChatGLM-v2.中文Bloom.Dolly_v2_3b助您实现更智能的应用!" 1.简介 目标:基于py ...

  4. C# 语言程序设计笔记

    C#是一种最新的.面向对象的编程语言.它使得程序员可以快速地编写各种基于Microsoft .NET平台的应用程序,Microsoft .NET提供了一系列的工具和服务来最大程度地开发利用计算与通讯领 ...

  5. iOS 屏幕旋转的设置方法

    VC上屏幕旋转的方式有2种 1.因重力导致的屏幕旋转 条件:shouldAutorotate返回true,设备开启了屏幕旋转开关. 设备发生重力旋转. 2.单页面强制旋转 条件:无. 设置设备旋转方向 ...

  6. 官方实锤!AMD真的已经有了大小核:不搞Intel那一套

    Intel 12代酷睿开始引入大小核混合架构,多核跑分提升立竿见影,在游戏.渲染等场景中也有很好的辅助作用,但因为大核心.小核心基于完全不同的架构,需要复杂的系统.软件调度配合,也直接导致失去了AVX ...

  7. Proxmox 7.4 使用vgpu_unlock,为GTX1060开启vGPU支持

    本文在 2021年发布的博客<Proxmox 5.4使用vgpu_unlock,为GTX1060开启vGPU支持>,介绍了 Proxmox VE 5.4 上部署vGPU unlock 的操 ...

  8. 小知识:RMAN基于某个具体时间点的恢复示例

    最近帮忙基于某个时间点恢复一个库,说是备份和归档是全的. 好多年没做过这类事情了,不过这算是最基本的DBA技能,下面给出RMAN基于某个具体时间点的恢复示例脚本: run{ allocate chan ...

  9. 移位寄存器的设计(VHDL)及testbench的编写

    移位寄存器是一种常用的存储元件,此处由D触发器构成,如下图所示. 当时钟边沿到来时,存储在移位寄存器的数据朝一个方向移动一个BIT位. 移位寄存器的功能主要为:串并转换,并串转换和同步延迟. vhdl ...

  10. CF1795

    A 先判断初始行不行,再模拟加入. B 题意:数轴上给定一些线段,和点 \(t\).问能否删去一些线段,使得 \(t\) 变成唯一的覆盖次数最多的点. 差分 + 贪心. C 有 \(n\) 杯水,\( ...