编写了一个HTTP高匿代理
python mitmproxy用法
![python mitmproxy用法](https://img.taocdn.com/s3/m/27229945a7c30c22590102020740be1e650eccd2.png)
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代理服务器](https://img.taocdn.com/s3/m/6fb21140e418964bcf84b9d528ea81c758f52e0c.png)
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代理](https://img.taocdn.com/s3/m/3896065f4431b90d6c85c7de.png)
什么是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代理原理](https://img.taocdn.com/s3/m/a096025bc381e53a580216fc700abb68a882ad5f.png)
http代理原理
HTTP代理是一种通信转发的技术,在网络通信中充当了中间
人的角色。
它通过接收客户端的请求,然后转发请求至服务器,并将服务器的响应再转发给客户端。
代理服务器的存在使得客户端与服务器之间的通信变得间接而不是直接的。
当客户端向代理发送请求时,客户端首先要将请求目标的
URL发送给代理服务器,并告知代理要访问的资源。
代理服
务器接收到请求后,会对请求进行解析和检查,然后决定是否允许该请求通过。
如果代理服务器允许请求通过,它会向请求目标发送一个新的请求,将客户端的请求作为自己的请求发送出去。
在接收到服务器的响应后,代理服务器再将响应转发给客户端。
代理服务器有能力修改响应内容,从而实现一些功能,比如缓存、数据压缩等。
代理服务器还可以对响应进行过滤和修改,以增强网络安全性,比如过滤不良内容或者添加额外的安全头部。
HTTP代理的工作原理还包括一些其他的技术,比如连接的保持、数据的压缩、SSL加密等。
这些技术都是为了提高代理服务器的性能和安全性。
总结来说,HTTP代理是一种将客户端与服务器之间的通信转
发的技术。
它通过接收客户端请求并将其转发给服务器,再将服务器的响应转发给客户端,实现了在网络通信中的中间代理
功能。
HTTP代理的工作原理还包括其他一些技术,以提高性能和安全性。
使用HTTP代理方法 代理使用方法
![使用HTTP代理方法 代理使用方法](https://img.taocdn.com/s3/m/8d85fb0516fc700abb68fcc2.png)
使用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代理服务器](https://img.taocdn.com/s3/m/d7cb7a5a1fd9ad51f01dc281e53a580217fc5068.png)
如何实现高效的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代理程序设计与实现](https://img.taocdn.com/s3/m/29ef1728a88271fe910ef12d2af90242a995ab77.png)
一个实用的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代理的示例代码](https://img.taocdn.com/s3/m/3ee37342f11dc281e53a580216fc700abb68521c.png)
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 代理的资料请关注其它相关⽂章!。
Java实现HTTP代理服务器
![Java实现HTTP代理服务器](https://img.taocdn.com/s3/m/f4db6cdd77eeaeaad1f34693daef5ef7ba0d1265.png)
Java实现HTTP代理服务器Java 实现HTTP代理服务器1. 主服务,⽤来侦听端⼝:package org.javaren.proxy;import .ServerSocket;import .Socket;publicclassSocketProxy{/*** @param args*/publicstaticvoid main(String[] args)throwsException{ServerSocket serverSocket =newServerSocket(8888);while(true){Socket socket =null;try{socket = serverSocket.accept();newSocketThread(socket).start();}catch(Exception e){e.printStackTrace();}}}}2. 核⼼代码,处理链接的代理线程,内部设计了Socket的认证:package org.javaren.proxy;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import .Socket;publicclassSocketThreadextendsThread{privateSocket socketIn;privateInputStream isIn;privateOutputStream osIn;//privateSocket socketOut;privateInputStream isOut;privateOutputStream osOut;publicSocketThread(Socket socket){this.socketIn = socket;}privatebyte[] buffer =newbyte[4096];privatestaticfinalbyte[] VER ={0x5,0x0};privatestaticfinalbyte[] CONNECT_OK ={0x5,0x0,0x0,0x1,0,0,0,0,0,0};publicvoid run(){try{System.out.println("\n\na client connect "+ socketIn.getInetAddress()+":"+ socketIn.getPort());isIn = socketIn.getInputStream();osIn = socketIn.getOutputStream();int len = isIn.read(buffer);System.out.println("< "+ bytesToHexString(buffer,0, len));osIn.write(VER);osIn.flush();System.out.println("> "+ bytesToHexString(VER,0, VER.length));len = isIn.read(buffer);System.out.println("< "+ bytesToHexString(buffer,0, len));// 查找主机和端⼝String host = findHost(buffer,4,7);int port = findPort(buffer,8,9);System.out.println("host="+ host +",port="+ port);socketOut =newSocket(host, port);isOut = socketOut.getInputStream();osOut = socketOut.getOutputStream();//for(int i =4; i <=9; i++){CONNECT_OK[i]= buffer[i];}osIn.write(CONNECT_OK);osIn.flush();System.out.println("> "+ bytesToHexString(CONNECT_OK,0, CONNECT_OK.length));SocketThreadOutputout=newSocketThreadOutput(isIn, osOut); out.start();SocketThreadInputin=newSocketThreadInput(isOut, osIn);in.start();out.join();in.join();}catch(Exception e){System.out.println("a client leave");}finally{try{if(socketIn !=null){socketIn.close();}}catch(IOException e){e.printStackTrace();}}System.out.println("socket close");}publicstaticString findHost(byte[] bArray,intbegin,intend){StringBuffer sb =newStringBuffer();for(int i =begin; i <=end; i++){sb.append(Integer.toString(0xFF& bArray[i]));sb.append(".");}sb.deleteCharAt(sb.length()-1);return sb.toString();}publicstaticint findPort(byte[] bArray,intbegin,intend){int port =0;for(int i =begin; i <=end; i++){port <<=16;port += bArray[i];}return port;}// 4A 7D EB 69// 74 125 235 105publicstaticfinalString bytesToHexString(byte[] bArray,intbegin,intend){ StringBuffer sb =newStringBuffer(bArray.length);String sTemp;for(int i =begin; i <end; i++){sTemp =Integer.toHexString(0xFF& bArray[i]);if(sTemp.length()<2)sb.append(0);sb.append(sTemp.toUpperCase());sb.append(" ");}return sb.toString();}}3. 读取线程,负责外⾯读数据,写⼊到请求端:package org.javaren.proxy;/*** * 从外部读取,向内部发送信息*/import java.io.InputStream;import java.io.OutputStream; publicclassSocketThreadInputextendsThread{privateInputStream isOut;privateOutputStream osIn;publicSocketThreadInput(InputStream isOut,OutputStream osIn){this.isOut = isOut;this.osIn = osIn;}privatebyte[] buffer =newbyte[409600];publicvoid run(){try{int len;while((len = isOut.read(buffer))!=-1){if(len >0){System.out.println(newString(buffer,0, len));osIn.write(buffer,0, len);osIn.flush();}}}catch(Exception e){System.out.println("SocketThreadInput leave");}}}4. 写⼊线程,负责读取请求端数据,写⼊到⽬标端:package org.javaren.proxy;import java.io.InputStream;import java.io.OutputStream;/*** 从内部读取,向外部发送信息** @author zxq**/publicclassSocketThreadOutputextendsThread{privateInputStream isIn;privateOutputStream osOut;publicSocketThreadOutput(InputStream isIn,OutputStream osOut){ this.isIn = isIn;this.osOut = osOut;}privatebyte[] buffer =newbyte[409600];publicvoid run(){try{int len;while((len = isIn.read(buffer))!=-1){if(len >0){System.out.println(newString(buffer,0, len));osOut.write(buffer,0, len);osOut.flush();}}}catch(Exception e){System.out.println("SocketThreadOutput leave");}}}。
【python爬虫】如何建立代理ip池?
![【python爬虫】如何建立代理ip池?](https://img.taocdn.com/s3/m/b9b70792ce2f0066f53322fa.png)
t=threading.Thread(target=findip,args=(type+1,pagenum+1,target url,path))
threads.append(t) print('开始爬取代理 ip')
for s in threads: # 开启多线程爬取 s.start() for e in threads: # 等待所有线程结束 e.join() print('爬取完成')
Gecko) Chrome/19.0.1055.1 Safari/535.24", \ "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML,
like Gecko) Chrome/19.0.1055.1 Safari/535.24" ] UserAgent=random.choice(user_agent_list) headers = {'User-Agent': UserAgent} return headers
#-----------------------------------------------------多线程抓
取 ip 入口-------------------def getip(targeturl,path):
truncatefile(path) # 爬取前清空文档
start = datetime.datetime.now() # 开始时间 threads=[] for type in range(4): # 四种类型 ip,每种类型取前三页,共 12 条线程 for pagenum in range(3):
如何解决爬虫被封的问题
![如何解决爬虫被封的问题](https://img.taocdn.com/s3/m/bc6d4168336c1eb91a375d4c.png)
如何解决爬虫被封的问题如果你在爬虫过程中有遇到“您的请求太过频繁,请稍后再试”,或者说代码完全正确,可是爬虫过程中突然就访问不了,那么恭喜你,你的爬虫被对方识破了,轻则给予友好提示警告,严重的可能会对你的ip进行封禁,所以代理ip那就尤为重要了。
今天我们就来谈一下代理IP,去解决爬虫被封的问题。
网上有许多代理ip,免费的、付费的。
大多数公司爬虫会买这些专业版,对于普通人来说,免费的基本满足我们需要了,不过免费有一个弊端,时效性不强,不稳定,所以我们就需要对采集的ip进行一个简单的验证。
1.目标采集本文主要针对西刺代理,这个网站很早之前用过,不过那个时候它还提供免费的api,现在api暂不提供了,我们就写个简单的爬虫去采集。
打开西刺代理,有几个页面,果断选择高匿代理。
Chrome浏览器右键检查查看network,不难发现,每个ip地址都在td标签中,对于我们来说就简单许多了,初步的想法就是获取所有的ip,然后校验可用性,不可用就剔除。
定义匹配规则import reip_compile = repile(r(\d+\.\d+\.\d+\.\d+)) # 匹配IPport_compile = repile(r(\d+)) # 匹配端口2.校验这里我使用淘宝ip地址库检验可用性2.1、关于淘宝IP地址库目前提供的服务包括:1. 根据用户提供的IP地址,快速查询出该IP地址所在的地理信息和地理相关的信息,包括国家、省、市和运营商。
2. 用户可以根据自己所在的位置和使用的IP地址更新我们的服务内容。
我们的优势:1. 提供国家、省、市、县、运营商全方位信息,信息维度广,格式规范。
2. 提供完善的统计分析报表,省准确度超过99.8%,市准确度超过96.8%,数据质量有保障。
2.2、接口说明。
python实现简单http代理
![python实现简单http代理](https://img.taocdn.com/s3/m/20b6bcc43086bceb19e8b8f67c1cfad6195fe9d4.png)
python实现简单http代理http 代理有什么⽤处?1,可以是插⼊ js ⼴告,某些 isp 就是这么⼲的,强插⼴告,现在 https 的⽹站越来越多了,插⼊不了。
2, ⽤来调试 app 或是别的程序,可以看到详细的 http 请求,响应,fiddler 这个软件也是做这个的,但它不开源。
使⽤ wireshark 抓包:GET http://localhost/logo.gif HTTP/1.1Host: localhostUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Accept-Encoding: gzip, deflateDNT: 1Connection: keep-aliveUpgrade-Insecure-Requests: 1#或第 2 种GET http://localhost:8000/logo.gif HTTP/1.1Host: localhost:8000User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Accept-Encoding: gzip, deflateDNT: 1Connection: keep-aliveUpgrade-Insecure-Requests: 1原理:http 1.1 也就是 tcp 连接,有 header 和 body ,更多复杂的细节这⾥不做介绍(session cookie 缓存等)下⾯使⽤ python 实现, listen 8000 端⼝,分析原始的请求⽹址的HOST 和端⼝,建⽴连接拿回数据转发。
java实现轻量型http代理服务器示例
![java实现轻量型http代理服务器示例](https://img.taocdn.com/s3/m/2013b51d77c66137ee06eff9aef8941ea76e4ba3.png)
java实现轻量型http代理服务器⽰例复制代码代码如下:package cn.liangjintang.httpproxy;import java.io.BufferedReader;import java.io.ByteArrayInputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import .ServerSocket;import .Socket;public class HttpProxy {static long threadCount = 0;int myTcpPort = 8080;private ServerSocket myServerSocket;private Thread myThread;public HttpProxy(int port) throws IOException {myTcpPort = port;myServerSocket = new ServerSocket(myTcpPort);myThread = new Thread(new Runnable() {public void run() {try {while (true)new HTTPSession(myServerSocket.accept());} catch (IOException ioe) {}}});myThread.setDaemon(true);myThread.start();}/*** Stops the server.*/public void stop() {try {myServerSocket.close();myThread.join();} catch (IOException ioe) {} catch (InterruptedException e) {}}public class HTTPSession implements Runnable {private Socket mySocket;public HTTPSession(Socket s) {mySocket = s;Thread t = new Thread(this);t.setDaemon(true);t.start();}@Overridepublic void run() {try {++threadCount;InputStream is = mySocket.getInputStream();if (is == null)return;final int bufsize = 8192;byte[] buf = new byte[bufsize];int splitbyte = 0;int rlen = 0;{int read = is.read(buf, 0, bufsize);while (read > 0) {rlen += read;splitbyte = findHeaderEnd(buf, rlen);if (splitbyte > 0)break;read = is.read(buf, rlen, bufsize - rlen);}ByteArrayInputStream hbis = new ByteArrayInputStream(buf, 0, rlen);BufferedReader hin = new BufferedReader(new InputStreamReader(hbis));Host host = new Host();{String string;boolean flag = false;while ((string = hin.readLine()) != null) {if (string.toLowerCase().startsWith("host:")) {host.host = string;flag = true;}System.out.println(string);}if (!flag) {mySocket.getOutputStream().write("error!".getBytes());mySocket.close();return;}}host.cal();System.out.println("address:[" + host.address + "]port:"+ host.port + "\n-------------------\n");try {pipe(buf, rlen, mySocket, mySocket.getInputStream(),mySocket.getOutputStream(), host);} catch (Exception e) {System.out.println("Run Exception!");e.printStackTrace();}}} catch (Exception e) {}System.out.println("threadcount:" + --threadCount);}/*** finad http header**/private int findHeaderEnd(final byte[] buf, int rlen) {int splitbyte = 0;while (splitbyte + 3 < rlen) {if (buf[splitbyte] == '\r' && buf[splitbyte + 1] == '\n'&& buf[splitbyte + 2] == '\r'&& buf[splitbyte + 3] == '\n')return splitbyte + 4;splitbyte++;}return 0;}void pipe(byte[] request, int requestLen, Socket client,InputStream clientIS, OutputStream clientOS, Host host) throws Exception {byte bytes[] = new byte[1024 * 32];Socket socket = new Socket(host.address, host.port);socket.setSoTimeout(3000);OutputStream os = socket.getOutputStream();InputStream is = socket.getInputStream();try {do {os.write(request, 0, requestLen);int resultLen = 0;try {while ((resultLen = is.read(bytes)) != -1&& !mySocket.isClosed() && !socket.isClosed()) {clientOS.write(bytes, 0, resultLen);}} catch (Exception e) {System.out.println("target Socket exception:"+ e.toString());}System.out.println("proxy requset-connect broken,socket:" + socket.hashCode());} while (!mySocket.isClosed()&& (requestLen = clientIS.read(request)) != -1);} catch (Exception e) {System.out.println("client Socket exception:" + e.toString()); }System.out.println("end,socket:" + socket.hashCode());os.close();is.close();clientIS.close();clientOS.close();socket.close();mySocket.close();}// target Host infofinal class Host {public String address;public int port;public String host;public boolean cal() {if (host == null)return false;int start = host.indexOf(": ");if (start == -1)return false;int next = host.indexOf(':', start + 2);if (next == -1) {port = 80;address = host.substring(start + 2);} else {address = host.substring(start + 2, next);port = Integer.valueOf(host.substring(next + 1)); }return true;}}}public static void main(String[] args) {try {new HttpProxy(8580);} catch (IOException ioe) {System.err.println("Couldn't start server:\n" + ioe); System.exit(-1);}System.out.println("start!");try {System.in.read();} catch (Throwable t) {}System.out.println("stop!");}}。
代理IP 的匿名程度分类
![代理IP 的匿名程度分类](https://img.taocdn.com/s3/m/10fbe5cb524de518964b7d4e.png)
代理IP 的匿名程度分类透明代理、匿名代理、混淆代理、高匿代理, 这4种代理,主要是在代理服务器端的配置不同,导致其向目标地址发送请求时HTTP 头,REMOTE_ADDR,HTTP_VIA,HTTP_X_FORWARDED_FOR三个变量不同。
1、透明代理(Transparent Proxy)REMOTE_ADDR = Proxy IPHTTP_VIA = Proxy IPHTTP_X_FORWARDED_FOR = Your IP透明代理虽然可以直接“隐藏”你的IP地址,但是还是可以从HTTP_X_FORWARDED_FOR来查到你是谁。
2、匿名代理(Anonymous Proxy)REMOTE_ADDR = proxy IPHTTP_VIA = proxy IPHTTP_X_FORWARDED_FOR = proxy IP匿名代理比透明代理进步了一点:别人只能知道你用了代理,无法知道你是谁。
复制代码3、混淆代理(Distorting Proxies)REMOTE_ADDR = Proxy IPHTTP_VIA = Proxy IPHTTP_X_FORWARDED_FOR = Random IP address如上,与匿名代理相同,如果使用了混淆代理,别人还是能知道你在用代理,但是会得到一个假的IP地址,伪装的更逼真4、高匿代理(Elite proxy或High Anonymity Proxy)REMOTE_ADDR = Proxy IPHTTP_VIA = not determinedHTTP_X_FORWARDED_FOR = not determined可以看出来,高匿代理让别人根本无法发现你是在用代理,所以是最好的选择。
UU代理不错的选择。
JAVA实现的HTTP反向代理[smiley-http-proxy-servlet]学习
![JAVA实现的HTTP反向代理[smiley-http-proxy-servlet]学习](https://img.taocdn.com/s3/m/5d15f4681fd9ad51f01dc281e53a580216fc5060.png)
JAVA实现的HTTP反向代理[smiley-http-proxy-servlet]学习 反向代理(Reverse Proxy)⽅式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部⽹络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为⼀个反向代理服务器。
简单来说,你的反向代理服务器会接收请求,但其⾃⾝不处理该请求,⽽是对请求经过⼀些处理,例如添加⽇志、缓存、⾝份验证等服务,然后再将请求转发到相应的应⽤服务器中进⾏处理,最后将处理结果返回。
我⽬前的需求是,A应⽤需要访问B应⽤的报表页⾯,B应⽤没有源码,要求⾃动处理B应⽤的登录权限。
避免⽤户重复登录。
1. 引⼊相关依赖<dependency><groupId>org.mitre.dsmiley.httpproxy</groupId><artifactId>smiley-http-proxy-servlet</artifactId><version>1.11</version></dependency>这个jar包,只有两个类,其中核⼼的就是 ProxyServlet,作者重写了HttpServlet的相关⽅法。
他复制了新的request为proxyRequest,然后替换了地址和相关属性,并使⽤HttpClient将proxyRequest发送出去,然后将接收到的proxyResponse的内容再复制给 HttpResponse 。
相当于中转站。
具体请看源码。
2.spring使⽤:2.1 application.yml增加代理参数配置# 设置代理proxy:servlet_url: /webappB/*target_url: https://webappB_HOST_IP:8001/webappB #已有的app路径其他demo# servlet_url: /proxybaidu/*# target_url: https://此处有⽞机:为什么代理url的app⼦路径和⽬标url的app⼦路径要⼀致(都为/webappB/)呢?这是因为: target_url页⾯⾥不⽌⽂本显⽰,还有其他资源的调⽤,⽐如图⽚,⽐如⾥⾯的js⼜调⽤了其他url.这样的话,假如 target页⾯⾥某个图⽚的url是相对路径img/test.jpg (https://webappB_HOST_IP:8001/webappB/img/test.jpg); 你的代理页⾯app⼦路径⽤webappC,那么图⽚地址就成 /webappC/image/test.jpg; 这样app⼦url换了以后是找不到图⽚地址的。
怎么代理http
![怎么代理http](https://img.taocdn.com/s3/m/8c3db4a7998fcc22bcd10d69.png)
怎么代理http
我们对HTTP代理应该是比较了解的,它在许多方面都有很多的使用范围。
HTTP代理最常见的适用范围是用以网络共享、网络加速和网络限制突破等。
除此之外,HTTP代理也常用于Web应用调试、Android/IOS APP中所调用的Web API监控和分析,HTTP代理还可用以请求/响应内容修改,在不更改服务端的状况下为Web应用添加额外的功能或是改变应用行为等。
HTTP代理是一个Web应用,它和别的一般Web应用并没有什么区别。
HTTP代理接到请求后,按照Header中Host字段的主机名和Get/POST请求地址综合判断目标主机,创建新的HTTP请求并转发请求数据信息,并将接到的响应数据信息发送给客户端。
那么代理HTTP的提取是什么样的。
(1)、提取代理ip
(2)、生成api链接,复制链接/打开链接即可应用
(3)、生成代理ip操作使用方式
其实很多的网站为了维护自身网站的安全会设置反爬虫机制,代理HTTP 的使用多数会用于爬虫工作,面对网站的反爬虫机制,使用代理HTTP可以解决这个问题。
如果还想继续访问这个网站,HTTP代理ip就很重要,倘若当前的ip地址受限制,可以换一个新的ip地址,保证爬虫的顺利进行。
java实现http的Post、Get、代理访问请求
![java实现http的Post、Get、代理访问请求](https://img.taocdn.com/s3/m/0c50d59dcd22bcd126fff705cc17552707225e9d.png)
java实现http的Post、Get、代理访问请求本⽂实例讲解了java实现http的Post、Get、代理访问请求的详细代码⽚段,分享给⼤家供⼤家参考,具体内容如下package ;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStreamWriter;import java.io.UnsupportedEncodingException;import .HttpURLConnection;import .InetSocketAddress;import .Proxy;import .URL;import .URLConnection;import java.util.List;import java.util.Map;/*** Http请求⼯具类* @author snowfigure* @since 2014-8-24 13:30:56* @version v1.0.1*/public class HttpRequestUtil {static boolean proxySet = false;static String proxyHost = "127.0.0.1";static int proxyPort = 8087;/*** 编码* @param source* @return*/public static String urlEncode(String source,String encode) {String result = source;try {result = .URLEncoder.encode(source,encode);} catch (UnsupportedEncodingException e) {e.printStackTrace();return "0";}return result;}public static String urlEncodeGBK(String source) {String result = source;try {result = .URLEncoder.encode(source,"GBK");} catch (UnsupportedEncodingException e) {e.printStackTrace();return "0";}return result;}/*** 发起http请求获取返回结果* @param req_url 请求地址* @return*/public static String httpRequest(String req_url) {StringBuffer buffer = new StringBuffer();try {URL url = new URL(req_url);HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();httpUrlConn.setDoOutput(false);httpUrlConn.setDoInput(true);httpUrlConn.setUseCaches(false);httpUrlConn.setRequestMethod("GET");httpUrlConn.connect();// 将返回的输⼊流转换成字符串InputStream inputStream = httpUrlConn.getInputStream();InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8"); BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String str = null;while ((str = bufferedReader.readLine()) != null) {buffer.append(str);}bufferedReader.close();inputStreamReader.close();// 释放资源inputStream.close();inputStream = null;httpUrlConn.disconnect();} catch (Exception e) {System.out.println(e.getStackTrace());}return buffer.toString();}/*** 发送http请求取得返回的输⼊流* @param requestUrl 请求地址* @return InputStream*/public static InputStream httpRequestIO(String requestUrl) {InputStream inputStream = null;try {URL url = new URL(requestUrl);HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();httpUrlConn.setDoInput(true);httpUrlConn.setRequestMethod("GET");httpUrlConn.connect();// 获得返回的输⼊流inputStream = httpUrlConn.getInputStream();} catch (Exception e) {e.printStackTrace();}return inputStream;}/*** 向指定URL发送GET⽅法的请求** @param url* 发送请求的URL* @param param* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
- 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,难道这样就“高匿”了?那就高匿吧。