`
ethen
  • 浏览: 122224 次
  • 性别: 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

    《基于Java多线程的HTTP代理服务器的研究与实现》这篇文档深入探讨了如何利用Java语言构建一个高效的多线程HTTP代理服务器。在信息技术领域,HTTP代理服务器扮演着至关重要的角色,它作为客户端与目标服务器之间的...

    tt.rar_ java_Java 代理服务器_java 线程_代理服务器_服务器

    在Java中实现代理服务器涉及到多个关键概念和技术,包括网络编程、多线程以及服务器端的处理逻辑。 首先,我们需要理解Java中的网络编程基础。Java提供了一系列的类库,如`java.net.Socket`和`java.net....

    java+selenium(房天下 链家小区 多线程+代理实现)

    总结,本项目展示了如何结合Java、Selenium和多线程技术实现高效且安全的网络爬虫。通过代理IP避免了被目标网站识别,提高了爬虫的生存能力。同时,项目的可扩展性也意味着它可以适应更多类似的需求,比如抓取其他...

    代理服务器实现-java(源码)

    总的来说,这个Java代理服务器示例提供了一个基础的代理服务实现,有助于理解网络编程、HTTP协议以及Java中的多线程和网络通信机制。通过扩展这个基础代码,可以实现更复杂的代理功能,如缓存、访问控制、加密等。

    Java的HTTP代理服务器 Smart Cache

    它利用了Java的多线程和网络编程能力,实现了对HTTP协议的代理服务,并结合智能缓存策略,优化了数据传输效率。 在HTTP代理服务器的角色下,Smart Cache充当了一个中介,用户通过这个代理服务器向目标Web服务器发送...

    基于Java实现的代理服务器

    Java 实现的代理服务器是一种网络通信工具,它允许客户端通过该服务器作为中介与目标服务器进行交互,从而隐藏了客户端的真实身份或提供了额外的安全性。在本项目中,我们主要关注的是实现了 SOCKS4 和 SOCKS5 协议...

    Java写http代理服务器

    在Java中实现HTTP代理服务器,主要涉及到以下几个关键步骤和知识点: 1. **网络编程基础**:熟悉Java的Socket编程是首要的,因为HTTP通信基于TCP/IP协议,我们需要使用Socket来建立客户端和服务器之间的连接。`java...

    Java代理服务器的实现

    ### Java代理服务器的实现 #### 概述 Java代理服务器是一种网络中间件,它作为客户端与目标服务器之间的中介,能够帮助转发HTTP请求和响应。在实际应用中,代理服务器不仅能够提升安全性,还能够用于缓存、日志...

    java 实现HTTP PROXY

    Java实现HTTP PROXY是一个常见的需求,特别是在开发网络应用或者测试环境中,我们可能需要通过代理服务器转发HTTP请求。本文将深入探讨如何使用Java编程语言来创建一个HTTP代理服务器,并且会涉及相关的源码分析。 ...

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

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

    Java代理服务器程序

    在这个Java实现的代理服务器程序中,我们可以深入探讨几个关键的技术点。 首先,代理服务器的核心是网络通信。Java提供了丰富的网络编程API,如java.net包中的Socket和ServerSocket类。ServerSocket用于监听客户端...

    java聊天室附加代理服务器(模拟)

    总结来说,"java聊天室附加代理服务器(模拟)"项目是一个综合性的学习和实践案例,涵盖了Java网络编程、数据库操作、安全认证以及多线程技术。通过完成这个项目,开发者不仅可以深入理解相关技术,还能提升在实际...

    Java开发的邮件代理服务器

    Java开发的邮件代理服务器是一种基于Java编程语言实现的软件系统,它充当了用户与实际邮件服务器之间的中介。这种代理服务器的主要任务是处理电子邮件的发送、接收以及管理等操作,为用户提供更加便捷和安全的服务。...

    简单爬虫 Java实现 多线程

    本文将深入探讨如何使用Java实现一个简单的多线程爬虫,包括其核心概念、步骤以及相关的库和工具。 首先,我们需要了解爬虫的基本原理。爬虫是一种自动抓取网页内容的程序,通过模拟浏览器发送HTTP请求到服务器,...

    JAVA代理服务器

    总的来说,Java代理服务器的实现涉及到网络编程、HTTP协议理解和多线程处理等多个方面,是一个很好的学习和实践Java技术的项目。你可以通过分析和修改提供的"JAVA实现代理服务器"源码,进一步提升你的网络编程技能。

    http代理服务器的实现(程序).rar

    综上所述,HTTP代理服务器的实现涉及网络编程、多线程、安全性和性能优化等多个技术领域。使用PHP、VB或Java等编程语言,可以灵活地构建符合需求的代理服务器系统。在毕业设计或论文中,这些技术和实践的深入探讨将...

    支持多线程的SFTP类代码

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

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

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

    http代理服务器的实现(程序).zip

    本篇将详细介绍HTTP代理服务器的工作原理及其在C、C++和Java中的实现方法。 HTTP代理服务器的核心任务是接收来自客户端的HTTP请求,解析请求内容,然后转发到目标Web服务器,并将服务器响应回传给客户端。这一过程...

Global site tag (gtag.js) - Google Analytics