灯火互联
管理员
管理员
  • 注册日期2011-07-27
  • 发帖数41778
  • QQ
  • 火币41290枚
  • 粉丝1086
  • 关注100
  • 终身成就奖
  • 最爱沙发
  • 忠实会员
  • 灌水天才奖
  • 贴图大师奖
  • 原创先锋奖
  • 特殊贡献奖
  • 宣传大使奖
  • 优秀斑竹奖
  • 社区明星
阅读:3618回复:0

简单的java版http代理

楼主#
更多 发布于:2013-01-10 15:32
为了说明http代理的工作机制,我特意写了一个最简单的代理,去掉很多繁杂的功能,并尽可能的使代码量小,源码如下,不清楚http代理机制的朋友参考一下基本就明白了。
 
[java]  
/*
 * $RCSfile: SimpleHttpProxy.java,v $$
 * $Revision: 1.1 $
 * $Date: 2013-1-9 $
 *
 * Copyright (C) 2008 Skin, Inc. All rights reserved.
 *
 * This software is the proprietary information of Skin, Inc.
 * Use is subject to license terms.
 */  
package test.com.skin.http.proxy;  
  
import java.io.ByteArrayOutputStream;  
import java.io.IOException;  
import java.io.InputStream;  
import java.io.OutputStream;  
import java.net.ServerSocket;  
import java.net.Socket;  
import java.net.SocketTimeoutException;  
import java.net.URL;  
  
/**
 * <p>Title: SimpleHttpProxy</p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2006</p>
 * @author xuesong.net
 * @version 1.0
 */  
public class SimpleHttpProxy  
{  
    public static final int PORT = 6666;  
    public static final byte[] CRLF = new byte[]{0x0D, 0x0A};  
  
    /**
     * @param args
     */  
    public static void main(String[] args)  
    {  
        ServerSocket socketServer = null;  
  
        try  
        {  
            socketServer = new ServerSocket(PORT);  
  
            while(true)  
            {  
                try  
                {  
                    final Socket socket = socketServer.accept();  
  
                    (new Thread(){  
                        public void run(){  
                            SimpleHttpProxy.service(socket);  
                        }  
                    }).start();  
                }  
                catch(SocketTimeoutException e)  
                {  
                    e.printStackTrace();  
                }  
                catch(IOException e)  
                {  
                    e.printStackTrace();  
                }  
            }  
        }  
        catch(Exception e)  
        {  
            e.printStackTrace();  
        }  
        finally  
        {  
            if(socketServer != null)  
            {  
                try  
                {  
                    socketServer.close();  
                }  
                catch(IOException e)  
                {  
                }  
            }  
        }  
    }  
  
    private static void service(Socket socket)  
    {  
        Socket remote = null;  
  
        try  
        {  
            socket.setSoTimeout(2000);  
            socket.setKeepAlive(false);  
            InputStream inputStream = socket.getInputStream();  
            OutputStream outputStream = socket.getOutputStream();  
              
            /**
             * 读取协议头的第一行
             * 格式: GET http://www.mytest.com HTTP/1.1
             */  
            byte[] buffer = readLine(inputStream);  
  
            if(buffer.length < 1)  
            {  
                return;  
            }  
  
            String header = new String(buffer, "UTF-8");  
            String[] action = header.split(" ");  
  
            if(action.length < 3)  
            {  
                return;  
            }  
  
            String address = action[1];  
  
            /**
             * 目标地址是从http协议的第一行取
             * 目标主机应该从协议的Host头里面取,如果Host取不到, 从地址里面取
             * 此处为了简化逻辑只从地址里面取host, 因此如果路径不是绝对路径就忽略
             */  
            if(address.startsWith("http://") == false)  
            {  
                return;  
            }  
  
            System.out.print(header);  
  
            URL url = new URL(address);  
            String host = url.getHost();  
            int port = (url.getPort() > -1 ? url.getPort() : 80);  
  
            remote = new Socket(host, port);  
            InputStream remoteInputStream = remote.getInputStream();  
            OutputStream remoteOutputStream = remote.getOutputStream();  
  
            /**
             * 某些服务器对协议头必须一次性读完, 例如qq空间
             * 因此此处先读出协议头, 并且一次写入, 写入之后必须flush
             * 否则就跳转到QQ首页了
             */  
            long contentLength = -1L;  
            ByteArrayOutputStream bos = new ByteArrayOutputStream();  
            bos.write(buffer, 0, buffer.length);  
  
            /**
             * 读取协议头
             * 也可以不读取协议头, 而是直接把inputStream写入到remoteOutputStream
             * 为了兼容某些服务器, 此处简单的读取一下协议头
             */  
            while((buffer = readLine(inputStream)).length > 0)  
            {  
                header = new String(buffer, "UTF-8").trim();  
  
                if(header.length() < 1)  
                {  
                    break;  
                }  
  
                if(header.startsWith("Content-Length:"))  
                {  
                    try  
                    {  
                        contentLength = Long.parseLong(header.substring(15).trim());  
                    }  
                    catch(NumberFormatException e){}  
                }  
  
                bos.write(buffer, 0, buffer.length);  
            }  
  
            /** 协议头和主体之间的空行 */  
            bos.write(CRLF);  
            remoteOutputStream.write(bos.toByteArray());  
            remoteOutputStream.flush();  
  
            /** 如果存在contentLength */  
            if(contentLength > 0)  
            {  
                copy(inputStream, remoteOutputStream, 4096, contentLength);  
            }  
  
            try  
            {  
                /**
                 * 将目标主机返回的数据写入到客户端
                 * 此处应该检查一下Content-Length, 并且根据Content-Length来决定要写入多少数据
                 * 不过很多服务器经常会不返回Content-Length,
                 * 没有Content-Length, read函数会一直读取
                 * 因此使用timeout来解决阻塞的问题
                 * 超时的时候自动退出线程, 否则该线程就无法释放了
                 */  
                remote.setSoTimeout(10000);  
                copy(remoteInputStream, outputStream, 4096);  
            }  
            catch(SocketTimeoutException e)  
            {  
            }  
            catch(Exception e)  
            {  
                e.printStackTrace();  
            }  
        }  
        catch(Exception e)  
        {  
            e.printStackTrace();  
        }  
        finally  
        {  
            try  
            {  
                if(socket != null)  
                {  
                    socket.close();  
                }  
            }  
            catch(IOException e)  
            {  
            }  
  
            try  
            {  
                if(remote != null)  
                {  
                    remote.close();  
                }  
            }  
            catch(IOException e)  
            {  
                e.printStackTrace();  
            }  
        }  
    }  
  
    public static byte[] readLine(InputStream stream) throws IOException  
    {  
        int b = -1;  
        ByteArrayOutputStream bos = new ByteArrayOutputStream(2048);  
  
        while((b = stream.read()) != -1)  
        {  
            if(b == '\n')  
            {  
                bos.write(b);  
                break;  
            }  
  
            bos.write(b);  
        }  
  
        return bos.toByteArray();  
    }  
  
    public static void copy(InputStream inputStream, OutputStream outputStream, int bufferSize) throws IOException  
    {  
        int length = 0;  
        byte[] buffer = new byte[bufferSize];  
  
        while((length = inputStream.read(buffer, 0, bufferSize)) > -1)  
        {  
            outputStream.write(buffer, 0, length);  
        }  
  
        outputStream.flush();  
    }  
  
    public static void copy(InputStream inputStream, OutputStream outputStream, int bufferSize, long size) throws IOException  
    {  
        if(size > 0)  
        {  
            int readBytes = 0;  
            long count = size;  
            int length = Math.min(bufferSize, (int)(size));  
            byte[] buffer = new byte[length];  
  
            while(count > 0)  
            {  
                if(count > length)  
                {  
                    readBytes = inputStream.read(buffer, 0, length);  
                }  
                else  
                {  
                    readBytes = inputStream.read(buffer, 0, (int)count);  
                }  
  
                if(readBytes > 0)  
                {  
                    outputStream.write(buffer, 0, readBytes);  
                    count -= readBytes;  
                }  
                else  
                {  
                    break;  
                }  
            }  
  
            outputStream.flush();  
        }  
    }  
}  

喜欢0 评分0
游客

返回顶部