编写了一个HTTP高匿代理
python mitmproxy用法

Python是一种十分流行的编程语言,其强大的功能和易学易用的特点使得它在软件开发、数据分析等领域越来越受到人们的青睐。
而mitmproxy是一个强大的HTTP代理工具,可以帮助开发者更好地理解和调试HTTP通信。
本文将介绍Python mitmproxy的用法,帮助读者更好地应用mitmproxy进行HTTP请求的调试和分析。
一、介绍mitmproxymitmproxy是一个用Python编写的中间人攻击代理工具,其功能非常强大。
它可以拦截HTTP通信,并对请求和响应进行实时修改和查看,帮助开发者更好地理解和调试HTTP通信。
mitmproxy还提供了一套强大的Python API,使得开发者可以通过编写Python脚本来扩展其功能,实现更多的定制化需求。
二、安装mitmproxy要使用mitmproxy,首先需要安装它。
mitmproxy可以通过pip来进行安装,命令如下:```bashpip install mitmproxy```安装完成后,可以通过命令行输入`mitmproxy`来启动mitmproxy,可以通过`mitmweb`来启动mitmproxy的Web界面。
三、基本用法1. 启动mitmproxy在命令行输入`mitmproxy`即可启动mitmproxy,开始拦截HTTP通信。
2. 查看HTTP请求和响应mitmproxy会将拦截到的HTTP通信实时显示在命令行界面上,包括请求和响应的内容、头部信息、时间等。
通过上下方向键可以快速查看历史请求和响应。
3. 修改HTTP请求和响应在mitmproxy中,可以对拦截到的HTTP请求和响应进行实时修改。
通过快捷键`e`进入编辑模式,就可以对请求和响应进行修改。
这对于调试和测试来说非常方便。
4. 导出HTTP请求和响应mitmproxy还提供了导出HTTP请求和响应的功能,可以将其保存为文件,并进行进一步的分析和处理。
四、使用Python APImitmproxy提供了一套强大的Python API,使得开发者可以通过编写Python脚本来扩展其功能,实现更多的定制化需求。
Java实现http代理服务器

Java实现http代理服务器 Java实现http代理服务器本⽂连接:gitee:默认端⼝:8888javac RuphyHttpProxy.javajava RuphyHttpProxy 11111代码如下://package me.muphy.servicce;import java.io.Closeable;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;import .ServerSocket;import .Socket;import java.util.concurrent.CountDownLatch;import java.util.concurrent.TimeUnit;import java.util.regex.Matcher;import java.util.regex.Pattern;/*** http代理*/public class RuphyHttpProxy extends Thread {private final ServerSocket server;private final int port;public RuphyHttpProxy(int port) throws IOException {this.port = port;server = new ServerSocket(port);System.out.println("代理端⼝:" + this.port);}public static void main(String[] args) throws IOException {int port = 8888;if (args != null && args.length > 0 && args[0].matches("\\d+")) {port = Integer.parseInt(args[0]);}new RuphyHttpProxy(port).start();}@Overridepublic void run() {// 线程运⾏函数while (true) {try {Socket client = server.accept();//使⽤线程处理收到的请求new HttpConnectThread(client).start();} catch (Exception e) {e.printStackTrace();}}}/*** 新连接处理线程*/private static class HttpConnectThread extends Thread {private Socket client;private Socket server = null;private String host = null;private int port = 80;private int clientReadLength = 0;byte clientInputBuffer[] = new byte[1024 * 1024 * 4];private DataInputStream clientInputStream = null; //客户端输⼊流private DataInputStream serverInputStream = null; //服务端输⼊流private DataOutputStream clientOutputStream = null; //客户端输出流private DataOutputStream serverOutputStream = null; //服务端输出流private long createTime = System.currentTimeMillis();private String clientInputString = null;public HttpConnectThread(Socket client) {this.client = client;}@Overridepublic void run() {try {clientInputStream = new DataInputStream(client.getInputStream());clientOutputStream = new DataOutputStream(client.getOutputStream());if (clientInputStream != null && clientOutputStream != null) {clientReadLength = clientInputStream.read(clientInputBuffer, 0, clientInputBuffer.length); // 从客户端读数据if (clientReadLength > 0) { // 读到数据clientInputString = new String(clientInputBuffer, 0, clientReadLength);if (clientInputString.contains("\n")) {clientInputString = clientInputString.substring(0, clientInputString.indexOf("\n"));}if (clientInputString.contains("CONNECT ")) {parseServerHost("CONNECT ([^ ]+) HTTP/");} else if (clientInputString.contains("http://") && clientInputString.contains("HTTP/")) {// 从所读数据中取域名和端⼝号parseServerHost("http://([^/]+)/");}if (host != null) {server = new Socket(host, port);// 根据读到的域名和端⼝号建⽴套接字serverInputStream = new DataInputStream(server.getInputStream());serverOutputStream = new DataOutputStream(server.getOutputStream());if (serverInputStream != null && serverOutputStream != null && server != null) {if (clientInputString.contains("CONNECT ")) {doConnect();return;}doRequest();return;}}}} catch (Exception e) {e.printStackTrace();}IOUtils.close(serverInputStream, serverOutputStream, server, clientInputStream, clientOutputStream, client);}/*** 解析主机地址** @param regExp*/private void parseServerHost(String regExp) {Pattern pattern = pile(regExp);Matcher matcher = pattern.matcher(clientInputString + "/");if (matcher.find()) {host = matcher.group(1);if (host.contains(":")) {port = Integer.parseInt(host.substring(host.indexOf(":") + 1));host = host.substring(0, host.indexOf(":"));}}}/*** 处理请求** @throws IOException*/private void doRequest() throws IOException, InterruptedException {serverOutputStream.write(clientInputBuffer, 0, clientReadLength);serverOutputStream.flush();final CountDownLatch latch;if (clientInputString.contains("POST ")) {latch = new CountDownLatch(2);// 建⽴线程 , ⽤于从内⽹读数据 , 并返回给外⽹new HttpChannel(clientInputStream, serverOutputStream, latch).start();} else {latch = new CountDownLatch(1);}// 建⽴线程 , ⽤于从外⽹读数据 , 并返回给内⽹new HttpChannel(serverInputStream, clientOutputStream, latch).start();latch.await(120, TimeUnit.SECONDS);IOUtils.close(serverInputStream, serverOutputStream, server, clientInputStream, clientOutputStream, client);System.out.println("请求地址:" + clientInputString + ",耗时:" + (System.currentTimeMillis() - createTime) + "ms"); }/*** 处理连接请求** @return*/private void doConnect() throws IOException, InterruptedException {String ack = "HTTP/1.0 200 Connection established\r\n";ack = ack + "Proxy-agent: proxy\r\n\r\n";clientOutputStream.write(ack.getBytes());clientOutputStream.flush();final CountDownLatch latch = new CountDownLatch(2);// 建⽴线程 , ⽤于从外⽹读数据 , 并返回给内⽹new HttpChannel(serverInputStream, clientOutputStream, latch).start();// 建⽴线程 , ⽤于从内⽹读数据 , 并返回给外⽹new HttpChannel(clientInputStream, serverOutputStream, latch).start();latch.await(120, TimeUnit.SECONDS);IOUtils.close(serverInputStream, serverOutputStream, server, clientInputStream, clientOutputStream, client);}}/*** 流通道处理线程*/private static class HttpChannel extends Thread {private final CountDownLatch countDownLatch;private final DataInputStream in;private final DataOutputStream out;public HttpChannel(DataInputStream in, DataOutputStream out, CountDownLatch countDownLatch) {this.in = in;this.out = out;this.countDownLatch = countDownLatch;}@Overridepublic void run() {byte buf[] = new byte[10240];try {while ((len = in.read(buf, 0, buf.length)) != -1) { out.write(buf, 0, len);out.flush();}} catch (Exception e) {e.printStackTrace();} finally {IOUtils.close(in, out);countDownLatch.countDown();}}}/*** 流⼯具类*/private static class IOUtils {/*** 关闭所有流*/private static void close(Closeable... closeables) {if (closeables != null) {for (int i = 0; i < closeables.length; i++) {if (closeables[i] != null) {try {closeables[i].close();} catch (IOException e) {e.printStackTrace();}}}}}}}。
什么是HTTP代理?爬虫如何使用HTTP代理

什么是HTTP代理?爬虫如何使用HTTP代理
如何做HTTP代理?在网站中每天都有很多的爬虫在大量的抓取信息,假如网站不设置反爬虫机制,必定导致网站压力过大无法运营,因此用各种各样的反爬虫来保护网站。
我们先来说一下HTTP代理原理:HTTP代理就是介于浏览器和web服务器之间的一台服务器,连接代理后,浏览器不再直接向web服务器取回网页,而是向代理服务器发出request信号,代理服务器再想web服务器发出请求,收到web服务器返回的数据后再反馈给浏览器。
爬虫工作者为了更好的采集信息,可以用现有的软件抓取数据或是依据目标网站编写代码。
但不论是什么方法,都离不开HTTP代理IP的支持来突破反爬虫机制。
这里以怎么HTTP 代理为例讲解一下,爬虫如何使用HTTP代理:
1、首先我们先登录账号提取IP
2、提取数量及其IP协议地区都可以自行选择
3、筛选一下IP,确保IP的连接率
由于网络上的网站对爬虫的监控越来越严,拥有代理IP池已经是爬虫用户的标配了,我们要及时更新反爬机制的对策,提高爬虫工作效率。
HTTP代理IP不仅能使我们不再怕反爬虫机制,更能隐藏IP地址,避免受到网络攻击,提高安全性。
http代理原理

http代理原理
HTTP代理是一种通信转发的技术,在网络通信中充当了中间
人的角色。
它通过接收客户端的请求,然后转发请求至服务器,并将服务器的响应再转发给客户端。
代理服务器的存在使得客户端与服务器之间的通信变得间接而不是直接的。
当客户端向代理发送请求时,客户端首先要将请求目标的
URL发送给代理服务器,并告知代理要访问的资源。
代理服
务器接收到请求后,会对请求进行解析和检查,然后决定是否允许该请求通过。
如果代理服务器允许请求通过,它会向请求目标发送一个新的请求,将客户端的请求作为自己的请求发送出去。
在接收到服务器的响应后,代理服务器再将响应转发给客户端。
代理服务器有能力修改响应内容,从而实现一些功能,比如缓存、数据压缩等。
代理服务器还可以对响应进行过滤和修改,以增强网络安全性,比如过滤不良内容或者添加额外的安全头部。
HTTP代理的工作原理还包括一些其他的技术,比如连接的保持、数据的压缩、SSL加密等。
这些技术都是为了提高代理服务器的性能和安全性。
总结来说,HTTP代理是一种将客户端与服务器之间的通信转
发的技术。
它通过接收客户端请求并将其转发给服务器,再将服务器的响应转发给客户端,实现了在网络通信中的中间代理
功能。
HTTP代理的工作原理还包括其他一些技术,以提高性能和安全性。
使用HTTP代理方法 代理使用方法

使用HTTP代理方法1.IE5.0以上版本中设置代理:菜单栏“工具”->下拉菜单“Internet选项”->选项卡“连接”->在“局域网设置”->在中间的“代理服务器”栏选中“使用代理服务器”->在“地址” 和“端口”栏输入本站提供的HTTP代理服务器->确定。
查看图示2.Maxthon(遨游)中设置代理服务器:菜单栏“选项”——》“代理服务器”——》“管理代理服务器列表”——》”添加”——》在输入框中输入标准格式的代理服务器,如XXX.XXX.XXX.XXX:端口,然后“确定”并退出,继续,菜单栏“选项”——》“代理服务器”——》然后选择刚才输入的代理服务器查看图示3.腾讯浏览器(TT浏览器)中设置代理服务器:菜单栏“工具”——》“代理服务器”——》“设置代理”——》在代理设置对话框中,点击“添加”——》在代理设置区中,输入代理,然后“确定”并退出,继续,菜单栏“工具”——》“代理服务器”——》然后选择刚才输入的代理服务器查看图示4.Google Chrome(谷歌浏览器)中设置代理服务器:菜单栏“选项”——》“选项”——》“更改代理设置”——》“局域网设置”——》在中间的“代理服务器”栏选中“使用代理服务器”在“地址” 和“端口”栏输入本站提供的HTTP代理服务器->确定查看图示FTP软件中Socks代理使用方法在FTP和P2P软件中我们可以使用SOCKS4/SOCKS5代理服务器,常见的软件的代理设置方法如下:1.迅雷/BT/Emule电驴/PPlive/PPS等软件中设置代理:菜单栏“选项”——》参数设置——》代理,然后在“代理服务器”项中选择代理类型,填写代理2.FlashFXP3.0以后版本中设置代理:菜单栏“选项”——》参数设置——》连接,然后在“代理服务器”项中选择代理类型,填写代理3.CuteFTP XP 5.0.2 中文版中设置代理:菜单栏“编辑”——》设置——》连接——》SOCKS--》选择代理类型,如SOCKS4或者SOCKS5,并填写代理4.LeapFtp中设置代理:菜单栏“选项”——》参数设置——》常规——》代理,将“使用代理”前面的方框钩上,然后填写代理,并将下面的SOCKS防火墙钩上代理的安全性与法律问题代理服务器除了网络服务商为了各种目的而开设外,大部分是新建网络服务器设置的疏漏!虽然法律尚无具体规定,但没有经过允许而使用他人的服务器当然还是不太好!虽然目的主机一般只能得到您使用的代理服务器IP,似乎有效的遮掩了你的行程,但是值得一提的是:网络服务商开通的专业级代理服务器一般都有路由和流程记录,因此可以轻易的通过调用历史纪录来查清使用代理服务器地址的来路。
如何实现高效的HTTP代理服务器

如何实现高效的HTTP代理服务器在现代互联网时代,HTTP代理服务器已经成为了一个必不可少的网络工具。
HTTP代理服务器不仅可以有效地提高网络访问速度,还可以保护用户的隐私和安全,成为了网络工作中不可缺少的一环。
但是,要实现一个高效的HTTP代理服务器,并不是一件简单的工作。
本文将从以下几个方面探讨如何实现高效的HTTP 代理服务器。
一、选择合适的服务器HTTP代理服务器的选择是非常重要的,因为服务器的硬件配置和带宽决定了代理服务器的处理能力。
选择合适的服务器,可以有效地提高HTTP代理服务器的转发速度和可靠性。
对于HTTP 代理服务器来说,硬件配置最好能够满足以下几个条件:1、高性能的处理器和内存HTTP代理服务器会处理大量的请求和响应,需要有一个高性能的处理器和足够大的内存来处理这些请求。
选择多核、高频的处理器和足够大的内存,能够提高HTTP代理服务器的转发速度和响应时间。
2、高速的网络接口HTTP代理服务器需要有一个高速、可靠的网络接口,以便快速地转发请求和响应。
选择10Gbps以上的网络接口,能够更好地保证代理服务器的转发速度和可靠性。
3、高速的硬盘存储HTTP代理服务器需要有足够的硬盘容量和高速的存储读写速度,以便缓存请求和响应。
选择高速的SSD硬盘,能够提高代理服务器的响应时间和性能。
二、优化网络传输在实现HTTP代理服务器时,应该注意网络传输的优化。
网络传输的优化包括以下几个方面:1、使用压缩算法HTTP代理服务器可以使用压缩算法,将数据压缩后再传输。
这样能够减少数据传输时的宽带占用率,提高网络传输速度。
目前比较常见的压缩算法有Gzip和Deflate。
2、使用缓存技术HTTP代理服务器可以使用缓存技术,将请求和响应缓存在本地,下次请求时直接从缓存中读取数据。
这样可以减少网络传输的次数,提高网络传输速度。
3、限制带宽使用HTTP代理服务器可以设置带宽限制,以限制网络传输时的宽带占用率。
一个实用的HTTP代理程序设计与实现

一个实用的HTTP代理程序设计与实现HTTP代理程序是一种常见的网络应用程序,它作为中介,将客户端请求转发给目标服务器,并将服务器的响应传递回客户端。
代理服务器在实际应用中具有许多用途,例如提供缓存功能、限制对一些网站或资源的访问、提供负载均衡等。
设计一个实用的HTTP代理程序可以分为以下几个步骤:1.建立TCP连接:当客户端发送一个HTTP请求到代理服务器时,代理服务器需要解析HTTP请求报文中的目标服务器地址和端口号,并建立TCP连接。
2.解析请求:代理服务器需要解析HTTP请求报文,提取出HTTP方法、URL、请求头部以及请求体等信息。
3.检查缓存:代理服务器可以实现缓存功能,检查请求URL是否命中缓存。
如果命中缓存,则直接返回缓存内容;否则,继续处理请求。
4.转发请求:代理服务器将从客户端接收到的HTTP请求报文转发给目标服务器。
在转发请求之前,代理服务器可以修改请求报文,例如更改请求头部、添加代理相关信息等。
5.接收响应:代理服务器接收目标服务器的响应,包括响应头部和响应体等信息。
6.缓存响应:代理服务器可以缓存从目标服务器接收到的响应,以便后续的相同请求可以直接从缓存返回数据。
7.返回响应:代理服务器将目标服务器的响应返回给客户端,同时可以对响应进行修改,例如更改响应头部、压缩响应内容等。
8.断开连接:当响应返回给客户端后,代理服务器可以关闭与目标服务器的TCP连接,同时等待下一个客户端请求的到来。
在实现HTTP代理程序时,需要注意以下几点:1.并发处理:代理服务器可能会同时接收多个客户端的请求,因此需要采用多线程或多进程的方式处理请求,以提高并发处理能力。
2.鉴权认证:代理服务器可以对客户端进行鉴权认证,以确保只有授权用户可以使用代理服务。
3.日志记录:代理服务器可以记录用户的请求和响应信息,以便进行排错和性能优化。
4.安全性考虑:代理服务器需要防止恶意用户通过代理绕过安全限制,因此可以实施一些安全策略,例如限制访问特定URL、防止跨站脚本攻击等。
JavaHttpClient实现socks代理的示例代码

JavaHttpClient实现socks代理的⽰例代码HttpClient 实现 socks 代理使⽤的环境<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.4.1</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpcore</artifactId><version>4.4.1</version></dependency>代码及 ConnectionSocketFactory 实现类package xxx;import com.lucas.admin.util.HttpClientUtil;import org.apache.http.HttpEntity;import org.apache.http.HttpHost;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.client.protocol.HttpClientContext;import org.apache.http.config.Registry;import org.apache.http.config.RegistryBuilder;import org.apache.http.conn.socket.ConnectionSocketFactory;import org.apache.http.conn.socket.PlainConnectionSocketFactory;import org.apache.http.conn.ssl.SSLConnectionSocketFactory;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;import org.apache.http.protocol.HttpContext;import org.apache.http.ssl.SSLContexts;import org.apache.http.util.EntityUtils;import java.io.IOException;import .InetSocketAddress;import .Proxy;import .Socket;/*** @author kzcming* @since 2020/11/19 15:51*/public class Test {public static void main(String[] args) throws Exception {test("https:///");}public static void test(String url) throws Exception{// ConnectionSocketFactory注册Registry<ConnectionSocketFactory> reg = RegistryBuilder.<ConnectionSocketFactory>create().register("http", new MyConnectionSocketFactory()).register("https",new MySSLConnectionSocketFactory()).build();// HTTP客户端连接管理池PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(reg);CloseableHttpClient httpclient = HttpClients.custom().setConnectionManager(connManager).build();try {// socks代理地址 , socks 地址和端⼝,这⾥随便写了⼀个1008InetSocketAddress socksaddr = new InetSocketAddress("你的地址", 1008);HttpClientContext context = HttpClientContext.create();context.setAttribute("socks.address", socksaddr);// 请求⽬标HttpGet request = new HttpGet(url);System.out.println("----------------------------------------");System.out.println("执⾏请求:" + request.getRequestLine());System.out.println("通过代理: " + socksaddr);System.out.println("----------------------------------------");CloseableHttpResponse response = httpclient.execute(request, context);try {HttpEntity entity = response.getEntity();System.out.println("----------------------------------------");System.out.println("返回响应:" + response.getStatusLine());System.out.println("响应内容:" + EntityUtils.toString(entity));System.out.println("----------------------------------------");} finally {response.close();}} finally {httpclient.close();}}/*** 实现 http 链接的socket ⼯⼚*/static class MyConnectionSocketFactory extends PlainConnectionSocketFactory {@Overridepublic Socket createSocket(final HttpContext context) throws IOException {InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socks.address");// socket代理Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr);return new Socket(proxy);}}/*** 实现 https 链接的socket ⼯⼚*/static class MySSLConnectionSocketFactory extends SSLConnectionSocketFactory {public MySSLConnectionSocketFactory() {super(SSLContexts.createDefault(), getDefaultHostnameVerifier());}@Overridepublic Socket createSocket(final HttpContext context) throws IOException {InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socks.address");// // socket代理Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr);return new Socket(proxy);}}}以上就是Java HttpClient 实现 socks 代理的⽰例代码的详细内容,更多关于Java HttpClient 实现 socks 代理的资料请关注其它相关⽂章!。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1. 编写了一个HTTP高匿代理本以为编写http代理和上一篇的端口转发差不多的,结果实际一编写起来发现要复杂的多。
怎么回事呢,就在于要手动解析http协议。
说简单点吧,如果直接用ie上一个网站,用sniffe一看http请求头是这样的。
GET / HTTP/1.1Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, application/QVOD, application/QVOD, */* Accept-Language: zh-CNUser-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)Accept-Encoding: gzip, deflateHost: Connection: Keep-AliveCookie: xxxxxxxxx但是如果用代理就变成了这样GET / HTTP/1.1Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, application/QVOD, application/QVOD, */* Accept-Language: zh-CNUser-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)Accept-Encoding: gzip, deflateHost: Proxy-Connection: Keep-AliveCookie: xxxxxxxxx区别就在这里,用代理get那地方会把完整url写上,而且Connection加上了proxy标志,其他一样。
所以用TcpListener和TcpClient每接受一个连接,就要首先把提交的http请求的头部分改写,就是把下面的改成上面的。
这是GET方法,只有请求的头部分没有实体部分。
还有一种POST方法,是包含实体部分的,比如上传图片了什么的,都是用的POST方法。
post方法紧跟在头部分后面。
怎么判断哪是头那是实体呢?http协议规定头必然有2个连续的"/r/n",就像上面Cookie后面就跟了2个/r/n,所以读取请求头的时候只要读到/r/n/r/n,那么前面就是头,后面就是实体。
实体大小在上面有一个Content-Length标记。
所以从/r/n/r/n后面读Content-Length大小后就结束了还有一种是CONNECT方法,凡是用connect的就是ssl加密通信,当收到 CONNECT:443 HTTP /1.0之类的请求后,代理服务器要给客户(如IE)返回一个"HTTP/1.1 200 Connection established/r/n/r/n",然后就tcpclinet一个服务器的443,后只负责客户和服务器的转发就可以了,就像上一篇的转发一样,什么都不用管了。
这种反而最简单。
就以上3种最常用。
其他的请求方法还有put option什么的,因为实在是没见过,也不知道去哪里试所以都按照get post的方法处理了。
服务器返回更麻烦,麻烦就在于http协议过于宽松,如果每个回应或者请求都包括Content-Length或者chunked之类表明实体大小的东西那么就好判断了,http协议规定判断实体大小的方法有好几种,当然最准确的就是有Content-Length和chunked,还有以服务器断开连接来判断的,有的回应中没有Content-Length或者chunked,以什么时候断开来判断,疑似那些网络上下坏文件的就是这么造成的,客户根本不知道有多大,如果读取完了服务器断开那么没问题,如果读着读着网络中断了了,客户还以为是服务器断开了是吧。
所以读取服务器回应的时候就要判断好几个值1、判断状态码,http协议规定1xx 204 304肯定不包括实体,所以读到/r/n/r/n就不用再读了2、判断没有Content-Length3、判断有没有chunked如果有Content-Length,那么读取和上面请求头一样,/r/n/r/n后面读Content-Length个返回给客户。
还有一种是chunked编码,这种编码一般是gzip压缩的,微软论坛就是用的这种,当你请求页面的时候,服务器一边把页面gzip压缩一点传给你再压缩一点传给你,所以开始没法得到Content-Length,但是每chunked却有标记的大小HTTP/1.1 200 OKCache-Control: privateContent-Type: text/html; charset=utf-8Server: Microsoft-IIS/7.5X-AspNetMvc-Version: 2.0X-AspNet-Version: 4.0.30319Set-Cookie: Set-Cookie: X-Powered-By: P3P: CP=ALL IND DSP COR ADM CONo CUR CUSo IVAo IVDo PSA PSD TAI TELo OUR SAMo CNT COM INT NAV ONL PHY PRE PUR UNIServer: CO1VB06Date: Fri, 24 Sep 2010 09:33:28 GMTntCoent-Length: 166137Content-Encoding: gzipTransfer-Encoding: chunked2D23...........}.s.G.......j....*u......y....%...;QO.M.[....3..,....!..O....H-."v..>.............=YY像上面chunked/r/n/r/n后面是实体,第一行2D23就是一chunk的大小所以在2D23/r/n后面开始读2D23个然后会紧跟着/r/n,然后后面就是下一chunk的大小,直到最后一chunk是0大小。
实体结束,最后再来一个/r/n。
也就是说chunked的最后7个一定是/r/n0/r/n/r/n,本来判断读到/r/n0/r/n/r/n就结束应该没问题,但是为了保险起见,还是一次一次的读大小再读大小。
最讨厌的就是既没有content-length也没有chunked,如果返回的是conntion: close还好点,读着读着发现那边断开了就行了,如果返回的是keep-alive,networkstream.read那里就卡住了,表现在ie就是看似页面都加载完了,但是进度条还是在慢慢地走着,所以只能加个读取超时,比如3秒钟还读不出来就断开连接。
反而ie那里却显示“完成”,而且如果再分析keep-alive那就太麻烦了,我是从服务器那里一旦读取完,不管是不是keep-alive一律关闭连接,也就说ie每一个请求都单独的tcpclient一次服务器完后关闭。
但是处理ie就不能这样了,ie每开一的端口和代理服务器连接发送的请求是一个或多个,所以tcplistener每进来一个ie的tcpclient(即ip+端口),处理完这个tcpclient的请求后不能像断开服务器那样断开,否则ie就什么都不显示一直走那个进度条或者找不到服务器。
所以处理完一次请求后要循环再读这个tcpclient的下一个请求,如果发现这个请求断开了就彻底关闭这个tcpclient。
所以整个流程是这样的1、tcplistener监听2、循环tcplistener.accepttcpclient()3、进来一个tcpclient()后,启动一个线程处理,上面继续循环等待4、同时3的那个tcpclient开始处理,读取他的http请求头,改写http请求头,然后把改写的请求头和下面实体部分发送到请求的服务器,这里要注意必须是随读随改随发送,不能等到全读取完了再发送,否则就超时了。
5、发送完毕,开始从服务器接收6、和第4差不多,也是从服务器随读随往ie发送,也是不能读取完再发否则就超时7、读取完毕,断开和服务器的连接,不管是不是keep-alive8、重复到第4步开始,再从ie读取下一个请求,如果有那么再执行5/6/7/8,直到发现ie的这个tcpclient断开了,就彻底结束掉这个线程。
大体就是这个样子了,所以把上面的条件用代码写出来就是http代理服务器了,把上面这些条件用代码写出来是很麻烦的,所以写出来的代码是非常丑陋的,而且我本来写的代码就很难看,这样一来就更没法看了,所以我就不献丑了,关键是解释这个大体过程比代码要重要,当时我找这过程别人的文章解释的都不太清楚,看了几页http协议文档,应该是机器翻译的,很难看懂,总共100几十页,看全了不值当的,有一篇介绍c#2003做代理的文章,一看根本就是端口转发没改请求头都,一试果然不行,还有一个外国人的,很长不愿看了,那种风格就像反编译.net类库看到的那种感觉,坐一块右一块的,而且运行后发现也不大行,所以只好一点一点的抠,但是好在编译后运行效果还是挺好的,测试了一下午,cpu占用率没超过3%的时候,内存占用10兆左右,下载什么的ssl都可以,只是上网偶尔出现进度条等待的情况,就是上面说的因为服务器那边没有实体长度信息等待超时的情况,但是这无关大雅了。
大部分网站都是和直接用ie一样刷的就出来了,感觉不到慢。
下载更没问题了,和直接用ie下载速度一样的。
最后就是为什么说是高匿呢,本来想查查原理的代理部分,又想先试试是什么结果,本以为是透明代理,结果试了好几个检查代理匿名性的网站,结果全都说是“高匿”,关于匿名性,代码体现的仅仅是把ie发送的proxy-connection改成了connection,难道这样就“高匿”了?那就高匿吧。