Java网络编程(1):基本网络支持

1、InetAddress

  InetAddress代表IP地址,其有两个子类Inet4Address、Inet6Address,使用类方法getByName、getByAddress、getLocalHost来获取InetAddress对象:

import java.net.*;

public class Test
{
	public static void main(String[] args)throws Exception
	{	
		InetAddress ip = InetAddress.getByName("www.baidu.com"); //根据主机名或IP地址文本获得InetAddress
		String str = ip.getHostName(); //"www.baidu.com"
		str = ip.getHostAddress(); //"111.13.100.91"
		str = ip.getCanonicalHostName(); //111.13.100.91
		
		ip = InetAddress.getByAddress(new byte[]{111,13,100,91}); //根据原始地址获得InetAddress
		str = ip.getHostName(); //"111.13.100.91"
		boolean bPing = ip.isReachable(2000); //测试主机是否可达
		
		InetAddress ipLocal = InetAddress.getLocalHost(); //获得本机IP对应的InetAddress
	}
}

2、URLDecoder、URLEncoder

  当URL中包含非西欧字符的时候应该将这些非西欧字符转换为"application/x-www-form-urlencoded"格式的字符串,使用URLEncoder的类方法encode()来将普通字符串转换为特殊字符串,使用URLDecoder的类方法decode()来将特殊字符转换为普通字符:

import java.net.*;

public class Test
{
	public static void main(String[] args)throws Exception
	{
		String urlStr = URLEncoder.encode("疯狂Java学习" , "UTF-8");//指定转换时使用的字符集为utf8
		System.out.println(urlStr); //%E7%96%AF%E7%8B%82Java%E5%AD%A6%E4%B9%A0
		String keyWord = URLDecoder.decode(urlStr, "UTF-8");//指定转换时使用的字符集为utf8
		System.out.println(keyWord); //疯狂Java学习
	}
}

3、URI、URL、URLConnection、HttpURLConnection

  URI(统一资源标识符)用来标识某一互联网资源,URL(统一资源定位符)表示资源在互联网上的位置,可见URL其实就是符合URI的子集。URI的格式如下:

  

  协议名:http、https、ftp等,最后附一个冒号。
  登录信息:指定用户名和密码作为身份认证,此项可选。
  服务器地址:可以是域名或IP地址。
  服务器端口号:此项可选,省略则为使用默认端口号。
  带层次的文件路径:用来定位特指的资源。
  查询字符串(参数):针对已指定的文件路径内的资源传入任意参数,多个参数使用'&'隔开,此项可选。
  片段标识符:标记出已获取资源中的子资源(文档内的某个位置),该项可选而且RFC中没有明确规定其使用方法。

        URI absoulte=new URI("http://www.example.com/");
        URI relatice=new URI("images/logo.png");
        System.out.println(absoulte.resolve(relatice)); //"http://www.example.com/images/logo.png"

  URL可以由协议名、主机、端口、资源组成:protocal://host:port/resourceName,如http://www.javase.org/index.php。URL中的getProtocal()、getHost()、getPort()、getFile()、getPath()、getQuery()可以分别获得URL的协议名、主机名、端口号、资源名、路径部分、查询字符串部分。下面是URL类构造方法中常用的两个:

  可以调用URL的openStream()来获得一个InputStream,可以从这个流直接读取对应的网络资源,如下为使用4个线程来下载html页面的示例,这会比在一个线程中一个一个的下载html页面要快:

import java.net.URL;
import java.io.*;

public class Test
{
	public static void main(String[] args)throws Exception
	{
		URL[] urls = {
			new URL("http://openhome.cc/Gossip/Encoding/"),	
			new URL("http://openhome.cc/Gossip/Scala/"),
			new URL("http://openhome.cc/Gossip/JavaScript/"),
			new URL("http://openhome.cc/Gossip/Python/")
		};
		
		String[] fileNames = {
			"Encoding.html",
			"Scala.html",
			"JavaScript.html",
			"Python.html"
		};
		
		for(int i = 0; i < urls.length; ++i)
		{
			int index = i;
			new Thread(()-> {
				try {
					dump(urls[index].openStream(), new FileOutputStream(fileNames[index]));
				}catch(IOException ex) {
					throw new RuntimeException(ex);
				}
			}).start();
		}
	}
	static void dump(InputStream src, OutputStream dest)throws IOException
	{
		try(src; dest){
			byte[] data = new byte[1024];
			int length;
			while((length = src.read(data)) != -1)
				dest.write(data, 0, length);
		}
	}

}

  URL的openConnection()方法用来获得一个该URL的连接对象(URLConnection类型),调用该方法不会建立网络连接。在与URL的连接建立好后,可以使用URLConnection的getInputStream方法可以获得对应的输入流(用来获得URLConnection相应的内容),getOutputStream方法获得对应的输出流(用于向URLConnection发送请求参数)。URLConnection表示与URL之间的通信连接,它是一个抽象类,URL的openConnection()返回的实际上是该类型的实现类:根据URL使用的协议(http://或jar:)返回HttpURLConnection或JarURLConnection类型。在建立和远程资源的连接之前,可以通过setRequestProperty()设置通用请求头字段(请求属性),通过addRequestProperty()增加请求头字段的值。

  URLPermission是一个工具类,它用于管理HttpURLConnection的权限。

  每个HttpURLConnection实例用来向http服务器发出单个请求,而且与服务器的底层连接可能会与其它HttpURLConnection实例共享,调用某个HttpURLConnection实例的InputStream或OutputStream的close方法来释放当前实例的网络资源但对于其它的共享实例无影响,调用某个HttpURLConnection实例的disconnect方法则可能会导致底层连接关闭如果持久连接在那时是空闲的话。

  下面是使用HttpURLConnection来获得网上指定图片大小并下载该图片的示例代码:

import java.net.*;
import java.io.*;

public class Test
{
	public static void main(String[] args)throws Exception
	{
		URL url = new URL("http://e.hiphotos.baidu.com/image/pic/item/9358d109b3de9c82ddf742856181800a19d8432d.jpg");
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		
		conn.setConnectTimeout(5 * 1000); //设置超时
		conn.setRequestMethod("GET"); //设置请求方法为GET
		conn.setRequestProperty(
			"Accept",
			"image/gif, image/jpeg, image/pjpeg, image/pjpeg, "
			+ "application/x-shockwave-flash, application/xaml+xml, "
			+ "application/vnd.ms-xpsdocument, application/x-ms-xbap, "
			+ "application/x-ms-application, application/vnd.ms-excel, "
			+ "application/vnd.ms-powerpoint, application/msword, */*"); //设置客户端希望接受的数据类型
		conn.setRequestProperty("Accept-Language", "zh-CN"); //客户端希望接收的语言类型
		conn.setRequestProperty("Charset", "UTF-8"); //接受的字符集
		conn.setRequestProperty("Connection", "Keep-Alive"); //连接重用(长连接):http1.0中每个请求/应答客户和服务器都要新建一个连接,
		//当使用Keep-Alive模式时可以使连接持续有效,避免了重新建立连接。http1.1中默认启用Keep-Alive,如果设置"Connection: close ",才关闭。
		//目前大部分浏览器都是用http1.1协议,也就是说默认都会发起Keep-Alive的连接请求,所以是否能完成一个完整的Keep- Alive连接就看服务器设置情况了。
		
		int fileSize = conn.getContentLength(); //获得URL指向资源的大小
		System.out.println(fileSize);
		
		InputStream inStream = conn.getInputStream();
		RandomAccessFile currentPart = new RandomAccessFile("image.jpg" , "rw");
		byte[] buffer = new byte[1024];
		int hasRead = 0;
		int length = 0;
		// 读取网络数据,并写入本地文件
		while ((hasRead = inStream.read(buffer)) != -1)
		{
			currentPart.write(buffer, 0, hasRead);
			// 累计下载的总大小
			length += hasRead;
		}
		System.out.println(length);
		currentPart.close();
		inStream.close();
		
		conn.disconnect(); //指示该底层连接上无其他请求了
	}
}

  如果只是发送GET方式请求,则使用connect方法建立与远程资源的连接,如果是发送POST方式的请求,则需要先设置doIn和doOut两个请求头字段的值,再获取URLConnection实例对应的输出流来发送请求参数。在建立和远程资源的连接之前,还可以通过以下方法设置特定请求头字段:setAllowUserInteraction()、setDoInput()、setDoOutput()、 setIfModifiedSince()、setUseCaches()。

  在与URL的连接建立好后,可以使用URLConnection的getContent()获得该URLConnection的内容,调用getHeaderField(String name)获得指定响应头字段的值,也可以调用下列方法获得特定响应头字段的值:getContentEncoding()、getContentLength()、getContentType()、getDate()、getExpiration()、getLastModifed()。

  不管是发送GET请求还是POST请求,程序中获取URLConnection响应的方式完全一样:如果可以确定远程响应是字符流则可以使用字符流来读取,如果无法确定的话就使用字节流读取。

  下面是向Web站点发送GET请求和POST请求,并从Web站点获取响应的示例:

import java.io.*;
import java.net.*;
import java.util.*;

public class GetPostTest
{
	/**
	 * 向指定URL发送GET方法的请求
	 * @param url 发送请求的URL
	 * @param param 请求参数,格式满足name1=value1&name2=value2的形式。
	 * @return URL所代表远程资源的响应
	 */
	public static String sendGet(String url , String param)
	{
		String result = "";
		String urlName = url + "?" + param; //URL与请求参数以'?'隔开
		try
		{
			URL realUrl = new URL(urlName);
			// 打开和URL之间的连接
			URLConnection conn = realUrl.openConnection();
			// 设置通用的请求属性
			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();
			// 获取所有响应头字段
			Map<String, List<String>> map = conn.getHeaderFields();
			// 遍历所有的响应头字段
			for (String key : map.keySet())
			{
				System.out.println(key + "--->" + map.get(key));
			}
			try(
				// 定义BufferedReader输入流来读取URL的响应
				BufferedReader in = new BufferedReader(
					new InputStreamReader(conn.getInputStream() , "utf-8")))
			{
				String line;
				while ((line = in.readLine())!= null)
				{
					result += "\n" + line;
				}
			}
		}
		catch(Exception e)
		{
			System.out.println("发送GET请求出现异常!" + e);
			e.printStackTrace();
		}
		return result;
	}
	
	/**
	 * 向指定URL发送POST方法的请求
	 * @param url 发送请求的URL
	 * @param param 请求参数,格式应该满足name1=value1&name2=value2的形式。
	 * @return URL所代表远程资源的响应
	 */
	public static String sendPost(String url , String param)
	{
		String result = "";
		try
		{
			URL realUrl = new URL(url);
			// 打开和URL之间的连接
			URLConnection conn = realUrl.openConnection();
			// 设置通用的请求属性
			conn.setRequestProperty("accept", "*/*");
			conn.setRequestProperty("connection", "Keep-Alive");
			conn.setRequestProperty("user-agent",
			"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
			// 发送POST请求必须设置如下两行
			conn.setDoOutput(true);
			conn.setDoInput(true);
			try(
				// 获取URLConnection对象对应的输出流
				PrintWriter out = new PrintWriter(conn.getOutputStream()))
			{
				// 发送请求参数
				out.print(param);
				// flush输出流的缓冲
				out.flush();
			}
			try(
				// 定义BufferedReader输入流来读取URL的响应
				BufferedReader in = new BufferedReader(new InputStreamReader
					(conn.getInputStream() , "utf-8")))
			{
				String line;
				while ((line = in.readLine())!= null)
				{
					result += "\n" + line;
				}
			}
		}
		catch(Exception e)
		{
			System.out.println("发送POST请求出现异常!" + e);
			e.printStackTrace();
		}
		return result;
	}
	
	// 提供主方法,测试发送GET请求和POST请求
	public static void main(String args[])
	{
		// 发送GET请求
		String s = GetPostTest.sendGet("http://localhost:8888/abc/a.jsp", null);
		System.out.println(s);
		// 发送POST请求
		String s1 = GetPostTest.sendPost("http://localhost:8888/abc/login.jsp", "name=crazyit.org&pass=leegang");
		System.out.println(s1);
	}
}

  对于https请求,可以使用HttpsURLConnection:(HttpsURLConnection) url.openConnection(),需要使用一个X509TrustManager对象来设置HttpsURLConnection。X509TrustManager是证书管理类,我们可以实现它的checkClientTrusted()、checkServerTrusted()、getAcceptedIssuers()方法,在这些方法中什么都不做的话就表示不做任何的验证。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值