【java】解析java网络
目录结构:
1. 模拟Post与Get请求
首先使用java来模拟Http的Post和Get请求。
Post请求:
/**
* 向指定URl发送Post请求
* @param url 发送请求的url
* @param para 请求参数,格式应该满足name1=value1&name2=value2的形式
* @return 远程资源的响应
*/
public static String sendPost(String url,String para){
String result="";
PrintWriter out=null;
BufferedReader in=null;
try{
URL realUrl=new URL(url);
//打开和URL之间的连接
HttpURLConnection conn=(HttpURLConnection)realUrl.openConnection();
//设置请求方法
conn.setRequestMethod("POST");
//设置通用的请求属性
conn.setRequestProperty("accept", "*/*");//接收数据的格式
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");//请求数据的格式
conn.setRequestProperty("connection", "Keep-Alive");//长连接
conn.setRequestProperty("user-agent","Mozilla/4.0 (Compatible;MSIE 6.0;Windows NT 5.1;SV1)");
//发送Post必须设置如下两行
conn.setDoInput(true);
conn.setDoOutput(true);
//获取URLConnection对象对应的输出流
out=new PrintWriter(conn.getOutputStream());
//发送请求参数
out.print(para);
//flush输出流的缓冲
out.flush();
in=new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8"));
String line="";
while((line=in.readLine())!=null){
result+=line;
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(out!=null){
out.close();//关闭输出流
}
if(in!=null){
try {
in.close();//关闭输入流
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
Get请求:
/**
* 向指定URL发送Get请求
* @param url 发送请求的URL
* @param para 请求参数,格式应满足name1=value1&name2=value2的形式
* @return 远程资源的响应
*/
public static String sendGet(String url,String para){
String result="";
String realName=url+"?"+para;
BufferedReader br=null;
try{
URL realUrl=new URL(realName);
//打开和URL之间的连接
HttpURLConnection conn=(HttpURLConnection)realUrl.openConnection();
//设置通用的请求属性
conn.setRequestMethod("GET");
conn.setRequestProperty("accept", "*/*");//接收数据的格式
conn.setRequestProperty("connection", "Keep-Alive");//长连接
conn.setRequestProperty("user-agent","Mozilla/4.0 (Compatible;MSIE 6.0;Windows NT 5.1;SV1)");
//建立连接
conn.connect();
br=new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8"));
String line=null;
while((line=br.readLine())!=null){
result+=line;
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(br!=null){
try {
br.close();//关闭输入流
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
上面的两个方法中,笔者多次使用setRequestProperty方法,setRequestProperty方法是用于设置请求头信息(header)的,比如accept、content-type、connection等等。
但若读者尝试设置Authorization头信息和Proxy-Authorization头信息的话,将会无效。这是因为Authorization是一个安全特性,setRequestProperty对其做了屏蔽处理
那么如何设置Authorization头信息呢?在下面笔者将会详解介绍。
2.设置Authorization头信息
要设置Authorization头信息的话,可以使用http components-client 插件,点我前往下载。
笔者这里下载的是4.5.6的版本,下面展示一下如何在请求中设置header信息:
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder; public class HttpTest { public static void main(String[] args) throws Exception {
String uri=""; HttpClientBuilder builder=HttpClientBuilder.create();
CloseableHttpClient client=null;
CloseableHttpResponse response=null; try{
client= builder.build();
//get
HttpUriRequest httpUriRequest=new HttpGet(uri); //post
/*
HttpPost httpUriRequest= new HttpPost(uri);
String para="para1=value1¶2=value2";
HttpEntity httpRequestEntity=new ByteArrayEntity(para.getBytes(),
ContentType.create("application/x-www-form-urlencoded",Charset.forName("utf-8")));
httpUriRequest.setEntity(httpRequestEntity);
*/ //添加header参数
httpUriRequest.addHeader("Connection", "Keep-Alive");
httpUriRequest.addHeader("Accept", "*/*");
httpUriRequest.addHeader("Agent","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:62.0) Gecko/20100101 Firefox/62.0");
//添加 authorization 信息
httpUriRequest.addHeader("Authorization","my authorization info"); response= client.execute(httpUriRequest);
HttpEntity httpEntity= response.getEntity();
//获得响应流
InputStream inputStream=httpEntity.getContent();
//转化为BufferedReader
BufferedReader br=new BufferedReader(new InputStreamReader(inputStream,"utf-8"));
//打印
String line=null;
while((line=br.readLine())!=null){
System.out.println(line);
}
}catch(Exception e){
e.printStackTrace();
}finally{
//关闭
if(response!=null)
response.close();
if(client!=null)
client.close();
}
}
}
除了使用HttpClientBuilder还可以使用DefaultHttpClient,笔者测试发现HttpClientBuilder.build在Android6.0的环境下存在Bug,并不能成功创建CloseableHttpClient实例。
使用DefaultHttpClient提供了另外一种思路,例如:
//创建DefaultHttpClient
DefaultHttpClient client= new DefaultHttpClient(); HttpGet httpUriRequest=new HttpGet(urlPath);
//设置header信息... HttpResponse httpResponse= client.execute(httpUriRequest);
3. 基于TCP的网络编程
3.1 TCP协议简介
TCP的全称是Transmission Control Protocol (传输控制协议)
- 传输控制协议,是一种面向连接的协议,类似打电话
 - 在通信的整个过程中保持连接
 - 保证了数据传递的可靠性和有序性
 - 是一种全双工的字节流通信方式
 - 服务器压力比较大,资源消耗比较快,发送数据效率比较低
 - 点对点的传输协议
 
接下来笔者解释一下上面的几个概念:
面向连接的传输协议:面向连接,比如A打电话给B,如果B接听了,那么A和B之间就的通话,就是面向连接的。
可靠的传输协议:可靠的,一旦建立了连接,数据的发送一定能够到达,并且如果A说“你好吗?” B不会听到“吗你好”,这就是可靠地数据传输。
双全工的传输协议:全双工,这个理解起来也很简单,A打电话给B,B接听电话,那么A可以说话给B听,同样B也可以给A说话,不可能只允许一个人说话.。
点对点的传输协议:点对点,这个看了上面的举例相比大家都知道了,还要说一点的是,如果在A和B打电话过程中,B又来了一个紧急电话,那么B就要将与A的通话进行通话保持,所以不管怎么讲同一个连接只能是点对点的,不能一对多。
3.2 半关闭的Socket
通常情况下,我们都是以行作为通信的最小数据单元(虽然可以通过在行中添加特殊字符协议来达到传输多种数据的目的,但始终都是以行作为处理的最基本单元。)如果通信的数据单元是多行的,比如URLConnection来获取远程主机的数据,远程主机响应的内容就可能包含很多行数据。但在这种情况下应该考虑一个问题:Socket的输出流如何表示数据已经结束。
不同通过关闭输出流来表示输出结果已经完毕,因为关闭输出流时,对应的Socket也被关闭,这样就不能再从Socket中读取数据,这显然不是我们希望的。
Socket提供了输入两个半关闭的方法,只关闭Socket的输出流或输入流。
shutdownInput():关闭该Socket的输出流,程序还可以通过该Socket的输出流输出数据。
shutdownOutput():关闭该Socket的输出流,程序还可以通过该Socket的输入流输入数据。
当调用shutdownInput或shutdownOutput方法关闭Socket的输入流或输出流后,该Socket处于“半关闭”状态,Socket可以通过调用isInputShutDown()方法来判断该Socket是否处于半读状态,通过调用isOutputShutDown()来判断是否处于半写状态。
当一个Socket先用调用shutdownInput()和shutdownOutput()方法后,该Socket也没有被关闭,只是该Socket既不能读也不能写。
当调用Socket的shutdownInput()或shutdownOutput()方法关闭了输出流或输入流后,该Socket无法再次打开输出流和输入流,因此这种做法不适合保持持久通信的交互式应用,只适用于一站式通信协议,例如Http协议-客户端连接到服务端后,开始发送请求数据,发送完成后无需再次发送数据,只需要读取服务端响应数据即可,当读取响应完成后,该Socket也关闭了。
3.3 TCP长链接
CP协议中有长连接和短连接之分。短连接在数据包发送完成后就会自己断开,长连接在发包完毕后,会在一定的时间内保持连接,即我们通常所说的Keepalive(存活定时器)功能。
默认的Keepalive超时需要7,200,000 milliseconds,即2小时,探测次数为5次。它的功效和用户自己实现的心跳机制是一样的。开启Keepalive功能需要消耗额外的宽带和流量,尽管这微不足道,但在按流量计费的环境下增加了费用,另一方面,Keepalive设置不合理时可能会因为短暂的网络波动而断开健康的TCP连接。
keepalive并不是TCP规范的一部分。在Host Requirements RFC罗列有不使用它的三个理由:
(1)在短暂的故障期间,它们可能引起一个良好连接(good connection)被释放(dropped),
(2)它们消费了不必要的宽带,
(3)在以数据包计费的互联网上它们(额外)花费金钱。然而,在许多的实现中提供了存活定时器。
一些服务器应用程序可能代表客户端占用资源,它们需要知道客户端主机是否崩溃。存活定时器可以为这些应用程序提供探测服务。Telnet服务器和Rlogin服务器的许多版本都默认提供存活选项。
个人计算机用户使用TCP/IP协议通过Telnet登录一台主机,这是能够说明需要使用存活定时器的一个常用例子。如果某个用户在使用结束时只是关掉了电源,而没有注销(log off),那么他就留下了一个半打开(half-open)的连接。如果客户端消失,留给了服务器端半打开的连接,并且服务器又在等待客户端的数据,那么等待将永远持续下去。存活特征的目的就是在服务器端检测这种半打开连接。
也可以在客户端设置存活器选项,且没有不允许这样做的理由,但通常设置在服务器。如果连接两端都需要探测对方是否消失,那么就可以在两端同时设置(比如NFS)。
keepalive工作原理:
若在一个给定连接上,两小时之内无任何活动,服务器便向客户端发送一个探测段。(我们将在下面的例子中看到探测段的样子。)客户端主机必须是下列四种状态之一:
1) 客户端主机依旧活跃(up)运行,并且从服务器可到达。从客户端TCP的正常响应,服务器知道对方仍然活跃。服务器的TCP为接下来的两小时复位存活定时器,如果在这两个小时到期之前,连接上发生应用程序的通信,则定时器重新为往下的两小时复位,并且接着交换数据。
2) 客户端已经崩溃,或者已经关闭(down),或者正在重启过程中。在这两种情况下,它的TCP都不会响应。服务器没有收到对其发出探测的响应,并且在75秒之后超时。服务器将总共发送10个这样的探测,每个探测75秒。如果没有收到一个响应,它就认为客户端主机已经关闭并终止连接。
3) 客户端曾经崩溃,但已经重启。这种情况下,服务器将会收到对其存活探测的响应,但该响应是一个复位,从而引起服务器对连接的终止。
4) 客户端主机活跃运行,但从服务器不可到达。这与状态2类似,因为TCP无法区别它们两个。它所能表明的仅是未收到对其探测的回复。
服务器不必担心客户端主机被关闭然后重启的情况(这里指的是操作员执行的正常关闭,而不是主机的崩溃)。
当系统被操作员关闭时,所有的应用程序进程(也就是客户端进程)都将被终止,客户端TCP会在连接上发送一个FIN。收到这个FIN后,服务器TCP向服务器进程报告一个文件结束,以允许服务器检测这种状态。
在第一种状态下,服务器应用程序不知道存活探测是否发生。凡事都是由TCP层处理的,存活探测对应用程序透明,直到后面2,3,4三种状态发生。在这三种状态下,通过服务器的TCP,返回给服务器应用程序错误信息。(通常服务器向网络发出一个读请求,等待客户端的数据。如果存活特征返回一个错误信息,则将该信息作为读操作的返回值返回给服务器。)在状态2,错误信息类似于“连接超时”。状态3则为“连接被对方复位”。第四种状态看起来像连接超时,或者根据是否收到与该连接相关的ICMP错误信息,而可能返回其它的错误信息。
在TCP程序中,我经常需要确认客户端和服务端是否还保持者连接,这个时候有如下两种方案:
1.TCP连接双方定时发握手消息,并且在后面的程序中单独启线程,发送心跳信息。
2.利用TCP协议栈中的KeepAlive探测,也就是对TCP的连接的Socket设置KeepAlive。
在Java中利用下面的方法设置长连接:
setKeepAlive(boolean)
3.4 TCP编程案例
服务端:
- 创建ServerSocket的对象并且提供端口号, public ServerSocket(int port)
 - 等待客户端的请求连接,使用accept()方法, public Socket accept()
 - 连接成功后,使用Socket得到输入流和输入流,进行通信
 - 关闭相关资源
 
客户端:
- 创建Socket类型的对象,并且提供IP地址和端口号, public Socket(String host, int port)
 - 使用Socket构造输入流和输出流进行通信
 - 关闭相关资源
 
在服务端采用死循环,不停的监听连接来的请求,每当连接成功后,就开启一个线程去处理。
/*
* 在提供端口号的时候应该注意:最好定义在1024~49151。
*/
public class TestServerString {
public static void main(String[] args) {
try{
//1.创建ServerSocket类型的对象,并提供端口号
ServerSocket ss = new ServerSocket(8888);
//2.等待客户端的连接请求,使用accept()方法,保持阻塞状态
while(true){
System.out.println("等待客户端的连接请求...");
Socket s = ss.accept();
new ServerThread(s).start();
System.out.println("客户端连接成功!");
} }catch(Exception e){
e.printStackTrace();
}
}
}
在输入流和输出流中采用循环可客户端传输信息
public class ServerThread extends Thread{
    private Socket s;
    public ServerThread(Socket s){
        this.s=s;
    }
    @Override
    public void run(){
        try{
            BufferedReader br = new BufferedReader(
                    new InputStreamReader(s.getInputStream()));
            PrintStream ps = new PrintStream(s.getOutputStream());
            //编程实现服务器可以不断地客户端进行通信
            while(true){
                //服务器接收客户端发来的消息并打印
                String str = br.readLine();
                //当客户端发来"bye"时,结束循环
                if("bye".equalsIgnoreCase(str)) break;
                System.out.println(s.getLocalAddress()+":"+ str);
                //向客户端回发消息“I received!”
                ps.println("server received!");
            }
            //4.关闭相关的套接字
            ps.close();
            br.close();
            s.close();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}
在客户端中采用循环,可以让客户端与服务器建立一次连接,实现多次通信。
public class TestClientString {
    public static void main(String[] args) {
        try{
            //1.创建Socket类型的对象,并指定IP地址和端口号
            Socket s = new Socket("127.0.0.1", 8888);
            //2.使用输入输出流进行通信
            BufferedReader br = new BufferedReader(
                    new InputStreamReader(System.in));
            PrintStream ps = new PrintStream(s.getOutputStream());
            BufferedReader br2 = new BufferedReader(
                    new InputStreamReader(s.getInputStream()));
            //编程实现客户端不断地和服务器进行通信
            while(true){
                //提示用户输入要发送的内容
                System.out.println("请输入要发送的内容:");
                String msg = br.readLine();
                ps.println(msg);
                //当客户端发送"bye"时,结束循环
                if("bye".equalsIgnoreCase(msg)){
                    break;
                };
                //等待接收服务器的回复,并打印回复的结果
                String str2 = br2.readLine();
                System.out.println("服务器发来的消息是:" + str2);
            }
            //3.关闭Socket对象
            br2.close();
            br.close();
            ps.close();
            s.close();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}
在socket中有两个构造方法,值得提一下:
Socket(InetAddress address, int port)
使用这个构造方法,程序会自动绑定一个本地地址,并且在以后的连接中不会改变,如果需要在本地模拟多个客户端,那么就应该使用下面个构造方法。
下面这个构造方法,在连接到远程地址中可以指定本地地址和端口:
Socket(String host, int port, InetAddress localAddr, int localPort)
如果本地端口指定为0,那么系统将会自动选择一个空闲的端口绑定。
4. 基于UDP的网络编程
4.1 UDP协议简介
客户端:
- 创建DatagramSocket类型的对象,不需要提供任何信息, public DatagramSocket()
 - 创建DatagramPacket类型的对象,指定发送的内容、IP地址、端口号, public DatagramPacket(byte[] buf, int length, InetAddress address, int port)
 - 发送数据,使用send()方法, public void send(DatagramPacket p)
 - 关闭相关的资源
 
服务端:
- 创建DatagramSocket类型的对象,并且指定端口, public DatagramSocket(int port)
 - 创建DatagramPacket类型的对象,用于接收发来的数据, public DatagramPacket(byte[] buf, int length)
 - 接收数据,使用receive()方法, public void receive(DatagramPacket p)
 - 关闭相关资源
 
4.2 UDP编程案例
最开始的发送方:
public class UDPSender {
    public static void main(String[] args) {
        try{
        /*
         * create DatagramSocket instance
         */
        DatagramSocket ds=new DatagramSocket();
        //create DatagramPackage instance and specify the content to send ,ip address,port
        InetAddress ia=InetAddress.getLocalHost();
        System.out.println(ia.toString());
        String str="你好";
        byte[] data=str.getBytes();
        DatagramPacket dp=new DatagramPacket(data,data.length,ia,8888);
        //send data use send()
        ds.send(dp);
        //create DatagramPacket instance for receive
        byte []b2=new byte[1024];
        DatagramPacket dp2=new DatagramPacket(b2,b2.length);
        ds.receive(dp2);
        System.out.println("result:"+new String(data));
        //close resorce
        ds.close();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}
最开始的接受方:
public class UDPReceiver {
    public static void main(String[] args) {
        try{
        /*
         * create DatagramSocket instance,and support port
         */
        DatagramSocket ds=new DatagramSocket(8888);
        /*
         * create DatagramPackage instance for receive data
         */
        byte []data=new byte[1024];
        DatagramPacket dp=new DatagramPacket(data,data.length);
        /*
         * receive source
         */
        ds.receive(dp);
        System.out.println("contents are:"+new String(data,0,dp.getLength()));
        /*
         * send data
         */
        String str="I received!";
        byte[] b2=str.getBytes();
        DatagramPacket dp2=
                new DatagramPacket(b2,b2.length,dp.getAddress(),dp.getPort());
        ds.send(dp2);
        System.out.println("发送成功,ip:"+dp.getAddress());
        /*
         * close resource
         */
        }catch(SocketException e){
            e.printStackTrace();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}
5. 代理服务器
java5开始,java在java.net包下面提供了Proxy和ProxySelector两个类,其中Proxy代表一个代理服务器,可以在打开URLConnection连接时指定Proxy,创建Socket连接时也可以指定Proxy;而ProxySelector代表一个代理选择器,它提供了对代理服务器更加灵活的控制,它可以对HTTP、HTTPS、FTP、SOCKETS等分别进行设置。通过使用ProxySelector,可以实现像在Internet Explorer、Firefox等软件中设置代理服务器类似的效果。
代理服务器的功能是代理用户去取得网络信息。当使用浏览器连接其他Internet站点取得网络信息时,通常需要先发送请求,然后等待响应。代理服务器是介于浏览器和服务器之间的一台服务器,设置了代理服务器后,浏览器不是直接向Web服务器发送请求,而是向代理服务器发送请求,并取回浏览器需要的信息,再送回给浏览器。由于大部分代理服务器上都具有缓存功能,它会不断的将新取得的数据存储到代理服务器的本地存储器上,如果浏览器所请求的数据在本机存储上是最新的,就不需要更新,否则就更新。
代理服务器有如下两个功能:
a.突破自身IP限制,对外隐藏真实IP(代理的IP分为两中,透明的和高匿的,如果是透明的,在服务器端通过一些手段是可以获得真实的IP地址的,而高匿的一般不可以。)
b.提高访问速度,代理服务器提供的缓冲功能可以避免每个用户都直接访问远程主机,从而提供访问速度。
5.1 Proxy指定代理服务器
Proxy有一个构造器:Proxy(Proxy.Type type,SocketAddress sa),用于创建表示代理服务器的Proxy对象。其中sa参数指定代理服务器的地址,type表示代理服务器的类型,该服务器的类型有三种:
Proxy.Type.DIRECT:表示直接连接,不使用代理。
Proxy.Type.HTTP:表示支持高级协议代理,如Http和FTP
Proxy.Type.SOCKS:表示SOCKS代理(V4,V5)代理。
一旦创建了Proxy对象之后,程序就可以在使用URLConnection打开连接时,或创建Socket连接时传入一个Proxy对象,作为本次连接所使用的代理服务器。
下面的案例展示了,如何对Http请求设置代理:
public class Test {
    static String urlStr="xxx";//真实的访问地址
    static String proxyUrl="89.140.19.74";//有效代理的地址
    static int proxyPort=6080;//有效代理的端口
    public static void main(String[] args) throws Exception {
        URL url=new URL(urlStr);
        //创建一个代理服务器对象
        Proxy proxy=new Proxy(Proxy.Type.HTTP,new InetSocketAddress(proxyUrl,proxyPort));
        //使用指定的代理服务器打开连接
        HttpURLConnection hurl= (HttpURLConnection)url.openConnection(proxy);
        hurl.setConnectTimeout(60000);//设置超时时间
        InputStream ism= hurl.getInputStream();
        byte[] bytes=new byte[1024];
        ism.read(bytes);
        System.out.println(new String(bytes));
    }
}
关于查看可用的代理服务器地址和端口,读者可以参考如下这个网站:小幻Http代理
5.2 ProxySelector自动选择代理服务器
前面介绍的直接使用Proxy对象可以在打开URLConnection连接或Socket连接时指定代理服务器,但使用这种方式每次打开连接时都需要显式地指定的Proxy对象,如果希望每次打开时候都能有默认的代理服务器,那么可以使用ProxySelector来实现。
ProxySelector是一个抽象类,该类有两个方法:
List<Proxy> select(URI uri):根据业务需要返回代理服务器列表,如果该方法返回的列表只包含一个Proxy,该Proxy将作为默认的代理服务器。
connectFailed(URI uri,SocketAddress as,IOException ioe):连接代理服务器失败时回调该方法。
通过调用ProxySelector的setDefault(ProxySelector ps)静态方法来注册代理选择器。
例如:
public class Test {
    static String urlStr="xxx";//真实的访问地址
    static String proxyUrl="89.140.19.74";//有效代理的地址
    static int proxyPort=6080;//有效代理的端口
    public static void main(String[] args) throws Exception {
        //注册默认的代理服务器
        ProxySelector.setDefault(new ProxySelector() {
            @Override
            public List<Proxy> select(URI uri) {
                //总是返回Http请求的某个固定代理服务器
                Proxy proxy=new Proxy(Proxy.Type.HTTP,new InetSocketAddress(proxyUrl,proxyPort));
                List<Proxy> list=new ArrayList<Proxy>();
                list.add(proxy);
                return list;
            }
            @Override
            public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
                System.out.println("异常,无法连接到指定服务器:"+ioe.getMessage());
            }
        });
        URL url=new URL(urlStr);
        HttpURLConnection hurl= (HttpURLConnection)url.openConnection();
        hurl.setConnectTimeout(60000);//设置超时时间
        InputStream ism= hurl.getInputStream();
        byte[] bytes=new byte[1024];
        ism.read(bytes);
        System.out.println(new String(bytes));
    }
}
还可以通过改变系统默认的代理服务器来代理功能:
public static void main(String[] args) throws Exception {
        java.util.Properties props=System.getProperties();
        //通过系统设置Http访问所用的代理服务器的主机地址和端口
        props.setProperty("http.proxyHost", "89.140.19.74");
        props.setProperty("http.proxyPort", "6080");
        //通过系统属性设置HTTP访问无需使用代理服务器的主机
        //可以使用*表示通配符,多个地址使用|分割
        props.setProperty("http.nonProxyHosts","localhost|192.168.10.*");
        //通过系统属性设置HTTPS访问所使用的代理服务器的主机地址和端口
        props.setProperty("https.proxyHost", "89.140.19.75");
        props.setProperty("https.proxtPort", "6080");
        //通过系统属性设置FTP访问所使用的代理服务器的主机地址和端口
        props.setProperty("ftp.proxyHost", "89.140.19.76");
        props.setProperty("ftp.proxtPort", "6080");
        //通过系统属性设置ftp访问无需代理服务器的主机
        props.setProperty("ftp.nonProxyHosts", "localHost|192.168.1.*");
        //通过系统属性设置SOCKS代理服务器的主机地址
        props.setProperty("socks.ProxyHost", "89.140.19.77");
        props.setProperty("socks.proxtPort", "6080");
        ProxySelector selector=ProxySelector.getDefault();
        System.out.println("系统默认的代理服务器:"+selector);
        System.out.println("系统为ftp://89.140.19.74选择的代理服务器:"+selector.select(new URI("ftp://89.140.19.74")));
        URL url=new URL("www.xxx.com");
        HttpURLConnection hurl= (HttpURLConnection)url.openConnection();
        hurl.setConnectTimeout(60000);//设置超时时间
        InputStream ism= hurl.getInputStream();
        byte[] bytes=new byte[1024];
        ism.read(bytes);
        System.out.println(new String(bytes));
    }
运行上面的程序,可能会因为代理服务器的地址无效而报错,这时候需要重新找个一个合法的代理主机。
【java】解析java网络的更多相关文章
- 高性能Java解析器实现过程详解
		
如果你没有指定数据或语言标准的或开源的Java解析器, 可能经常要用Java实现你自己的数据或语言解析器.或者,可能有很多解析器可选,但是要么太慢,要么太耗内存,或者没有你需要的特定功能.或者开源解析 ...
 - Java学习之网络编程实例
		
转自:http://www.cnblogs.com/springcsc/archive/2009/12/03/1616413.html 多谢分享 网络编程 网络编程对于很多的初学者来说,都是很向往的一 ...
 - Java进阶之网络编程
		
网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者可能觉得网络编 ...
 - Java解析XML之Dom4j
		
Java解析XML文件的方法有多种,个人感觉最常用的是使用Dom4j来解析XML文件.下面就简单介绍下Dom4j的基础使用. Dom4j需要jar包的支持,大家可以从网络上下载,如dom4j-1.6. ...
 - 第84节:Java中的网络编程(中)
		
第84节:Java中的网络编程(中) 实现客户端和服务端的通信: 客户端需要的操作,创建socket,明确地址和端口,进行键盘录入,获取需要的数据,然后将录入的数据发送给服务端,为socket输出流, ...
 - 第78节:Java中的网络编程(上)
		
第78节:Java中的网络编程(上) 前言 网络编程涉及ip,端口,协议,tcp和udp的了解,和对socket通信的网络细节. 网络编程 OSI开放系统互连 网络编程指IO加网络 TCP/IP模型: ...
 - XML概念定义以及如何定义xml文件编写约束条件java解析xml   DTD XML Schema JAXP java xml解析 dom4j  解析 xpath dom sax
		
本文主要涉及:xml概念描述,xml的约束文件,dtd,xsd文件的定义使用,如何在xml中引用xsd文件,如何使用java解析xml,解析xml方式dom sax,dom4j解析xml文件 XML来 ...
 - 两道面试题,带你解析Java类加载机制
		
文章首发于[博客园-陈树义],点击跳转到原文<两道面试题,带你解析Java类加载机制> 在许多Java面试中,我们经常会看到关于Java类加载机制的考察,例如下面这道题: class Gr ...
 - 【转】两道面试题,带你解析Java类加载机制(类初始化方法 和 对象初始化方法)
		
本文转自 https://www.cnblogs.com/chanshuyi/p/the_java_class_load_mechamism.html 关键语句 我们只知道有一个构造方法,但实际上Ja ...
 
随机推荐
- 交叉编译和安装ARM板(RK3288)和Linux 3.10上的RTL8188无线网卡驱动
			
插入无线网卡,输入ifconfig,发现没有检测到网卡. 输入lsusb,查看无线网卡型号. 我用的无线网卡是EDUP的网卡,包装盒里有一张驱动光盘,把光盘里linux下的驱动目录复制下来.如果没有驱 ...
 - openstack学习-KeyStone安装(二)
			
一.安装keystone # yum install -y openstack-keystone httpd mod_wsgi memcached python-memcached 二.设置Memca ...
 - 利用python将表格中的汉字转化为拼音
			
缺少包时用pip install 进行安装,例如: pip install xlsxwriter 完成代码如下: #!/usr/bin/python #-*-coding:utf-8-*- #fr ...
 - 6-12 油田 uva572
			
DFS入门题 注意输入的\n要处理! #include<bits/stdc++.h> using namespace std; ][]; int n,m; ][]; void dfs(in ...
 - 李宏毅机器学习笔记2:Gradient Descent(附带详细的原理推导过程)
			
李宏毅老师的机器学习课程和吴恩达老师的机器学习课程都是都是ML和DL非常好的入门资料,在YouTube.网易云课堂.B站都能观看到相应的课程视频,接下来这一系列的博客我都将记录老师上课的笔记以及自己对 ...
 - Flutter常用组件(Widget)解析-Container
			
一个组件它往往包含了一些常见的painting, positioning和sizing这样的小部件. Container相当于我们常用的div,在Flutter中用的非常多,现在来看看Containe ...
 - Python3 图像边界识别
			
# -*- coding: utf-8 -*- """ Created on Wed Mar 7 11:04:15 2018 @author: markli " ...
 - 细说Vue作用域插槽,匹配应用场景。
			
最近在官方文档中看到,vue新增了一种插槽机制,叫做作用域插槽.要求的版本是2.1.0+. 首先来说一下:顾名思义,所谓作用域插槽,主要就在作用域,需要注意的是(以下几点看不懂不要紧,配合下面的例子, ...
 - 运营商DNS系统安全解决方案
			
DNS系统面临的主要风险 目前,DNS面临的安全问题主要可以分为三类:DNS欺骗攻击.拒绝服务攻击.系统漏洞,下文将分别进行介绍.  DNS欺骗攻击 当一个DNS服务器遭到欺骗攻击,使用了来自一个恶 ...
 - nowcoder提高组2题解
			
T1 化一下试子就ok code #include<cstdio> #include<algorithm> inline long long read() { long lon ...