`
ethen
  • 浏览: 119520 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

多线程Http代理服务器 Java实现

阅读更多

最近心血来潮,想熟悉一下Socket编程,就在网上看了一些资料,对Socket有了一个比较基本的了解,无意间竟发现用Java开发的简易HttpProxy的Demo,现对源程序进行了一些小的修改,使可读性变强,以供大家参考。

import java.io.*;
import java.net.*;
public class MyHttpProxy extends Thread { 
	static public int CONNECT_RETRIES=5;	//尝试与目标主机连接次数
	static public int CONNECT_PAUSE=5;	//每次建立连接的间隔时间
	static public int TIMEOUT=50;	//每次尝试连接的最大时间
	static public int BUFSIZ=1024;	//缓冲区最大字节数
	static public boolean logging = false;	//是否记录日志
	static public OutputStream log_S=null;	//日志输出流
	static public OutputStream log_C=null;	//日志输出流
//	static public String LOGFILENAME_S="log_S.txt";
//	static public String LOGFILENAME_C="log_C.txt";
	// 与客户端相连的Socket
	protected Socket csocket;	
    public MyHttpProxy(Socket cs) { 
	csocket=cs;
	start(); 
    }
    public void writeLog(int c, boolean browser) throws IOException {
    	if(browser) log_C.write((char)c);
    	else log_S.write((char)c);
    }

    public void writeLog(byte[] bytes,int offset, int len, boolean browser) throws IOException {
   	for (int i=0;i<len;i++) 
   		writeLog((int)bytes[offset+i],browser);
    }
    public void run(){
    	String buffer = "";		//读取请求头
    	String URL="";			//读取请求URL
    	String host="";			//读取目标主机host
    	int port=80;			//默认端口80
    	Socket ssocket = null;
         //cis为客户端输入流,sis为目标主机输入流
    	InputStream cis = null,sis=null;
         //cos为客户端输出流,sos为目标主机输出流
    	OutputStream cos = null,sos=null;	    	
       	try{
    		csocket.setSoTimeout(TIMEOUT);
    		cis=csocket.getInputStream();
    		cos=csocket.getOutputStream();
    		while(true){
    			int c=cis.read();
    			if(c==-1) break;		//-1为结尾标志
    			if(c=='\r'||c=='\n') break;//读入第一行数据
    			buffer=buffer+(char)c;
    			if (logging) writeLog(c,true);
    		}
    	//抽取URL(http://www.baidu.com/)  	
   		URL=getRequestURL(buffer);		
	
		int n;
    	//抽取host
  		n=URL.indexOf("//");
 		if (n!=-1) 	
                		host=URL.substring(n+2);	// www.baidu.com/
  		n=host.indexOf('/');
   		if (n!=-1) 	
                  		host=host.substring(0,n);// www.baidu.com
    	    
    	// 分析可能存在的端口号
  		n=host.indexOf(':');
   		if (n!=-1) { 
   			port=Integer.parseInt(host.substring(n+1));
   			host=host.substring(0,n);
  		}
   		int retry=CONNECT_RETRIES;
   		while (retry--!=0) {
   			try {
    				ssocket=new Socket(host,port);	//尝试建立与目标主机的连接
    				break;
    			} catch (Exception e) { }
                 		// 等待
   			Thread.sleep(CONNECT_PAUSE);
   		}
   		if(ssocket!=null){
   			ssocket.setSoTimeout(TIMEOUT);
   			sis=ssocket.getInputStream();
   			sos=ssocket.getOutputStream();
   			sos.write(buffer.getBytes());		//将请求头写入
   			pipe(cis,sis,sos,cos);				//建立通信管道
   		}    			
          	}catch(Exception e){
    		e.printStackTrace();
    	}
    	finally {
		try { 
		    	csocket.close();
		    	cis.close();
		    	cos.close();
		} 
		catch (Exception e1) {
		    	System.out.println("\nClient Socket Closed Exception:");
		    	e1.printStackTrace();
		}
		try { 
		    	ssocket.close();
		    	sis.close();
		    	sos.close();
		} 
		catch (Exception e2) {
		    	System.out.println("\nServer Socket Closed Exception:");
		    	e2.printStackTrace();
		}
       	}
    }
    public String getRequestURL(String buffer){
    	String[] tokens=buffer.split(" ");
    	String URL="";
    	for(int index=0;index<tokens.length;index++){
    		if(tokens[index].startsWith("http://")){
    			URL=tokens[index];
    			break;
    		}
    	}
    	return URL;    	
    }
    public void pipe(InputStream cis,InputStream sis,OutputStream sos,OutputStream cos){
    	try {
    	    int length;
    	    byte bytes[]=new byte[BUFSIZ];
    	    while (true) {
    	    	try {
    	    		if ((length=cis.read(bytes))>0) {
    	    			sos.write(bytes,0,length);
    	    			if (logging) writeLog(bytes,0,length,true); 	    			
    	    		}
    	    		else if (length<0)
    	    			break;
    	    	}
    	    	catch(SocketTimeoutException e){}
    	    	catch (InterruptedIOException e) { 
    	    		System.out.println("\nRequest Exception:");
    	    		e.printStackTrace();
    	    	}
    	    	try {
    	    		if ((length=sis.read(bytes))>0) {
    	    			cos.write(bytes,0,length);
    	    			if (logging) writeLog(bytes,0,length,false);
    	    		}
    	    		else i[align=left][/align]f (length<0) 
    	    			break;
    	    	}
    	    	catch(SocketTimeoutException e){}
    	    	catch (InterruptedIOException e) {
    	    		System.out.println("\nResponse Exception:");
    		    	e.printStackTrace();
    	    	}
    	    }
    	} catch (Exception e0) {
    	    System.out.println("Pipe异常: " + e0);
    	}
    }
}

 

 
下面这张图可以清晰地阐明HttpProxy的实现原理:


其中流程具体如下:
1、客户端通过浏览器向代理服务器发送HttpRequest(GET/POST);
2、代理服务器读取请求头,抽取出请求的具体目标服务器HOST和PORT;
3、代理服务器把请求头发送给目标服务器;
4、代理服务器建立管道,供客户端和目标服务器通过两个Socket通信。

遗留问题:
最终经过测试,发现在访问百度时会出现非常诡异的错误,不知道为何?
问题如下:
1、访问百度主页,正常显示。
2、在百度主页点击贴吧或者其他链接时会发现链接到一些非常诡异的页面,不知道为何。还待以后研究。
简单的测试

public static  void startProxy(int port,Class clobj) { 
    try { 
        ServerSocket ssock=new ServerSocket(port); 
        while (true) { 
        Class [] sarg = new Class[1]; 
        Object [] arg= new Object[1]; 
        sarg[0]=Socket.class; 
        try { 
        java.lang.reflect.Constructor cons = clobj.getDeclaredConstructor(sarg); 
        arg[0]=ssock.accept(); 
        cons.newInstance(arg); // 创建HttpProxy或其派生类的实例 
        } catch (Exception e) { 
        Socket esock = (Socket)arg[0]; 
        try { esock.close(); } catch (Exception ec) {} 
        } 
        } 
    } catch (IOException e) { 
    System.out.println("\nStartProxy Exception:"); 
    e.printStackTrace(); 
    } 
    } 


        // 测试用的简单main方法 
    static public void main(String args[]) throws FileNotFoundException { 
    System.out.println("在端口808启动代理服务器\n"); 
    OutputStream file_S=new FileOutputStream(new File(LOGFILENAME_S)); 
    OutputStream file_C=new FileOutputStream(new File(LOGFILENAME_C)); 
    MyHttpProxy.log_S=file_S; 
    MyHttpProxy.log_C=file_C; 
    MyHttpProxy.logging=true; 
    MyHttpProxy.startProxy(808,MyHttpProxy.class); 
    }

 

 代码如下:

  • 大小: 23 KB
  • 大小: 22.8 KB
分享到:
评论
2 楼 xlrtx 2013-10-01  
好像只发了HTTP的第一行请求,没有包括后面的header,比如cookie什么什么的

所以访问某些页面会出现奇怪的问题吧
1 楼 liaoshaoyao 2011-03-27  
如何使用呀? 运行测试类之后再在浏览器中输入目标URL?

相关推荐

    基于Java多线程的HTTP代理服务器的研究与实现.pdf

    NULL 博文链接:https://sunshineyao.iteye.com/blog/976871

    基于HTTP代理服务器的实现的毕业设计,Socket编程技术,借助第三方库实现HTTP协议的解析和封装,使用多线程技术实现并发

    在实现过程中,我们将采用Java语言和Socket编程技术,借助第三方库实现HTTP协议的解析和封装,同时使用多线程技术实现并发处理。具体实现包括: 1. 建立Socket连接,监听客户端请求。 2. 解析HTTP请求报文,获取...

    支持多线程的SFTP类代码

    适用多线程的SFTP类,支持代理服务器,是spring服务类,无需修改可直接与spring结合使用。 代码经过大量的并发使用验证,稳定可靠。 依赖的jar包如下: &lt;groupId&gt;com.jcraft&lt;/groupId&gt; &lt;artifactId&gt;...

    代理服务器自动测试工具(含Java源码)

    用Java写的一个小工具,通过HTML解析技术,从http://www.cnproxy.com读取代理服务器列表,并采用多线程通过代理服务器连接指定网站,测试该服务器是否可用,将可以使用的代理服务器列出以供使用。这个小工具使用了...

    socketproxy:一个简单的 Java 多线程 Socket 代理服务器。 它侦听传入的连接并将任何通信转发到服务器,同时记录整个对话

    套接字代理一个简单的 Java 多线程 Socket 代理服务器。 它侦听传入的连接并将任何通信转发到服务器,同时记录整个对话。套接字代理服务器这是库的主类。 它可以由第三方实例化,并提供本地端口和服务器的远程主机/...

    java开源包4

    Smart Cache 是一个采用 Java 开发的 HTTP/1.1代理服务器,也可以用来作为Web的缓存系统。 高性能的JSON处理 Jackson Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash ...

    java开源包3

    Smart Cache 是一个采用 Java 开发的 HTTP/1.1代理服务器,也可以用来作为Web的缓存系统。 高性能的JSON处理 Jackson Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash ...

    JAVA上百实例源码以及开源项目

     Tcp服务端与客户端的JAVA实例源代码,一个简单的Java TCP服务器端程序,别外还有一个客户端的程序,两者互相配合可以开发出超多的网络程序,这是最基础的部分。 递归遍历矩阵 1个目标文件,简单! 多人聊天室 3...

    JAVA上百实例源码以及开源项目源代码

     Tcp服务端与客户端的JAVA实例源代码,一个简单的Java TCP服务器端程序,别外还有一个客户端的程序,两者互相配合可以开发出超多的网络程序,这是最基础的部分。 递归遍历矩阵 1个目标文件,简单! 多人聊天室 3...

    java开源包11

    Smart Cache 是一个采用 Java 开发的 HTTP/1.1代理服务器,也可以用来作为Web的缓存系统。 高性能的JSON处理 Jackson Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash ...

    java开源包6

    Smart Cache 是一个采用 Java 开发的 HTTP/1.1代理服务器,也可以用来作为Web的缓存系统。 高性能的JSON处理 Jackson Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash ...

    java开源包9

    Smart Cache 是一个采用 Java 开发的 HTTP/1.1代理服务器,也可以用来作为Web的缓存系统。 高性能的JSON处理 Jackson Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash ...

    java开源包101

    Smart Cache 是一个采用 Java 开发的 HTTP/1.1代理服务器,也可以用来作为Web的缓存系统。 高性能的JSON处理 Jackson Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash ...

    java开源包5

    Smart Cache 是一个采用 Java 开发的 HTTP/1.1代理服务器,也可以用来作为Web的缓存系统。 高性能的JSON处理 Jackson Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash ...

    java开源包1

    Smart Cache 是一个采用 Java 开发的 HTTP/1.1代理服务器,也可以用来作为Web的缓存系统。 高性能的JSON处理 Jackson Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash ...

    JAVA_API1.6文档(中文)

    java.lang.instrument 提供允许 Java 编程语言代理检测运行在 JVM 上的程序的服务。 java.lang.management 提供管理接口,用于监视和管理 Java 虚拟机以及 Java 虚拟机在其上运行的操作系统。 java.lang.ref 提供...

    java开源包8

    Smart Cache 是一个采用 Java 开发的 HTTP/1.1代理服务器,也可以用来作为Web的缓存系统。 高性能的JSON处理 Jackson Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash ...

    java开源包10

    Smart Cache 是一个采用 Java 开发的 HTTP/1.1代理服务器,也可以用来作为Web的缓存系统。 高性能的JSON处理 Jackson Jackson 是一个 Java 用来处理 JSON 格式数据的类库,性能非常好。 哈希计算工具 java-hash ...

    Proxy-Server:一个多线程的网络代理服务器,可被普通网络浏览器用来匿名访问远程主机

    #Multithreaded Proxy Server 这是一个多线程 Web 代理服务器,可用于普通 Web 浏览器匿名访问远程主机。 它可以响应 GET 和 POST 请求。 有关更多信息,请参阅。 源代码文件是 src 文件夹下的 ProxyServer.java 和 ...

    Http/FTP多线程断点续传下载组件

    点量Http、FTP多线程断点续传下载组件(下载DLL)的开发目的是让用户可以无需关心Http/FTP协议的具体细节,只需要几十行甚至几行代码,便可以实现一个功能完善的Http/FTP下载软件。点量Http/FTP下载组件(DLL)支持...

Global site tag (gtag.js) - Google Analytics