前言

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

      注意点 1.SqlSugar Code First可以快速开发,使用起来也要分阶段使用,比如早期随便搞,中后期需要禁用一些功能保证数据安全(标题6和7 ) 2.数据库账号需要有比较高的权限, 3. ...

  2. ChatGenTitle:使用百万arXiv论文信息在LLaMA模型上进行微调的论文题目生成模型

    ChatGenTitle:使用百万arXiv论文信息在LLaMA模型上进行微调的论文题目生成模型 相关信息 1.训练数据集在Cornell-University/arxiv,可以直接使用: 2.正式发 ...

  3. 11.1 C++ STL 应用字典与列表

    C++ STL 标准模板库提供了丰富的容器和算法,这些模板可以灵活组合使用,以满足不同场景下的需求.本章内容将对前面学习的知识进行总结,并重点讲解如何灵活使用STL中的vector和map容器,以及如 ...

  4. 6.0 Python 使用函数装饰器

    装饰器可以使函数执行前和执行后分别执行其他的附加功能,这种在代码运行期间动态增加功能的方式,称之为"装饰器"(Decorator),装饰器的功能非常强大,装饰器一般接受一个函数对象 ...

  5. 基于volcano实现节点真实负载感知调度

    本文分享自华为云社区<基于volcano实现节点真实负载感知调度>,作者: 可以交个朋友. 背景 默认调度器调度器视某个节点的空闲可调度资源=节点可分配资源 - SUM(节点上已调度Pod ...

  6. React核心概念与JSX

    React概况 React是一个只用来写HTML的UI页面的JS库,在MVC设计模式中它只相当于View,故:它并不是一个框架(MVC架构角色设计). React组件内数据改动会自动更新到屏幕上. R ...

  7. 技嘉水雕II 360水冷散热器评测:稳压340W i9-14900K

    一.前言:极简卡扣连锁风扇设计 再多风扇也只需2根线 如今这个年代,DIY主机几乎都会配大量的RGB风扇,然而"光污染"虽然带来了视觉感官享受,在理线方面却非常繁琐. 就拿360水 ...

  8. 从零搭建Vue3 + Typescript + Pinia + Vite + Tailwind CSS + Element Plus开发脚手架

    项目代码以上传至码云,项目地址:https://gitee.com/breezefaith/vue-ts-scaffold 目录 前言 脚手架技术栈简介 vue3 TypeScript Pinia T ...

  9. (Python)每日代码||2024.1.17||函数中给列表形参默认值时,该默认列表在函数中的改变会保留下来

    def f(x,li=[1]): print(id(li)) li.append(x) print(li) f('a')#第一次调用函数 print() f('b')#第二次调用函数 print() ...

  10. Java21 + SpringBoot3集成七牛云对象存储OSS,实现文件上传

    目录 前言 实现步骤 引入maven依赖 修改配置文件 创建七牛云配置类 创建文件操作服务类 创建文件操作控制器 前端实现 运行效果 总结 前言 近日心血来潮想做一个开源项目,目标是做一款可以适配多端 ...