Java中的代理原理及代理使用示例

今天再测试Socket编程时,无法连接外网。公司用的是Http的代理。上网搜索也没看太懂,所以花了大量时间来学习。看了HTTP和TCP协议的关系好,才有所明白。现在能通过Socket使用HTTP代理了,结果很简单,过程却好难。

1. 先简要说说HTTP和TCP(具体内容自行Google,资料很多很全),这里就讲讲要点:

HTTP:是应用层协议,是基于传输层协议的。

TCP: 是传输层协议,是基于网络层协议的。

IP: 是网络层协议。

一个TCP的连接要进行三次握手(就像转户口一样,不详说),HTTP只是一个应用协议,也就是相当于一个自定义协议,即其没有对底层的传输方式进行干涉,只是对数据内容格式进行了定义。打个比方,别人说“SB”(你的名字),你回答“是”,仅仅是内容格式,没有改变声音的传输方式(通过声波传送<网络硬件介质>,通过双方都能听懂的语言<TCP/IP>)。同理,FTP, Telnet也是一种应用层协议,打个比方对于FTP,别人说“SB",你回答“哎”,只是格式内容不同而已。

2. 认识到以上之后,我们再说说HTTP代理,从上可以理解,HTTP代理服务器就是这样一台机器:你把所有的HTTP请求(不管是想请求百度还是Google)都发到这个HTTP代理服务器,然后这个HTTP代理服务器请求你要访问的最终地址,把响应回传给你。这里还要注意它代理的是HTTP协议,而HTTP又是基于TCP的,也就是说这个服务器代理的是指定HTTP内容格式的TCP连接。再说下去也没意思了,看以下代码:

代码如下:

//以下地址是代理服务器的地址 
Socket socket = new Socket("10.1.2.188", 80); 
//写与的内容就是遵循HTTP请求协议格式的内容,请求百度 
socket.getOutputStream().write(new String("GET http://www.baidu.com/ HTTP/1.1\r\n\r\n").getBytes()); 
byte[] bs = new byte[1024]; 
InputStream is = socket.getInputStream(); 
int i; 
while ((i = is.read(bs)) > 0) { 
    System.out.println(new String(bs, 0, i)); 

is.close();

当然在Java中,有Proxy代理上网的使用,此时使用URL(HTTP)就不涉及Socket(TCP)了,看如下代码

代码如下:

//设置代理 
System.setProperty("http.proxySet", "true"); 
System.setProperty("http.proxyHost", "10.1.2.188"); 
System.setProperty("http.proxyPort", "80"); 
 
//直接访问目的地址 
URL url = new URL("http://www.baidu.com"); 
URLConnection con = url.openConnection(); 
InputStreamReader isr = new InputStreamReader(con.getInputStream()); 
char[] cs = new char[1024]; 
int i = 0; 
while ((i = isr.read(cs)) > 0) { 
    System.out.println(new String(cs, 0, i)); 

isr.close();

最后总结一下:

在使用HTTP代理的环境中,

如果使用Socket(TCP)连接外网,则直接连接代理服务器,然后在发送的HTTP请求中指明要转发到的外网网址。

如果使用URL(HTTP)连接外网,则需要设置HTTP代理参数或使用Proxy。

OK,明白以后可以随意使用了,看以下代码,使用NIO的Socket通过HTTP代理访问外网的例子:

代码如下:

SocketChannel sc = SocketChannel.open(new InetSocketAddress("10.1.2.188", 80)); 
 
sc.write(Charset.forName("utf8").encode("GET http://www.baidu.com/ HTTP/1.1\r\n\r\n")); 
 
ByteBuffer buffer = ByteBuffer.allocate(1024); 
 
while (sc.read(buffer) != -1) { 
    buffer.flip(); 
    System.out.println(Charset.forName("utf8").decode(buffer)); 
    buffer.clear(); 

sc.close();

Java Socket编程中加入代理示例

有些时候我们的网络不能直接连接到外网, 需要使用http或是https或是socket代理来连接到外网, 这里是java使用代理连接到外网的一些方法,:方法一使用系统属性来完成代理设置, 这种方法比较简单, 但是不能对单独的连接来设置代理:

代码如下:

public static void main(String[] args) {
        Properties prop = System.getProperties();
        // 设置http访问要使用的代理服务器的地址
        prop.setProperty("http.proxyHost", "192.168.0.254");
        // 设置http访问要使用的代理服务器的端口
        prop.setProperty("http.proxyPort", "8080");
        // 设置不需要通过代理服务器访问的主机,可以使用*通配符,多个地址用|分隔
        prop.setProperty("http.nonProxyHosts", "localhost|192.168.0.*");
        // 设置安全访问使用的代理服务器地址与端口
        // 它没有https.nonProxyHosts属性,它按照http.nonProxyHosts 中设置的规则访问
        prop.setProperty("https.proxyHost", "192.168.0.254");
        prop.setProperty("https.proxyPort", "443");
        // 使用ftp代理服务器的主机、端口以及不需要使用ftp代理服务器的主机
        prop.setProperty("ftp.proxyHost", "192.168.0.254");
        prop.setProperty("ftp.proxyPort", "2121");
        prop.setProperty("ftp.nonProxyHosts", "localhost|192.168.0.*");
        // socks代理服务器的地址与端口
        prop.setProperty("socksProxyHost", "192.168.0.254");
        prop.setProperty("socksProxyPort", "8000");
        // 设置登陆到代理服务器的用户名和密码
        Authenticator.setDefault(new MyAuthenticator("userName", "Password"));
    }
    static class MyAuthenticator extends Authenticator {
        private String user = "";
        private String password = "";
        public MyAuthenticator(String user, String password) {
            this.user = user;
            this.password = password;
        }
        protected PasswordAuthentication getPasswordAuthentication() {
            returnnew PasswordAuthentication(user, password.toCharArray());
        }
    }

方法二使用Proxy来对每个连接实现代理, 这种方法只能在jdk 1.5以上的版本使用(包含jdk1.5), 优点是可以单独的设置每个连接的代理, 缺点是设置比较麻烦:

代码如下:

public static void main(String[] args) {
        try {
            URL url = new URL("http://www.baidu.com");
            // 创建代理服务器
            InetSocketAddress addr = new InetSocketAddress("192.168.0.254",
                    8080);
            // Proxy proxy = new Proxy(Proxy.Type.SOCKS, addr); // Socket 代理
            Proxy proxy = new Proxy(Proxy.Type.HTTP, addr); // http 代理
            // 如果我们知道代理server的名字, 可以直接使用
            // 结束
            URLConnection conn = url.openConnection(proxy);
            InputStream in = conn.getInputStream();
            // InputStream in = url.openStream();
            String s = IOUtils.toString(in);
            System.out.println(s);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

(0)

相关推荐

  • 通过代理类实现java连接数据库(使用dao层操作数据)实例分享

    首先,我们在一个java文件中定义要存储的结构类型: 复制代码 代码如下: import java.util.Date ;/** * * @author Nero */public class Emp {    private int empno ;    private String ename ;    private String job ;    private Date hiredate ;    private float sal ;    public void setEmpno(

  • 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 java.net.ServerS

  • java实现动态代理方法浅析

    一些Java项目中在mybatis与spring整合中有MapperScannerConfigurer的使用,该类通过反向代理自动生成基于接口的动态代理类. 有鉴于此,本文浅析了java的动态代理. 本文使用动态代理模拟处理事务的拦截器. 接口: public interface UserService { public void addUser(); public void removeUser(); public void searchUser(); } 实现类: public class

  • java利用反射实现动态代理示例

    复制代码 代码如下: package com.et59.cus.domain.dao.ex; import java.lang.reflect.Field;import java.lang.reflect.Method;import java.lang.reflect.Modifier; import org.apache.log4j.Logger;/** *  * <p>Title: ReflectUtil.java</p> * <p>Description: 反射&

  • Java中的引用和动态代理的实现详解

    我们知道,动态代理(这里指JDK的动态代理)与静态代理的区别在于,其真实的代理类是动态生成的.但具体是怎么生成,生成的代理类包含了哪些内容,以什么形式存在,它为什么一定要以接口为基础? 如果去看动态代理的源代码(java.lang.reflect.Proxy),会发现其原理很简单(真正二进制类文件的生成是在本地方法中完成,源代码中没有),但其中用到了一个缓冲类java.lang.reflect.WeakCache<ClassLoader,Class<?>[],Class<?>

  • Java中注解与原理分析详解

    目录 一.注解基础 二.注解原理 三.常用注解 1.JDK注解 2.Lombok注解 四.自定义注解 1.同步控制 2.类型引擎 一.注解基础 注解即标注与解析,在Java的代码工程中,注解的使用几乎是无处不在,甚至多到被忽视: 无论是在JDK源码或者框架组件,都在使用注解能力完成各种识别和解析动作:在对系统功能封装时,也会依赖注解能力简化各种逻辑的重复实现: 基础接口 在Annotation的源码注释中有说明:所有的注解类型都需要继承该公共接口,本质上看注解是接口,但是代码并没有显式声明继承关

  • Java中synchronized实现原理详解

    记得刚刚开始学习Java的时候,一遇到多线程情况就是synchronized,相对于当时的我们来说synchronized是这么的神奇而又强大,那个时候我们赋予它一个名字"同步",也成为了我们解决多线程情况的百试不爽的良药.但是,随着我们学习的进行我们知道synchronized是一个重量级锁,相对于Lock,它会显得那么笨重,以至于我们认为它不是那么的高效而慢慢摒弃它. 诚然,随着Javs SE 1.6对synchronized进行的各种优化后,synchronized并不会显得那么

  • Java中死锁的原理实战分析

    本文实例讲述了Java中死锁的原理.分享给大家供大家参考,具体如下: 一 点睛 当两个线程相互等待对方释放同步监视器时就会发生死锁,Java虚拟机没有监测.也没有采用措施来处理死锁情况,所以多线程编程时应该采取措施避免死锁的出现. 一旦出现死锁,整个程序既不会发生任何异常,也不会给出任何提示,只是所有线程处于阻塞状态,无法继续. 二 代码 class A { public synchronized void foo( B b ) { System.out.println("当前线程名: &quo

  • java中Base64编码原理实例讲解

    什么是 Base64 编码 Base64 编码是最常见的编码方式,基于 64 个可打印字符来表示任意二进制数据的方法,是从二进制转换到可见字符的过程. 使用场景 数据加密或签名通过 Base64 转换为字符串存储或传输. 不能传输文件的网络环境可以转换 Base64 进行网络传输. 在文本资源(如 HTML 和 CSS文件)中嵌入图片文件或其他二进制资源. 在 URL.网页中传输少量二进制数据等等. Base64 编码原理 原理是把每 3 个字节(每个字节为 8 位, 3 个字节为 24 位)重

  • java中fork-join的原理解析

    ForkJoinTask就是ForkJoinPool里面的每一个任务.他主要有两个子类:RecursiveAction和RecursiveTask.然后通过fork()方法去分配任务执行任务,通过join()方法汇总任务结果, 这就是整个过程的运用.他有两个子类,使用这两个子类都可以实现我们的任务分配和计算. (1)RecursiveAction 一个递归无结果的ForkJoinTask(没有返回值) (2)RecursiveTask 一个递归有结果的ForkJoinTask(有返回值) For

  • java中TESTful架构原理分析

    目录 1. 什么是REST 2. 理解RESTful 2. 1 资源与URI 2. 2 统一资源接口 GET POST PUT DELETE 2. 3 资源的表述 在URI里边带上版本号 使用URI后缀来区分表述格式 如何处理不支持的表述格式 2. 4 资源的链接 2. 5 状态的转移 2. 5.1 应用状态与资源状态 2. 5.2 应用状态的转移 3. 总结 1. 什么是REST REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征

  • GC参考手册二java中垃圾回收原理解析

    内存碎片整理 每次执行清除(sweeping), JVM 都必须保证不可达对象占用的内存能被回收重用.但这(最终)有可能会产生内存碎片(类似于磁盘碎片), 进而引发两个问题: 写入操作越来越耗时, 因为寻找一块足够大的空闲内存会变得非常麻烦. 在创建新对象时, JVM在连续的块中分配内存.如果碎片问题很严重, 直至没有空闲片段能存放下新创建的对象,就会发生内存分配错误(allocation error). 要避免这类问题,JVM 必须确保碎片问题不失控.因此在垃圾收集过程中, 不仅仅是标记和清除

  • 浅析Java中的SPI原理

    在面向对象的程序设计中,模块之间交互采用接口编程,通常情况下调用方不需要知道被调用方的内部实现细节,因为一旦涉及到了具体实现,如果需要换一种实现就需要修改代码,这违反了程序设计的"开闭原则".所以我们一般有两种选择:一种是使用API(Application Programming Interface),另一种是SPI(Service Provider Interface),API通常被应用程序开发人员使用,而SPI通常被框架扩展人员使用. 在进入下面学习之前,我们先来再加深一下API和

  • Java中的HashSet详解和使用示例_动力节点Java学院整理

    第1部分 HashSet介绍 HashSet 简介 HashSet 是一个没有重复元素的集合. 它是由HashMap实现的,不保证元素的顺序,而且HashSet允许使用 null 元素. HashSet是非同步的.如果多个线程同时访问一个哈希 set,而其中至少一个线程修改了该 set,那么它必须 保持外部同步.这通常是通过对自然封装该 set 的对象执行同步操作来完成的.如果不存在这样的对象,则应该使用 Collections.synchronizedSet 方法来"包装" set.

随机推荐