教程:自定义网络
Java 平台备受推崇,部分原因是其适用于编写使用和与互联网资源以及万维网进行交互的程序。事实上,兼容 Java 的浏览器极大地利用了 Java 平台的这种能力,在互联网上传输和运行小程序。
本教程将引导您了解编写可在互联网上使用的 Java 应用程序和小程序的复杂性。
有两个部分。第一部分描述了 Java 平台的网络功能,您可能已经在不知不觉中使用网络。第二部分简要概述了网络,使您熟悉在阅读如何使用 URL、套接字和数据报之前应了解的术语和概念。
讨论了您的 Java 程序如何使用 URL 来访问互联网上的信息。URL(统一资源定位符)是互联网上资源的地址。您的 Java 程序可以使用 URL 来连接并检索网络上的信息。本课程提供了 URL 的更完整定义,并向您展示如何创建和解析 URL,如何打开与 URL 的连接,以及如何从该连接读取和写入。
解释了如何使用套接字,以便您的程序可以与网络上的其他程序通信。套接字是运行在网络上的两个程序之间的双向通信链路的一个端点。本课程向您展示了客户端如何连接到标准服务器 Echo 服务器,并通过套接字与其通信。然后,它详细介绍了一个完整客户端/服务器示例的细节,展示了如何实现客户端和服务器端的客户端/服务器对。
逐步带您完成一个使用数据报进行通信的简单客户端/服务器示例。然后,它挑战您使用多播套接字重新编写示例。
解释了为什么您可能想要访问网络接口参数以及如何做到这一点。它提供了如何列出分配给计算机的所有 IP 地址以及其他有用信息的示例,例如接口是否正在运行。
讨论了如何使用 cookies 在客户端和服务器之间创建会话,以及如何在 HTTP URL 连接中利用 cookies。
安全考虑:
请注意,网络通信需经当前安全管理器批准。安全管理器 描述了安全管理器是什么以及它如何影响您的应用程序。有关 JDK 提供的安全功能的一般信息,请参考 Java SE 中的安全功能。
下面课程中的示例程序涵盖了 URL、套接字和数据报,它们都是独立的应用程序,默认情况下没有安全管理器。如果将这些应用程序转换为小程序,根据运行它们的浏览器或查看器的不同,它们可能无法在网络上通信。请参阅 小程序的功能和限制 以获取有关小程序所受安全限制的信息。
课程:网络概述
原文:docs.oracle.com/javase/tutorial/networking/overview/index.html
在接下来几节的示例之前,您应该对一些网络基础知识有所了解。此外,为了增强您的信心,我们还包括了一个回顾您可能已经了解的关于在 Java 中进行网络操作的部分。
您可能已经了解的关于在 Java 中进行网络操作的内容
如果您已经在本教程的其他部分工作过,那么您可能已经通过互联网加载了一个小程序,并且可能已经将网络中的图像加载到通过网络运行的小程序中。所有这些都是使用网络,而您已经知道如何做。本页突出了在本教程的其他部分和课程中涵盖的网络功能,这些功能您可能已经熟悉,并提供链接到讨论这些功能的页面。
网络基础知识
您将学习关于 TCP、UDP、套接字、数据报和端口的知识,以充分利用本教程中剩余课程的内容。如果您已经熟悉这些概念,可以随意跳过本节。
你可能已经了解的关于 Java 网络的知识
原文:docs.oracle.com/javase/tutorial/networking/overview/alreadyknow.html
“网络”这个词让许多程序员心生恐惧。不要害怕!在 Java 环境中提供的网络功能非常容易使用。事实上,你可能已经在不知不觉中使用网络了!
从网络加载小程序
如果你有一个支持 Java 的浏览器,你肯定已经执行了许多小程序。你运行的小程序是通过 HTML 文件中的特殊标签引用的 - 标签。小程序可以位于任何地方,无论是在本地计算机上还是在互联网上的某个地方。小程序的位置对用户完全不可见。然而,小程序的位置被编码在标签中。浏览器解码这些信息,找到小程序并运行它。如果小程序位于你自己的机器之外的某台机器上,浏览器必须在运行之前下载小程序。
这是你从 Java 开发环境访问互联网的最高级别。其他人已经花时间编写了一个浏览器,完成了连接到网络和从中获取数据的所有繁重工作,从而使你能够从世界各地运行小程序。
更多信息:
“Hello World!”应用程序展示了如何编写你的第一个小程序并运行它。
Java 小程序系列描述了如何从头到尾编写 Java 小程序。
从 URL 加载图像
如果你尝试编写自己的 Java 小程序和应用程序,你可能已经遇到了 java.net 包中的一个类叫做 URL。这个类代表统一资源定位符,是网络上某些资源的地址。你的小程序和应用程序可以使用 URL 来引用甚至连接到网络上的资源。例如,要从网络加载图像,你的 Java 程序必须首先创建一个包含图像地址的 URL。
这是你可以与互联网互动的下一个最高级别 - 你的 Java 程序获取它想要的东西的地址,为其创建一个 URL,然后使用 Java 开发环境中的某个现有函数来连接到网络并检索资源。
更多信息:
如何使用图标展示了当你有图像的 URL 时如何将其加载到你的 Java 程序中(无论是小程序还是应用程序)。在加载图像之前,你必须创建一个包含资源地址的 URL 对象。
处理 URL,这一系列中的下一课,提供了关于 URL 的完整讨论,包括你的程序如何连接到它们以及如何从连接中读取和写入数据。
网络基础知识
原文:docs.oracle.com/javase/tutorial/networking/overview/networking.html
在互联网上运行的计算机使用传输控制协议(TCP)或用户数据报协议(UDP)相互通信,如此图所示:
当你编写通过网络进行通信的 Java 程序时,你是在应用层编程。通常情况下,你不需要关心 TCP 和 UDP 层。相反,你可以使用 java.net 包中的类。这些类提供了系统独立的网络通信。然而,为了决定你的程序应该使用哪些 Java 类,你需要了解 TCP 和 UDP 的区别。
TCP
当两个应用程序想要可靠地相互通信时,它们建立连接并在该连接上来回发送数据。这类似于打电话。如果你想和肯塔基州的比阿特丽斯阿姨通话,当你拨打她的电话号码并她接听时,就建立了连接。你通过电话线互相交流数据。像电话公司一样,TCP 保证从连接的一端发送的数据实际上到达另一端,并且按照发送顺序。否则,会报告错误。
TCP 为需要可靠通信的应用程序提供了一对一的通道。超文本传输协议(HTTP)、文件传输协议(FTP)和 Telnet 都是需要可靠通信通道的应用程序的示例。在网络上传输和接收数据的顺序对于这些应用程序的成功至关重要。当使用 HTTP 从 URL 读取数据时,数据必须按照发送顺序接收。否则,你会得到一个混乱的 HTML 文件、一个损坏的 zip 文件或其他无效信息。
定义:
TCP(传输控制协议)是一种基于连接的协议,它在两台计算机之间提供可靠的数据流。
UDP
UDP 协议提供了两个应用程序之间不保证通信的功能。UDP 不像 TCP 那样基于连接。相反,它从一个应用程序发送独立的数据包(称为数据报)到另一个应用程序。发送数据报就像通过邮政服务发送信件一样:交付顺序不重要,也不保证,每个消息都是独立的。
定义:
UDP(用户数据报协议)是一种协议,它发送独立的数据包(称为数据报)从一台计算机到另一台计算机,不保证到达。UDP 不像 TCP 那样基于连接。
对于许多应用程序,可靠性的保证对于信息从连接的一端传输到另一端的成功至关重要。然而,其他形式的通信并不需要如此严格的标准。事实上,它们可能会因为额外的开销或可靠连接可能使服务无效而变慢。
举个例子,考虑一个时钟服务器,当被请求时向其客户端发送当前时间。如果客户端错过了一个数据包,重新发送它并没有意义,因为当客户端第二次接收到时,时间将不正确。如果客户端发出两个请求并且接收到服务器发送的数据包顺序不对,也没关系,因为客户端可以发现数据包顺序不对并发出另一个请求。在这种情况下,TCP 的可靠性是不必要的,因为它会导致性能下降,可能会影响服务的实用性。
另一个不需要可靠通道保证的服务的例子是 ping 命令。ping 命令的目的是测试网络上两个程序之间的通信。事实上,ping 需要知道丢失或顺序错乱的数据包,以确定连接的好坏。可靠通道会使这项服务完全无效。
UDP 协议提供了在网络上两个应用程序之间不保证通信的功能。UDP 不像 TCP 那样基于连接。相反,它从一个应用程序发送独立的数据包到另一个应用程序。发送数据报就像通过邮件服务发送信件一样:交付顺序不重要,也不被保证,每个消息都独立于其他消息。
注意:
许多防火墙和路由器已经配置为不允许 UDP 数据包。如果您在防火墙外部连接到服务时遇到问题,或者客户端无法连接到您的服务,请询问系统管理员是否允许 UDP。
理解端口
一般来说,计算机与网络之间有一个物理连接。所有发送给特定计算机的数据都通过这个连接到达。然而,这些数据可能是针对计算机上运行的不同应用程序的。那么计算机如何知道将数据转发给哪个应用程序呢?通过端口。
通过互联网传输的数据附带有标识计算机和目标端口的寻址信息。计算机通过其 32 位 IP 地址进行标识,IP 使用它将数据传递到网络上的正确计算机。端口由一个 16 位数字进行标识,TCP 和 UDP 使用它将数据传递给正确的应用程序。
在基于连接的通信(如 TCP)中,服务器应用程序将套接字绑定到特定端口号。这样做的效果是向系统注册服务器以接收所有发送到该端口的数据。然后客户端可以在服务器的端口处与服务器会合,如下图所示:
定义:
TCP 和 UDP 协议使用端口将传入的数据映射到计算机上运行的特定进程。
在基于数据报的通信(如 UDP)中,数据报包含其目的地的端口号,UDP 将数据包路由到适当的应用程序,如下图所示:
端口号范围从 0 到 65,535,因为端口由 16 位数字表示。端口号从 0 到 1023 是受限制的;它们保留供 HTTP 和 FTP 等众所周知的服务以及其他系统服务使用。这些端口被称为众所周知的端口。您的应用程序不应尝试绑定到它们。
JDK 中的网络类
通过java.net中的类,Java 程序可以使用 TCP 或 UDP 在互联网上进行通信。URL、URLConnection、Socket和ServerSocket类都使用 TCP 在网络上进行通信。DatagramPacket、DatagramSocket和MulticastSocket类用于 UDP。
教程:使用 URL
原文:docs.oracle.com/javase/tutorial/networking/urls/index.html
URL 是统一资源定位符的缩写。它是指向互联网上资源的引用(地址)。您向您喜爱的 Web 浏览器提供 URL,以便它可以定位互联网上的文件,就像您向邮局提供地址以便它可以找到您的通信对象一样。
与互联网交互的 Java 程序还可以使用 URL 来找到他们希望访问的互联网资源。Java 程序可以使用java.net包中的一个名为URL的类来表示 URL 地址。
术语说明:
术语URL可能会产生歧义。它可以指互联网地址或 Java 程序中的URL对象。在需要明确 URL 含义的情况下,本文使用"URL 地址"来指代互联网地址,使用"URL对象"来指代程序中URL类的实例。
什么是 URL?
URL 采用描述如何在互联网上找到资源的字符串形式。URL 有两个主要组成部分:访问资源所需的协议和资源的位置。
创建 URL
在您的 Java 程序中,您可以创建一个表示 URL 地址的 URL 对象。URL 对象始终指向绝对 URL,但可以从绝对 URL、相对 URL 或 URL 组件构造。
解析 URL
过去需要解析 URL 以查找主机名、文件名和其他信息的日子已经一去不复返了。有了有效的 URL 对象,您可以调用其任何访问器方法,从 URL 中获取所有这些信息,而无需进行任何字符串解析!
直接从 URL 读取
本节展示了您的 Java 程序如何使用openStream()方法从 URL 中读取信息。
连接到 URL
如果您想要的不仅仅是从 URL 中读取信息,您可以通过在 URL 上调用openConnection()来连接到它。openConnection()方法返回一个 URLConnection 对象,您可以用它进行更一般的与 URL 通信,如从中读取、向其中写入或查询其内容和其他信息。
从 URLConnection 读取和写入
一些 URL(例如许多与 cgi-bin 脚本相关的 URL)允许您(甚至要求您)向 URL 写入信息。例如,搜索脚本可能要求在执行搜索之前向 URL 写入详细的查询数据。本节展示了如何向 URL 写入信息以及如何获取结果。
什么是 URL?
原文:docs.oracle.com/javase/tutorial/networking/urls/definition.html
如果您一直在浏览网络,您无疑听说过 URL 这个术语,并且已经使用 URL 从网络访问 HTML 页面。
尽管不完全准确,但通常最容易将 URL 视为全球网络上文件的名称,因为大多数 URL 指向网络上某台机器上的文件。但请记住,URL 也可以指向网络上的其他资源,例如数据库查询和命令输出。
定义:
URL 是统一资源定位符的缩写,是指向互联网上资源的引用(地址)。
URL 有两个主要组成部分:
- 协议标识符:对于 URL http://example.com,协议标识符是 http。
- 资源名称:对于 URL http://example.com,资源名称是 example.com。
请注意,协议标识符和资源名称之间用冒号和两个正斜杠分隔。协议标识符指示要用于获取资源的协议的名称。此示例使用超文本传输协议(HTTP),通常用于提供超文本文档。HTTP 只是用于访问网络上不同类型资源的许多不同协议之一。其他协议包括文件传输协议(FTP)、Gopher、文件和新闻。
资源名称是资源的完整地址。资源名称的格式完全取决于所使用的协议,但对于许多协议,包括 HTTP,资源名称包含以下一个或多个组件:
主机名
存储资源的机器名称。
文件名
机器上文件的路径名。
端口号
要连接的端口号(通常是可选的)。
参考
指向资源内命名锚点的参考,通常标识文件内的特定位置(通常是可选的)。
对于许多协议,主机名和文件名是必需的,而端口号和参考是可选的。例如,HTTP URL 的资源名称必须指定网络上的服务器(主机名)和该机器上文档的路径(文件名);它还可以指定端口号和参考。
创建 URL
原文:docs.oracle.com/javase/tutorial/networking/urls/creatingUrls.html
创建 URL 对象的最简单方法是从表示 URL 地址的人类可读形式的 String 创建。这通常是另一个人将用于 URL 的形式。在您的 Java 程序中,您可以使用包含此文本的 String 来创建 URL 对象:
URL myURL = new URL("http://example.com/");
上面创建的 URL 对象表示一个绝对 URL。绝对 URL 包含到达所需资源的所有必要信息。您还可以从相对 URL地址创建 URL 对象。
创建相对于另一个的 URL
相对 URL 只包含足够的信息,以便相对于(或在另一个 URL 的上下文中)到达资源。
相对 URL 规范通常在 HTML 文件中使用。例如,假设您编写了一个名为 JoesHomePage.html 的 HTML 文件。在此页面中,有指向其他页面 PicturesOfMe.html 和 MyKids.html 的链接,这些页面位于与 JoesHomePage.html 相同的机器和目录中。从 JoesHomePage.html 到 PicturesOfMe.html 和 MyKids.html 的链接可以像文件名一样指定,如下所示:
<a href="PicturesOfMe.html">Pictures of Me</a> <a href="MyKids.html">Pictures of My Kids</a>
这些 URL 地址是相对 URL。也就是说,这些 URL 是相对于包含它们的文件——JoesHomePage.html来指定的。
在您的 Java 程序中,您可以从相对 URL 规范创建一个 URL 对象。例如,假设您在站点 example.com 知道两个 URL:
http://example.com/pages/page1.html http://example.com/pages/page2.html
您可以相对于它们的共同基本 URL http://example.com/pages/ 创建这些页面的 URL 对象,如下所示:
URL myURL = new URL("http://example.com/pages/"); URL page1URL = new URL(myURL, "page1.html"); URL page2URL = new URL(myURL, "page2.html");
此代码片段使用了一个 URL 构造函数,让您可以从另一个 URL 对象(基础)和相对 URL 规范创建一个 URL 对象。此构造函数的一般形式是:
URL(URL *baseURL*, String *relativeURL*)
第一个参数是指定新 URL 的基础的 URL 对象。第二个参数是指定相对于基础的资源名称的其余部分的 String。如果 baseURL 为 null,则此构造函数将 relativeURL 视为绝对 URL 规范。相反,如果 relativeURL 是绝对 URL 规范,则构造函数将忽略 baseURL。
这个构造函数也适用于为文件中的命名锚点(也称为引用)创建 URL 对象。例如,假设 page1.html 文件在文件底部有一个名为 BOTTOM 的命名锚点。您可以使用相对 URL 构造函数为其创建一个 URL 对象,如下所示:
URL page1BottomURL = new URL(page1URL,"#BOTTOM");
其他 URL 构造函数
URL 类提供了另外两个用于创建 URL 对象的构造函数。当您使用具有主机名、文件名、端口号和 URL 资源名称部分中的引用组件的 URL(如 HTTP URL)时,这些构造函数很有用。当您没有包含完整 URL 规范的 String,但您知道 URL 的各个组件时,这两个构造函数很有用。
例如,假设您设计一个类似文件浏览面板的网络浏览面板,允许用户选择协议、主机名、端口号和文件名。您可以从面板的组件构造一个URL。第一个构造函数从协议、主机名和文件名创建一个URL对象。以下代码片段创建一个URL到example.com站点的page1.html文件:
new URL("http", "example.com", "/pages/page1.html");
这等同于
new URL("http://example.com/pages/page1.html");
第一个参数是协议,第二个是主机名,最后一个是文件的路径名。请注意,文件名包含一个斜杠在开头。这表示文件名是从主机的根目录指定的。
最终的URL构造函数将端口号添加到前一个构造函数中使用的参数列表中:
URL gamelan = new URL("http", "example.com", 80, "pages/page1.html");
这将为以下 URL 创建一个URL对象:
http://example.com:80/pages/page1.html
如果使用这些构造函数之一构造URL对象,您可以通过使用URL对象的toString方法或等效的toExternalForm方法获得包含完整 URL 地址的String。
具有特殊字符的 URL 地址
一些 URL 地址包含特殊字符,例如空格字符。就像这样:
http://example.com/hello world/
在将这些字符传递给 URL 构造函数之前,它们需要进行编码以使其合法。
URL url = new URL("http://example.com/hello%20world");
在这个例子中编码特殊字符很容易,因为只有一个字符需要编码,但是对于具有多个这些字符的 URL 地址,或者在编写代码时不确定需要访问哪些 URL 地址时,您可以使用java.net.URI类的多参数构造函数来自动处理编码。
URI uri = new URI("http", "example.com", "/hello world/", "");
然后将 URI 转换为 URL。
URL url = uri.toURL();
MalformedURLException
四个URL构造函数中的每一个如果构造函数的参数引用null或未知协议,则会抛出MalformedURLException。通常,您希望通过将 URL 构造函数语句嵌入到try/catch对中来捕获和处理此异常,就像这样:
try { URL myURL = new URL(...); } catch (MalformedURLException e) { // *exception handler code here* // ... }
有关处理异常的信息,请参阅异常。
注意:
URL是“一次写入”对象。一旦创建了URL对象,就无法更改其任何属性(协议、主机名、文件名或端口号)。
解析 URL
原文:docs.oracle.com/javase/tutorial/networking/urls/urlInfo.html
URL类提供了几种方法,让您可以查询URL对象。您可以使用这些访问器方法从 URL 中获取协议、权限、主机名、端口号、路径、查询、文件名和引用:
getProtocol
返回 URL 的协议标识符组件。
getAuthority
返回 URL 的权限组件。
getHost
返回 URL 的主机名组件。
getPort
返回 URL 的端口号组件。getPort方法返回一个整数,即端口号。如果端口未设置,getPort返回-1。
getPath
返回此 URL 的路径组件。
getQuery
返回此 URL 的查询组件。
getFile
返回 URL 的文件名组件。getFile方法返回与getPath相同的内容,再加上getQuery的值(如果有的话)。
getRef
返回 URL 的引用组件。
注意:
请记住,并非所有 URL 地址都包含这些组件。URL 类提供这些方法是因为 HTTP URL 包含这些组件,可能是最常用的 URL。URL 类在某种程度上是以 HTTP 为中心的。
您可以使用这些get*XXX*方法获取有关 URL 的信息,而不管您使用哪种构造函数创建 URL 对象。
URL 类以及这些访问器方法使您永远不必再解析 URL!只需给定任何 URL 的字符串规范,创建一个新的 URL 对象,并调用所需信息的任何访问器方法即可。这个小例子程序从字符串规范创建一个 URL,然后使用 URL 对象的访问器方法解析 URL:
import java.net.*; import java.io.*; public class ParseURL { public static void main(String[] args) throws Exception { URL aURL = new URL("http://example.com:80/docs/books/tutorial" + "/index.html?name=networking#DOWNLOADING"); System.out.println("protocol = " + aURL.getProtocol()); System.out.println("authority = " + aURL.getAuthority()); System.out.println("host = " + aURL.getHost()); System.out.println("port = " + aURL.getPort()); System.out.println("path = " + aURL.getPath()); System.out.println("query = " + aURL.getQuery()); System.out.println("filename = " + aURL.getFile()); System.out.println("ref = " + aURL.getRef()); } }
下面是程序显示的输出:
protocol = http authority = example.com:80 host = example.com port = 80 path = /docs/books/tutorial/index.html query = name=networking filename = /docs/books/tutorial/index.html?name=networking ref = DOWNLOADING
直接从 URL 读取
原文:docs.oracle.com/javase/tutorial/networking/urls/readingURL.html
成功创建URL后,您可以调用URL的openStream()方法来获取一个流,从中可以读取 URL 的内容。openStream()方法返回一个java.io.InputStream对象,因此从 URL 读取就像从输入流读取一样简单。
以下的小型 Java 程序使用openStream()来在 URL http://www.oracle.com/上获取输入流。然后在输入流上打开一个BufferedReader,并从BufferedReader读取,从而从 URL 读取。所有读取的内容都被复制到标准输出流:
import java.net.*; import java.io.*; public class URLReader { public static void main(String[] args) throws Exception { URL oracle = new URL("http://www.oracle.com/"); BufferedReader in = new BufferedReader( new InputStreamReader(oracle.openStream())); String inputLine; while ((inputLine = in.readLine()) != null) System.out.println(inputLine); in.close(); } }
当您运行该程序时,您应该在命令窗口中看到从http://www.oracle.com/位置的 HTML 文件中滚动显示的 HTML 命令和文本内容。或者,程序可能会挂起,或者您可能会看到异常堆栈跟踪。如果出现后两种情况中的任何一种,您可能需要设置代理主机以便程序可以找到 Oracle 服务器。
连接到 URL
原文:docs.oracle.com/javase/tutorial/networking/urls/connecting.html
成功创建URL对象后,您可以调用URL对象的openConnection方法获取一个URLConnection对象,或者其协议特定的子类之一,例如java.net.HttpURLConnection
您可以使用此URLConnection对象在连接之前设置参数和一般请求属性。仅当调用URLConnection.connect方法时才会启动与 URL 表示的远程对象的连接。这样做时,您正在初始化您的 Java 程序与网络上的 URL 之间的通信链接。例如,以下代码打开到example.com站点的连接:
try { URL myURL = new URL("http://example.com/"); URLConnection myURLConnection = myURL.openConnection(); myURLConnection.connect(); } catch (MalformedURLException e) { // new URL() failed // ... } catch (IOException e) { // openConnection() failed // ... }
每次调用此 URL 的协议处理程序的openConnection方法都会创建一个新的URLConnection对象。
您并不总是需要显式调用connect方法来启动连接。依赖于连接的操作,如getInputStream、getOutputStream等,将在必要时隐式执行连接。
现在您已成功连接到您的 URL,您可以使用URLConnection对象执行诸如从连接中读取或写入的操作。接下来的部分将向您展示如何操作。
从 URLConnection 读取和写入
原文:docs.oracle.com/javase/tutorial/networking/urls/readingWriting.html
URLConnection类包含许多方法,让您可以通过网络与 URL 通信。URLConnection是一个以 HTTP 为中心的类;也就是说,当您使用 HTTP URL 时,其中许多方法才有用。然而,大多数 URL 协议允许您从连接中读取和写入。本节描述了这两个功能。
Java 中文官方教程 2022 版(四十五)(2)https://developer.aliyun.com/article/1488409