动态ip

>

代理ip软件

>

换ip软件

>

HTTP代理

>
Socks5代理
黑核动态ip代理
您的位置: 首页 > 新闻资讯 > 正文

HTTP代理服务器的实现

发布时间:2019-06-11 09:42:32 来源:黑核动态ip代理

分享到

  HTTP代理服务(proxy server) 器就是客户端也是服务端,是一个事务处理的中间人,就像下图所展示的一样。

HTTP代理服务器的实现

  图片来源于《HTTP权威指南》

  代理服务器的作用有很多,例如:儿童过滤器、文档访问控制、安全防火墙、web缓存等等。

  以下,我用最基础的代码写一个简易的HTTP代理服务器,最后还有相关的解说,有助于更容易理解HTTP代理服务器的机制。


package testproxy;

import java.lang.reflect.Constructor;

import java.net.*;

import java.io.*;

public class TextHttpProxy extends Thread {


    //操作实现代理服务器的类

    static public int RETRIES = 5;

    //在放弃之前尝试连接远程主机的次数

    static public int PAUSE = 5;

    //在两次连接尝试之间的暂停时间

    static public int TIMEOUT = 50;

    //等待Socket输入的等待时间

    static public int BUFSIZ = 1024;

    //输入的缓冲大小

    static public boolean logging = false;

    //是否要求代理服务器在日志中记录所有已传输的数据

    static public OutputStream log = null;

    //默认日志例程将向该OutputStream对象输出日志信息

    protected Socket socket;

    // 传入数据用的Socket

    static private String parent = null;

    //上级代理服务器

    static private int parentPort = -1;

    //  用来把一个代理服务器链接到另一个代理服务器(需要指定另一个服务器的名称和端口)。  

    static public void setParentProxy(String name, int port) {


        parent = name;

        parentPort = port;


    }

    public TextHttpProxy(Socket s) {


        //创建一个代理线程

        socket = s;

        start();

        //启动线程


    }

    public void writeLog(int c, boolean browser) throws IOException {


        //写日志

        log.write(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 String printLog(String url, String host, int port, Socket sock) {


        java.text.DateFormat cal = java.text.DateFormat.getDateTimeInstance();

        System.out.println(cal.format(new java.util.Date()) + " - " + url + " "

                + sock.getInetAddress() + "\n");

        return host;


    }

    public void run() {


        // 执行操作的线程

        String line;

        String host;

        int port = 80;

        //默认端口为80

        Socket outbound = null;

        //每次请求都会创建一个新的线程

        try {


            socket.setSoTimeout(TIMEOUT);

            //设置超时时间

            InputStream is = socket.getInputStream();

            //创建输入流

            OutputStream os = null;

            try {


                line = "";

                // 获取请求行的内容

                host = "";

                int state = 0;

                boolean space;

                while (true) {


                    //无限循环

                    int c = is.read();

                    //读取输入流的信息

                    if (c == -1)//没有读取信息

                        break;

                    if (logging)

                        writeLog(c, true);

                    //将信息写入日志

                    space = Character.isWhitespace((char) c);

                    //判断是否为空白字符

                    switch (state) {


                    //判断状态

                    case 0:

                        if (space)

                            continue;

                        //跳过本次循环

                        state = 1;

                        //更改状态

                    case 1:

                        if (space) {


                            state = 2;

                            continue;

                            //跳过本次循环


                        }

                        line = line + (char) c;

                        //添加读取的信息

                        break;

                    case 2:

                        if (space)

                            continue; 

                        // 跳过空白字符

                        state = 3;

                        //更改状态

                    case 3:

                        if (space) {


                            //如果是空白字符

                            state = 4;

                            //更改状态

                            String host0 = host;

                            //取出网址

                            int n;

                            n = host.indexOf("//");

                            //获取网址(不包括协议)

                            if (n != -1)

                                //没有找到

                                host = host.substring(n + 2);

                            n = host.indexOf('/');

                            if (n != -1)

                                //没有找到/

                                host = host.substring(0, n);

                            n = host.indexOf(":");

                            // 分析可能存在的端口号

                            if (n != -1) {


                                //没有找到:

                                port = Integer.parseInt(host.substring(n + 1));

                                host = host.substring(0, n);


                            }

                            host = printLog(host0, host, port, socket);

                            //获得网站域名


                            if (parent != null) {


                                host = parent;

                                port = parentPort;


                            }

                            int retry = RETRIES;

                            while (retry-- != 0) {


                                try {


                                    outbound = new Socket(host, port);

                                    //创建连接对象,通向目标服务器

                                    break;


                                } catch (Exception e) {


                                    System.out.println("无法创建连接:"+e.getMessage());


                                }

                                Thread.sleep(PAUSE);

                                //设置线程等待


                            }

                            if (outbound == null)

                                break;

                            outbound.setSoTimeout(TIMEOUT);

                            //设置超时时间,防止read方法导致的组赛

                            os = outbound.getOutputStream();

                            //获得输出流对象

                            os.write(line.getBytes());

                            //将信息写入流

                            os.write(' ');

                            os.write(host0.getBytes());

                            //将信息写入流

                            os.write(' ');

                            writeInfo(is, outbound.getInputStream(), os, socket

                                    .getOutputStream());

                            //调用方法将信息写入日志,套接字数据的交换

                            break;


                        }

                        host = host + (char) c;

                        break;


                    }


                }


            } catch (IOException e) {


            }


        } catch (Exception e) {


        } finally {


            try {


                socket.close();

                //释放资源


            } catch (Exception e1) {


            }

            try {


                outbound.close();


            } catch (Exception e2) {


            }

        }

    }

    void writeInfo(InputStream is0, InputStream is1, OutputStream os0,

            OutputStream os1) throws IOException {


        //读取流中信息写入日志

        try {


            int ir;

            byte bytes[] = new byte[BUFSIZ];

            //创建字节数组,大小:1024

            //也是定影socket缓冲区的大小

            while (true) {


                try {


                    if ((ir = is0.read(bytes)) > 0) {


                        //判断读取输入流的信息

                        os0.write(bytes, 0, ir);

                        //将读取的数据写入输出流对象中


                        if (logging)

                            writeLog(bytes, 0, ir, true);

                        //写入日志


                    } else if (ir < 0)

                        //读取完毕

                        break;

                } catch (InterruptedIOException e) {


                    //捕获中断IO流异常


                }

                try {


                    if ((ir = is1.read(bytes)) > 0) {


                        //判断读取输入流的信息

                        os1.write(bytes, 0, ir);

                        //将读取的数据写入输出流对象中

                        if (logging)

                            writeLog(bytes, 0, ir, false);

                        //写入日志


                    } else if (ir < 0)

                        //读取完毕

                        break;


                } catch (InterruptedIOException e) {


                    //捕获中断IO流异常


                }

            }

        } catch (Exception e0) {


            //捕获异常

        }

    }



    static public void proxyStart(int port, Classclobj) {


        ServerSocket serverSocket;

        try {


            serverSocket = new ServerSocket(port);

            //根据端口创建服务器端Socket对象

            while (true) {


                Class[] objClass = new Class[1];

                //创建类数组,大小为1

                Object[] obj = new Object[1];

                //创建对象数组,大小为1

                objClass[0] = Socket.class;

                //添加Socket类

                try {


                    Constructor cons = clobj.getDeclaredConstructor(objClass);

                    //创建代理服务器实例

                    obj[0] = serverSocket.accept();

                    //挂起等待客户的请求

                    cons.newInstance(obj); 

                    // 创建TextHttpProxy或其派生类的实例  创建传入类


                } catch (Exception e) {


                    Socket socket = (Socket) obj[0];

                    //对象强制转换

                    try {


                        socket.close();

                        //释放资源


                    } catch (Exception ec) {


                    }


                }


            }


        } catch (IOException e) {


        }

    }

    static public void main(String args[]) {


        System.out.println("HTTP代理服务器已经成功启动!");

        TextHttpProxy.log = System.out;

        //日志信息输出到控制台

        TextHttpProxy.logging = false;

        TextHttpProxy.proxyStart(9080, TextHttpProxy.class);


        //调用方法

    }


}


  代码解说:

  开启一个服务器Socket 监听指定端口的请求,同时,代理服务器挂起等待客户端的请求。服务器的Socket监听到连接请求时,则开启一个新的线程处理这个连接请求,服务器的Socket 再次进入监听状态。

  在连接线程时,代理服务器接受来自客户端的请求,并执行操作的线程,设置超时时间,解析客户端Host头域里面的值,获取目标web服务器地址,分析可能存在的端口号,建立socket将请求发送到远程服务器,然后将响应报文转发回原socket。最后把 socket 关闭,线程销毁。

  写一个简单的main方法来进行代理服务器测试,并将日志信息显示在控制台。

  代码解说图:

HTTP代理服务器的实现

  以下图片是测试效果:

  使用firefox浏览器,手动设置代理服务器

HTTP代理服务器的实现

  运行代码,开启代理服务器,输入HTTP协议的URI,如图

HTTP代理服务器的实现

  能进入这个网站,说明你的代理成功了!

  在控制台会输出以下信息

HTTP代理服务器的实现

  在这个实现HTTP代理服务器的过程中,socket 是非常重要的,它也叫做套接字。如下是它的作用:

  socket (套接字)之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。

  服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。

  客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。

  连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

  如果不太懂HTTP和socket之间的联系,那就用传说中的比喻来说说:HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。


相关资讯

互联网工作中ip代理是不可缺少的工具

目前,中国的互联网大军正在不断壮大,各种各样依托互联网的新兴行业正在兴起,哪怕是很多传统行业,为了抢占竞争的制高点,也将跟友商之间的竞争搬到了互联网平台之上。对

来源:黑核混拨ip加速器网

2018-12-27 17:45:23

IP加速器的使用方法和简单问题解决办法

IP加速器,顾名思义就是加速IP,提升网络性能,降低网络延迟。黑核混拨ip加速器是一款ip量大速度快的加速器,非游戏外挂,可以放心使用。IP加速器的客户端设置简

来源:黑核混拨ip加速器网

2018-12-28 10:21:44

操作简单又实用的IP加速器

怎么才能自动修改电脑IP地址,有时注册一个账号需要改IP地址才能注册,那么怎么修改电脑的IP地址呢,如果能自动的切换自己网络IP地址?这时候需要用到换ip工具,

来源:黑核混拨ip加速器网

2018-12-28 11:52:51

现在采集越来越难如何找到实用的HTTP代理IP

目前,中国的互联网大军正在不断壮大,各种各样依托互联网的新兴行业正在兴起,哪怕是很多传统行业,为了抢占竞争的制高点,也将跟友商之间的竞争搬到了互联网平台之上。对

来源:黑核混拨ip加速器网

2018-12-28 15:56:10

国内好用又实惠的https代理ip服务器不要错过了

随着大数据时代的到来,爬虫已经成了获取数据的必不可少的方式,在使用爬虫多次爬取同一网站时,经常会被网站的IP反爬虫机制给禁掉,为了解决封禁IP的问题,通常会使用

来源:黑核混拨ip加速器网

2018-12-28 16:55:02

免费的代理ip软件能用吗?

很多网民朋友疑惑,市面中的免费爬虫代理IP到底安不安全?使用后会对自己造成威胁吗?其实大家有这些顾虑是正常的,小编在这里也不推荐使用免费代理IP。一、IP重复率

来源:黑核混拨ip加速器网

2018-12-28 17:34:12

这几招教你解决IP被封的问题

在爬虫时,我们不可避免的会遇到网页的反爬封锁,所以就有了爬虫的攻防,在攻和守之间两股力量不断的抗衡。接下来就讲讲使用爬虫时ip限制问题的六种方法!方法1.1.I

来源:黑核混拨ip加速器网

2018-12-28 17:47:52

代理ip软件能帮助你实现优化网站

如今代理IP工具在营销领域,无论是主动式的发布推广信息,还是被动性反制竞争对手的恶意点击来说,都具有不可替代的作用。可细心的人们发现市面上代理IP的软件太多,如

来源:黑核混拨ip加速器网

2019-01-08 17:54:51

实用https代理服务器别人能查到真实地址吗

现在,高匿代理ip时代已经到来,但是,还是有很多人不了解高匿代理ip到底有什么用,虽然随着网络科技的发展,网络对我们的生活带来了很多方便,也带来了更多的选择,网

来源:黑核混拨ip加速器网

2018-12-28 17:02:47

什么是ip代理软件?可以修改ip地址吗?

经常碰到朋友问,代理IP是做啥的,有什么用。我对他一顿解释,然后他还是云里雾里,好吧,可能是我口才不好,这里写文再解释下。代理IP对于很多人来说,用处很大,他们

来源:黑核混拨ip加速器网

2018-12-27 17:27:18

在线客服
大客户VIP渠道
点击这里给我发消息
讨论QQ群
客服电话
13318873961