网络编程总结(三):Java 对网络的基本支持

Java 提供了支持网络的 API,他们都在 java.net 包下,这些 API 提供了一系列针对我们访问互联网的方法,下面来依次认识一下:

InetAddress 类

该类表示互联网协议(IP)地址。大多数其他网络类都要用到这个类,一般来讲,它包含一个主机名和一个 IP 地址。

InetAddress 类没有公共构造函数,只有一些静态工厂方法,可以连接到 DNS 服务器来解析主机名。最常用的是 InetAddress.getByName() 方法,

例如:

public class NetTest {
    public static void main(String[] args) {
        try {
            System.out.println(InetAddress.getByName("www.li-xyz.com"));
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

输出结果:

www.li-xyz.com/23.106.154.100

该类还有其他一些方法,可以去查看 API,这里就不浪费篇幅了。

URI 类

什么是 URI?

在电脑术语中,统一资源标识符(英语:Uniform Resource Identifier,或URI)是一个用于标识某一互联网资源名称的字符串。 该种标识允许用户对网络中(一般指万维网)的资源通过特定的协议进行交互操作。

URI 语法

URI 语法URI 协议名(例如 http、ftp、mailto、file),一个冒号,和协议对应的内容所构成。特定的协议定义了协议内容的语法和语义,而所有的协议都必须遵循一定的 URI 语法通用规则。

下面展示了两个 URI 例子以及它们的组成部分

                    hierarchical part
        ┌───────────────────┴─────────────────────┐
                    authority               path
        ┌───────────────┴───────────────┐┌───┴────┐
  abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
  └┬┘   └───────┬───────┘ └────┬────┘ └┬┘           └─────────┬─────────┘ └──┬──┘
scheme  user information     host     port                  query         fragment

  urn:example:mammal:monotreme:echidna
  └┬┘ └──────────────┬───────────────┘
scheme              path

Java 对 URI 的支持

Java 提供了 URI 类来帮助我们处理 URI 内容,看一个小例子

public class NetTest {
    public static void main(String[] args) {
        try {
            URI uri = new URI("https://www.li-xyz.com/content/images/2017/02/QQ--20170221093402.png");
            System.out.println(uri.getHost());
            System.out.println(uri.getPath());
            System.out.println(uri.getScheme());
        } catch (URISyntaxException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

执行结果:

www.li-xyz.com
/content/images/2017/02/QQ--20170221093402.png
https

该类还有其他一些方法,可以去查看 API,这里就不浪费篇幅了。

URL

统一资源定位符(或称统一资源定位器/定位地址、URL地址等[1],英语:Uniform / Universal Resource Locator,常缩写为URL),有时也被俗称为网页地址(网址)。如同在网络上的门牌,是因特网上标准的资源的地址(Address)。

统一资源定位符的标准格式如下:

协议类型://服务器地址(必要时需加上端口号)/路径/文件名

日常使用

超文本传输协议(HTTP)的统一资源定位符将从因特网获取信息的五个基本元素包括在一个简单的地址中:

  1. 传送协议。
  2. 服务器。(通常为域名,有时为IP地址)
  3. 端口号。(以数字方式表示,若为HTTP的默认值“:80”可省略)
  4. 路径。(以“/”字符区别路径中的每一个目录名称)
  5. 查询。(GET模式的窗体参数,以“?”字符为起点,每个参数以“&”隔开,再以“=”分开参数名称与数据,通常以UTF8的URL编码,避开字符冲突的问题)

其中:

  1. http,是协议;
  2. zh.wikipedia.org,是服务器;
  3. 80,是服务器上的网络端口号;
  4. /w/index.php,是路径;
  5. ?title=Special:%E9%9A%8F%E6%9C%BA%E9%A1%B5%E9%9D%A2&printable=yes,是询问。

大多数网页浏览器不要求用户输入网页中http://的部分,因为绝大多数网页内容是超文本传输协议文件。同样,80是超文本传输协议文件的常用端口号,因此一般也不必写明。一般来说用户只要键入统一资源定位符的一部分zh.wikipedia.org/wiki/Special:%E9%9A%8F%E6%9C%BA%E9%A1%B5%E9%9D%A2就可以了。

由于超文本传输协议允许服务器将浏览器重定向到另一个网页地址,因此许多服务器允许用户省略网页地址中的部分,比如www。从技术上来说这样省略后的网页地址实际上是一个不同的网页地址,浏览器本身无法决定这个新地址是否通,服务器必须完成重定向的任务。

其他使用

统一资源定位符不但被用作网页地址,数据库终端也使用统一资源定位符服务器连接其服务器。实际上任何终端-服务器程序都可以使用统一资源定位符来连接。

以下是一个数据库的统一资源定位符:

jdbc:datadirect:oracle://myserver:1521;sid=testdb

URI 和 URL 的区别

查看本文:[[译]URL和URI的区别](http://www.cnblogs.com/hust-ghtao/p/4724885.html)

Java 对 URL 的支持

  • 创建新的URL
    URL 类提供了不同的构造函数来帮助我们创建一个 URL 对象
URL(String spec) 
根据 String 表示形式创建 URL 对象。 

URL(String protocol, String host, int port, String file) 
根据指定 protocol、host、port 号和 file 创建 URL 对象。 

URL(String protocol, String host, int port, String file, URLStreamHandler handler) 
根据指定的 protocol、host、port 号、file 和 handler 创建 URL 对象。 

URL(String protocol, String host, String file) 
根据指定的 protocol 名称、host 名称和 file 名称创建 URL。 

URL(URL context, String spec) 
通过在指定的上下文中对给定的 spec 进行解析创建 URL。 

URL(URL context, String spec, URLStreamHandler handler) 
通过在指定的上下文中用指定的处理程序对给定的 spec 进行解析来创建 URL。 
  • 从 URL 获取数据
    URL 名为资源定位符,顾名思义,它定位到互联网上的某一个资源,所以理所当然的我们也可以获取到该资源,URL 提供下面几个方法来从 URL 获取数据
 Object getContent() 
获取此 URL 的内容。 

 Object getContent(Class[] classes) 
获取此 URL 的内容。 

 URLConnection openConnection() 
返回一个 URLConnection 对象,它表示到 URL 所引用的远程对象的连接。 

 URLConnection openConnection(Proxy proxy) 
与 openConnection() 类似,所不同是连接通过指定的代理建立;不支持代理方式的协议处理程序将忽略该代理参数并建立正常的连接。 

 InputStream openStream() 
打开到此 URL 的连接并返回一个用于从该连接读入的 InputStream。 

最常用的是 openStream() 方法,它会返回一个 InputStream,可以直接从这个流中读取数据,如果要更多的控制下载过程,则需要调用 openConnection(),会得到一个 URLConnection,然后由它获得一个 InputStream。

一个小例子:

public class NetTest {
    public static void main(String[] args) {
        try {
            URL url = new URL("https://www.li-xyz.com/content/images/2017/02/QQ--20170221093402.png");
            InputStream inputStream = url.openStream();

            FileOutputStream fos = new FileOutputStream(new File("D:\\X.png"));

            BufferedInputStream bis = new BufferedInputStream(inputStream);
            byte[] buf = new byte[1024];
            int len = 0;
            while ((len = bis.read(buf)) != -1) {
                fos.write(buf, 0, len);
                fos.flush();
            }

            inputStream.close();
            fos.close();
            bis.close();
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

URLEncoder 和 URLDecoder

x-www-form-urlencoded

在 URLEncoder 和 URLDecoder 之前需要先明白这个东西,因为现在流行的操作系统有好多,而这些操作系统对于各自的标准也有所不同,所以在处理 URL 在不同的操作系统之间会有不同的情况,例如有些操作系统不允许文件中有空格,但是有的却可以,大多数操作系统不反对文件名中出现#号,但在 URL 中 # 号表示文件名的结束,后面是片段标识符。另外还有其他特殊字符、非字母数字字符等在 URL 中或另一个操作系统上有特殊的意义,这也会产生类似的问题。

为了解决这个问题,需要将 URL 中使用的字符转换为 ASCII 码。

URL 类不会对我们传入的字符串做自动解码或编码,所以 Java 提供了 URLEncoder 和URLDecoder 来帮助我们解决这个问题

URLEncoder 编码

要对字符串完成 URL 编码,需要将这个字符串传入 URLEncoder.encode() 方法中,该方法会返回一个已经编码好的字符串。

URLDecoder 解码

要对已经编码的 URL 字符串解码,需要将该字符串传入 URLDecoder.decode() 方法中,该方法会对传入的字符串解码,并将解码后的字符串返回。

一个例子:

public class NetTest {
    public static void main(String[] args) {
        String str = "Java 中的网络";
        String encoderStr = URLEncoder.encode(str);
        
        System.out.println(encoderStr);
        System.out.println(URLDecoder.decode(encoderStr));
    }
}

输出:

Java+%D6%D0%B5%C4%CD%F8%C2%E7
Java 中的网络

参考资料

  • 《疯狂 Java 讲义 第三版》
  • 《Java 网络变成 第四版》