前言

  • 前段时间写了一个爬虫,用来收集资源,但是遇到了一个问题,也即是目标网站会通过每个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. 可持久化非确定状态AC自动分块维护线段平衡仙人掌优化最小费用最大流预处理混合图上莫比乌斯反演莫队带花舞蹈链并查集树状数组套主席树预处理动态DP分治FFT求多项式逆元对数函数的指数函数用可持久化并查集合并最小费用循环流上插头DP

    P8946 - The Lost Symbol 这种类型的 dp 的特点就是大部分转移形如 \(f(i,j)\rightarrow f(i+1,j+1)\) 之类的,并且当以上转移出现时原数组被清空, ...

  2. echarts中x轴文字太长换行的几种方式

    我们在使用echarts中,可能会遇见文字太长.导致显示不完全. 我们可以使用换行来处理 第一方式直接使用 \n 文字直接换行显示 使用\n <!DOCTYPE html> <htm ...

  3. gin启动https支持

    gin是一个使用Go语言开发的Web框架,具有运行速度快,分组的路由器,良好的崩溃捕获和错误处理,支持中间件等. 在工作中有时候需要支持https服务,gin可以通过中间件的方式来提供对https的支 ...

  4. Leetcode 面试题22. 链表中倒数第k个节点 Java语言求解

    题目链接 https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/ 题目内容 输入一个链表,输出该链 ...

  5. 新建立git分支,之后将分支合并到master上

    1.打开PowerShell 进入解决方案中的文件夹中,并列出目前远程的所有分支 命令:git branch -a 2.从远程获取最新版本到本地 命令:git fetch --all 3.使本地代码与 ...

  6. TienChin 活动管理-设置活动的默认状态

    // 设置活动未过期,相当于新增的活动,默认都是未过期的 activity.setActivityStatus(1);

  7. 阿里天池实验室简明教程以及Docker安装使用[一]

    1.天池notebook简介和使用 天池实验室是基于PAI DSW探索版开发的,PAI DSW (Data Science Workshop)是为算法开发者量身打造的云天池实验室是基于PAI DSW探 ...

  8. C++ Qt开发:TableWidget表格组件

    Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍TableWi ...

  9. Rsync+Inotify 实现数据同步

    Rsync 是UNIX及类UNIX-Like平台下一款强大的数据镜像备份软件,它不像FTP或其他文件传输服务那样需要进行全备份,Rsync 可以根据数据的变化进行差异备份,从而减少数据流量,提高工作效 ...

  10. clickhouse-备份表结构

    clickhouse导出表结构 #!/bin/bash OUTDIR=/root/backup/ clickhouse-client -q "SHOW DATABASES" > ...