IP地址与 InetAddress 类
在Java网络通信中,IP地址是设备在网络中的唯一标识,而InetAddress类则是Java对IP地址的高层表示,它封装了IP地址和域名的相关信息,并提供了一系列方法来获取和操作这些信息。以下是对IP地址与InetAddress类的详细解析:
• 定义:IP(Internet Protocol)地址是分配给上网设备的唯一标志,用于指明因特网上的一台计算机在网络中的地址。
• 形式:IP地址通常用四段十进制数表示(每段8位),例如192.168.1.1。此外,还有文字域名表示法,如www.example.com(http://www.example.com)。
• 分类:IP地址分为IPv4和IPv6两种。IPv4使用32位无符号数字表示,而IPv6则使用128位无符号数字表示。
• 特殊地址:
• 本机地址:127.0.0.1(或localhost),称为回送地址或本地回环地址,用于指代当前计算机。
• 私有地址:如192.168.x.x,用于局域网内部使用,不直接暴露在互联网上。
• 定义:InetAddress类是java.net包中的一个类,用于封装IP地址和域名信息。
• 构造函数:InetAddress类没有公开的构造函数,因此不能通过new关键字直接创建对象。相反,它提供了一系列静态工厂方法来创建对象。
• 常用方法:
• getByName(String host):通过主机名或IP地址字符串获取一个InetAddress对象。如果主机名无法解析,将抛出UnknownHostException异常。
• getLocalHost():获取本地主机的InetAddress对象,包含本地机的域名和IP地址。
• getHostName():获取InetAddress对象的主机名。
• getHostAddress():获取InetAddress对象的IP地址字符串。
• isLoopbackAddress():检查是否为回环地址。
• isMulticastAddress():检查是否为组播地址。
• isAnyLocalAddress():检查是否为通配地址。
• getAddress():获取原始的IP地址字节数组。
• toString():返回IP地址的字符串表示,通常包含主机名和IP地址。
• getCanonicalHostName():获取规范的主机名。
• getAllByName(String host):返回指定主机名的所有可能的InetAddress对象(包括IPv4和IPv6地址),这些对象保存在一个数组中。
• DNS解析:InetAddress类使用本地机器配置或网络命名服务(如DNS)来解析主机名到IP地址的映射。为了提高效率,它会缓存一段时间内的解析结果。对于解析不成功的结果,默认缓存时间为10秒(这个时间可以通过系统属性networkaddress.cache.ttl和networkaddress.cache.negative.ttl来控制)。
• 安全性:在默认的安全管理器控制下,不可信代码(如来自第三方或外部系统的代码)在尝试创建InetAddress对象时可能会受到限制。特别是,它们可能只允许获取本地主机的IP地址,而不允许对第三方主机进行DNS查找。
以下是一个简单的示例,演示如何使用InetAddress类来获取本地主机和远程主机的IP地址及主机名:
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressExample {
public static void main(String[] args) {
try {
// 获取本地主机的InetAddress对象
InetAddress localHost = InetAddress.getLocalHost();
System.out.println("本地主机名: " + localHost.getHostName());
System.out.println("本地IP地址: " + localHost.getHostAddress());
// 通过主机名获取远程主机的InetAddress对象
InetAddress remoteHost = InetAddress.getByName("www.baidu.com");
System.out.println("远程主机名: " + remoteHost.getHostName());
System.out.println("远程IP地址: " + remoteHost.getHostAddress());
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
在上面的示例中,我们首先通过getLocalHost()方法获取了本地主机的InetAddress对象,并打印了本地主机名和IP地址。然后,我们通过getByName()方法获取了远程主机(百度)的InetAddress对象,并打印了远程主机名和IP地址。
综上所述,InetAddress类是Java网络通信中处理IP地址和域名的重要工具。它提供了丰富的方法来获取和操作这些信息,使得网络通信变得更加方便和高效。
URL 类和 URLConnection 类
在Java网络通信中,URL(Uniform Resource Locator,统一资源定位符)类和URLConnection类扮演着至关重要的角色。以下是对这两个类的详细解析:
• URL类是Java网络编程中的一个核心类,用于表示统一资源定位符。
• 它位于java.net包中,提供了与Web资源交互的功能,包括解析URL字符串、打开与URL相关联的连接、读取和写入数据等。
• URL(String spec):通过指定的URL字符串创建一个URL对象。
• URL(String protocol, String host, int port, String file):通过指定的协议、主机名、端口号和文件路径创建一个URL对象。
• URL(String protocol, String host, String file):通过指定的协议、主机名和文件路径创建一个URL对象,端口号使用默认值。
• URL(URL context, String spec):通过基URL和相对URL创建一个URL对象。
• getProtocol():获取URL的协议部分。
• getHost():获取URL的主机名。
• getPort():获取URL的端口号。
• getPath():获取URL的路径部分。
• getQuery():获取URL的查询字符串。
• getFile():获取URL的文件名和查询字符串。
• getRef():获取URL的片段标识符(锚点)。
• openConnection():打开与此URL对象关联的连接。
• openStream():打开一个输入流,以读取此URL表示的资源。
• URL对象是不可变的,保证了线程安全。
• 使用了策略设计模式来配置不同的URL实例,协议处理器就是策略,URL类构成上下文,通过它来选择不同的策略。
• URLConnection类是一个抽象类,表示应用程序和URL之间的通信连接。
• 它的实例可用于读取和写入此URL引用的资源。
• URLConnection允许使用GET、POST或其他HTTP方法请求方式将请求数据发送到服务器。
• HttpURLConnection:用于处理HTTP协议的连接。
• JarURLConnection:用于处理JAR文件内部的连接(不常用于网络通信)。
• connect():如果尚未建立连接,则打开到URL引用的资源的通信链接。
• getInputStream():返回一个输入流,用于读取资源信息。
• getOutputStream():返回一个输出流,用于将数据发送到服务器。
• setRequestProperty(String key, String value):设置指定的请求关键字对应的值。
• setDoInput(boolean doinput):设置是否使用URL连接进行输入,默认值为true。
• setDoOutput(boolean dooutput):设置是否使用URL连接进行输出,默认值为false。如果设置为true,就可以获取一个字节输出流,用于将数据发送到服务器。
• setUseCaches(boolean usecaches):设置此连接是否使用任何可用的缓存,默认值为true。
• getHeaderField(String name):返回指定头字段的值。
• getHeaderFields():返回头字段的不可修改的Map。
• getContentType():返回content-type头字段的值。
• getContentEncoding():返回content-encoding的值。
• 创建一个URL对象。
• 通过URL对象的openConnection()方法获取URLConnection对象。
• 设置连接参数(如请求属性)。
• 建立连接(对于某些协议可能需要)。
• 进行数据的读取或写入操作。
• 关闭连接。
• URLConnection是一个抽象类,实际使用时通常是通过它的子类(如HttpURLConnection)来进行操作。
• 根据不同的协议(如HTTP、FTP等),URLConnection的行为可能会有所不同。因此,在编写代码时需要考虑协议的特性。
• 在进行网络操作时,需要处理可能发生的异常,如IOException。
• 使用完连接后,应该关闭它以释放系统资源。
综上所述,URL类和URLConnection类是Java网络通信中的基础类,它们提供了与Web资源交互的强大功能。通过这两个类,Java程序可以轻松地访问和操作远程资源。
应用InetAddress 类
InetAddress类是Java标准库中的一个重要类,用于表示互联网协议(IP)地址。它在Java网络通信中扮演着关键角色,提供了丰富的功能来获取和操作IP地址。以下是对InetAddress类的详细解析:
InetAddress类是java.net包的一部分,用于封装IP地址和主机名的映射。它是一个抽象类,具体实现由其子类Inet4Address和Inet6Address提供,分别用于表示IPv4和IPv6地址。
• getByName(String host):通过主机名或IP地址字符串获取一个InetAddress对象。如果传入的是主机名,则会尝试连接DNS服务器来获取对应的IP地址。
• getLocalHost():获取本地主机的InetAddress对象,即本机的IP地址。
• getAllByName(String host):根据主机名返回其可能的所有InetAddress对象,保存在一个数组中。这对于具有多个IP地址的主机特别有用。
• getHostName():获取主机的主机名。如果InetAddress对象是通过主机名创建的,则直接返回该主机名;否则,将执行反向名称查找并返回结果。
• getCanonicalHostName():获取规范的主机名。这与getHostName()类似,但返回的是更规范的主机名形式。
• isLoopbackAddress():检查是否为回环地址(LoopbackAddress),即127.0.0.1或::1。
• isMulticastAddress():检查是否为组播地址(Multicast Address)。
• isAnyLocalAddress():检查是否为通配地址(AnyLocal Address),这种地址用于监听所有可用的网络接口。
• getHostAddress():获取主机的IP地址字符串。
• getAddress():获取原始的IP地址字节数组。
• toString():返回IP地址的字符串表示,通常包括主机名和IP地址。
• equals(Object obj)和hashCode():用于比较两个InetAddress对象是否相等,并获取IP地址的哈希码值。
1. 网络通信:InetAddress类可以用于网络通信中的地址解析、封装和验证。例如,可以使用getByName()方法将主机名解析为IP地址,或使用getHostAddress()方法获取主机的IP地址。
2. Socket编程:在Socket编程中,可以使用InetAddress类来指定要连接的远程主机的IP地址。它可以帮助建立网络连接、发送和接收数据。
3. 网络服务:InetAddress类可以用于实现网络服务,例如通过getLocalHost()方法获取本机的IP地址,并通过getHostName()方法获取主机名。
4. 安全验证:InetAddress类可以用于验证远程主机的身份。例如,可以使用getCanonicalHostName()方法获取远程主机的规范主机名,然后与预期的主机名进行比较,以确保连接到的是正确的主机。
5. 日志记录和监控:InetAddress类可以用于记录网络请求的来源和目标地址,以及监控网络连接的状态和活动。
1. DNS查找开销:DNS查找可能相当耗时,因此InetAddress类会缓存查找到的结果。默认情况下,成功的DNS查找结果会缓存一段时间,而不成功的查找结果只会缓存很短的时间(如10秒)。
2. 安全性:在默认的安全管理器控制下,不可信代码(如来自第三方或外部系统的代码)可能受到限制,不允许进行任意的DNS查找或创建InetAddress对象。这是为了防止信息泄露和潜在的安全风险。
综上所述,InetAddress类是Java网络通信中一个非常有用的类,它提供了丰富的功能来获取和操作IP地址,适用于各种网络通信和安全验证的场景。
Socket 通信
Java网络通信中的Socket通信是一种底层的通信机制,它允许两个程序通过网络进行双向数据传输。以下是对Java Socket通信的详细解析:
• Socket是网络通信的端点,由IP地址和端口号唯一标识。
• 通信的两端都有Socket,数据在两个Socket间通过IO流传输。
• 用于唯一标识网络中的一台主机。
• 可以是IPv4地址(如192.168.1.100)或IPv6地址。
• 用于标识主机上的一个特定应用程序或进程。
• 端口号的范围是0~65535,其中0~1023被一些知名的网络服务所占用,如HTTP服务通常使用端口80,HTTPS服务使用端口443。
Socket通信主要基于两种协议:TCP和UDP。
• 面向连接的、可靠的、基于字节流的传输层通信协议。
• 在socket之间进行数据传输之前必然要建立连接,所以需要连接时间。
• TCP传输数据没有大小限制,一旦连接建立起来,双方的socket就可以按统一的格式传输大的数据。
• 是一个可靠的协议,它确保接收方完全正确地获取发送方所发送的全部数据。
• 面向无连接的传输层协议。
• 每个数据报中都给出了完整的地址信息,因此无需要建立发送方和接收方的连接。
• UDP传输数据时是有大小限制的,每个被传输的数据报必须限定在64KB之内。
• 是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方。
Java提供了java.net.Socket类和java.net.ServerSocket类来实现网络通信。
• 主要用于服务器端,可以创建一个服务器套接字,绑定到指定的端口,并监听客户端的连接请求。
• 当有客户端连接时,它会接受连接并返回一个Socket对象,通过这个Socket对象,服务器就可以与客户端进行通信。
• 用于客户端和服务器端建立连接后的通信。
• 客户端通过创建Socket对象并指定服务器的IP地址和端口号来发起连接请求。
• 连接成功后,就可以通过Socket对象的输入流和输出流进行数据的读写。
• 服务器端创建ServerSocket实例,并绑定到指定的端口。
• 客户端创建Socket实例,并指定服务器的IP地址和端口号。
• 服务器端通过ServerSocket的accept()方法等待并处理客户端的请求。
• 一旦请求被接受,便建立起连接Socket对象。
• 利用getInputStream和getOutputStream方法在两端打开输入输出流。
• 通过输入流读取数据,通过输出流发送数据。
• 关闭所有的流资源和套接字资源,以确保程序的正常结束。
• 默认情况下,写入的数据会暂存于缓冲区中,待缓冲区满时,JVM才会自动刷新。
• 可以使用PrintWriter类的flush()方法来手动刷新缓冲区,或使用带自动刷新功能的PrintWriter(设置autoflush参数为true,但需注意仅在调用println、printf或format方法时触发)。
2. readLine()方法使用不当导致数据读取异常:
• BufferedReader类的readLine()方法为阻塞型函数,旨在读取一行数据,但不具备识别“一行”数据结束的能力。
• 当使用该方法读取数据后,若输入流中未遇到适当的行结束标志(如换行符),它将持续阻塞。
• 为解除readLine()方法的阻塞并正确返回读取值,需确保输入流中包含必要的行结束标志,并及时调用flush()方法以确保数据已成功写入IO流。
综上所述,Java网络通信中的Socket通信是一种强大且灵活的网络编程方式。通过掌握Socket通信的基本概念、协议、Java实现、基本步骤以及常见问题及解决方案,可以更好地理解和应用Socket通信进行网络通信开发。
UDP
以下是对Java网络通信中UDP的详细知识的归纳:
• 定义:UDP(User Datagram Protocol)即用户数据报协议,是一种无连接的网络传输协议。
• 特点:
• 无连接:发送方直接发送数据,接收方直接接收数据,无需像TCP那样建立连接和维护状态,因此更加轻量级。
• 不可靠:UDP不保证数据的可靠性和顺序性,数据可能会丢失、重复或乱序到达。协议本身不提供错误检测和重传机制。
• 面向数据报:将数据分成小块,每个数据块称为数据报。每个UDP数据报都包含了目标地址和端口号,数据报之间相互独立,不建立连接。
• 低开销:UDP的头部开销小,传输效率高。没有连接建立、维护和终止的开销,也没有复杂的错误控制和流量控制机制。
• 支持广播和多播:可以向多个目标发送数据。
• 实时性好:由于没有连接建立和维护的开销,加上较低的协议处理时间,UDP适合实时性要求高的应用,如视频会议、语音通信和在线游戏。
• DatagramSocket:用于创建UDP套接字,用于发送和接收数据报。它提供了基本的网络通信功能,如绑定到特定的IP地址和端口、发送和接收DatagramPacket、管理网络连接的基本设置(例如超时、缓冲区大小)等。
• DatagramPacket:用于表示一个数据包。它包含发送或接收的数据,以及目标或来源的IP地址和端口。可以封装数据(字节数组),并存储发送或接收数据包的目标或来源信息(IP地址和端口)。
1. 发送数据:
• 创建一个DatagramSocket对象(可选地指定发送端的端口号)。
• 创建一个DatagramPacket对象,将需要发送的数据封装到该对象中,并指定接收端的IP地址和端口号。
• 调用DatagramSocket对象的send()方法发送数据报。
2. 接收数据:
• 创建一个DatagramSocket对象(指定接收端的端口号)。
• 创建一个空的DatagramPacket对象,用于接收数据报。该对象需要指定一个字节数组来存储接收到的数据,以及该数组的长度。
• 调用DatagramSocket对象的receive()方法接收数据报。该方法会阻塞,直到接收到一个数据报为止。
• 从接收到的DatagramPacket对象中获取数据,并处理。
以下是一个简单的Java UDP通信示例,包括发送端和接收端的实现: • 发送端代码:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPSender {
public static void main(String[] args) {
DatagramSocket socket = null;
try {
socket = new DatagramSocket(); // 创建DatagramSocket对象,不指定发送端的端口号,系统会自动分配
InetAddress address = InetAddress.getByName("localhost"); // 指定接收端的IP地址
int port = 9876; // 指定接收端的端口号
String message = "Hello, UDP!";
byte[] buffer = message.getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, address, port); // 创建DatagramPacket对象,封装需要发送的数据
socket.send(packet); // 发送数据报
System.out.println("Message sent: " + message);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (socket != null && !socket.isClosed()) {
socket.close(); // 关闭DatagramSocket对象
}
}
}
}
• 接收端代码:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UDPReceiver {
public static void main(String[] args) {
DatagramSocket socket = null;
try {
socket = new DatagramSocket(9876); // 创建DatagramSocket对象,指定接收端的端口号
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length); // 创建空的DatagramPacket对象,用于接收数据报
socket.receive(packet); // 接收数据报,该方法会阻塞,直到接收到一个数据报为止
String message = new String(packet.getData(), 0, packet.getLength()); // 从接收到的DatagramPacket对象中获取数据,并处理
System.out.println("Message received: " + message);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (socket != null && !socket.isClosed()) {
socket.close(); // 关闭DatagramSocket对象
}
}
}
}
• 数据丢失:由于UDP是无连接的不可靠协议,因此可能会出现数据丢失的情况。在需要高可靠性的场景下,应考虑使用TCP协议或在应用层实现可靠性机制。
• 超时设置:在接收数据时,可以设置超时时间以避免长时间等待。当超过指定时间未接收到数据包时,会抛出SocketTimeoutException异常。可以在异常处理中进行重试或其他处理。
• 数据包大小限制:UDP数据包有大小限制(通常为64KB以内),如果发送的数据超过这个限制,可能会导致数据丢失。可以通过调整数据包大小或分包发送来解决这个问题。
• 端口占用:确保接收端口正确绑定,如果端口被其他程序占用,可能导致数据包无法接收。
综上所述,Java中的UDP通信涉及DatagramSocket和DatagramPacket两个主要类。通过这两个类,可以实现无连接的、不可靠的、面向数据报的通信方式。在使用UDP进行通信时,需要注意数据丢失、超时设置、数据包大小限制和端口占用等问题。