JAVA网络通信

IP地址与 InetAddress 类

在Java网络通信中,IP地址是设备在网络中的唯一标识,而InetAddress类则是Java对IP地址的高层表示,它封装了IP地址和域名的相关信息,并提供了一系列方法来获取和操作这些信息。以下是对IP地址与InetAddress类的详细解析:

一、IP地址基础

  • 定义: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类详解

  • 定义: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类

  1. 定义与功能:

      • URL类是Java网络编程中的一个核心类,用于表示统一资源定位符。

      • 它位于java.net包中,提供了与Web资源交互的功能,包括解析URL字符串、打开与URL相关联的连接、读取和写入数据等。

  2. 构造方法:

      • 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对象。

  3. 常用方法:

      • getProtocol():获取URL的协议部分。

      • getHost():获取URL的主机名。

      • getPort():获取URL的端口号。

      • getPath():获取URL的路径部分。

      • getQuery():获取URL的查询字符串。

      • getFile():获取URL的文件名和查询字符串。

      • getRef():获取URL的片段标识符(锚点)。

      • openConnection():打开与此URL对象关联的连接。

      • openStream():打开一个输入流,以读取此URL表示的资源。

  4. 特点:

      • URL对象是不可变的,保证了线程安全。

      • 使用了策略设计模式来配置不同的URL实例,协议处理器就是策略,URL类构成上下文,通过它来选择不同的策略。

二、URLConnection类

  1. 定义与功能:

      • URLConnection类是一个抽象类,表示应用程序和URL之间的通信连接。

      • 它的实例可用于读取和写入此URL引用的资源。

      • URLConnection允许使用GET、POST或其他HTTP方法请求方式将请求数据发送到服务器。

  2. 子类:

      • HttpURLConnection:用于处理HTTP协议的连接。

      • JarURLConnection:用于处理JAR文件内部的连接(不常用于网络通信)。

  3. 主要方法:

      • 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的值。

  4. 使用步骤:

      • 创建一个URL对象。

      • 通过URL对象的openConnection()方法获取URLConnection对象。

      • 设置连接参数(如请求属性)。

      • 建立连接(对于某些协议可能需要)。

      • 进行数据的读取或写入操作。

      • 关闭连接。

  5. 注意事项:

      • URLConnection是一个抽象类,实际使用时通常是通过它的子类(如HttpURLConnection)来进行操作。

      • 根据不同的协议(如HTTP、FTP等),URLConnection的行为可能会有所不同。因此,在编写代码时需要考虑协议的特性。

      • 在进行网络操作时,需要处理可能发生的异常,如IOException。

      • 使用完连接后,应该关闭它以释放系统资源。

综上所述,URL类和URLConnection类是Java网络通信中的基础类,它们提供了与Web资源交互的强大功能。通过这两个类,Java程序可以轻松地访问和操作远程资源。

应用InetAddress 类

InetAddress类是Java标准库中的一个重要类,用于表示互联网协议(IP)地址。它在Java网络通信中扮演着关键角色,提供了丰富的功能来获取和操作IP地址。以下是对InetAddress类的详细解析:

一、InetAddress类概述

InetAddress类是java.net包的一部分,用于封装IP地址和主机名的映射。它是一个抽象类,具体实现由其子类Inet4Address和Inet6Address提供,分别用于表示IPv4和IPv6地址。

二、InetAddress类的功能

  1. 获取IP地址:

  • getByName(String host):通过主机名或IP地址字符串获取一个InetAddress对象。如果传入的是主机名,则会尝试连接DNS服务器来获取对应的IP地址。

  • getLocalHost():获取本地主机的InetAddress对象,即本机的IP地址。

  • getAllByName(String host):根据主机名返回其可能的所有InetAddress对象,保存在一个数组中。这对于具有多个IP地址的主机特别有用。

  2. 获取主机名:

  • getHostName():获取主机的主机名。如果InetAddress对象是通过主机名创建的,则直接返回该主机名;否则,将执行反向名称查找并返回结果。

  • getCanonicalHostName():获取规范的主机名。这与getHostName()类似,但返回的是更规范的主机名形式。

  3. 判断IP地址类型:

  • isLoopbackAddress():检查是否为回环地址(LoopbackAddress),即127.0.0.1或::1。

  • isMulticastAddress():检查是否为组播地址(Multicast Address)。

  • isAnyLocalAddress():检查是否为通配地址(AnyLocal Address),这种地址用于监听所有可用的网络接口。

  4. 其他功能:

  • getHostAddress():获取主机的IP地址字符串。

  • getAddress():获取原始的IP地址字节数组。

  • toString():返回IP地址的字符串表示,通常包括主机名和IP地址。

  • equals(Object obj)和hashCode():用于比较两个InetAddress对象是否相等,并获取IP地址的哈希码值。

三、InetAddress类的使用场景

  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通信的基本概念

  1. Socket(套接字):

      • Socket是网络通信的端点,由IP地址和端口号唯一标识。

      • 通信的两端都有Socket,数据在两个Socket间通过IO流传输。

  2. IP地址:

      • 用于唯一标识网络中的一台主机。

      • 可以是IPv4地址(如192.168.1.100)或IPv6地址。

  3. 端口号:

      • 用于标识主机上的一个特定应用程序或进程。

      • 端口号的范围是0~65535,其中0~1023被一些知名的网络服务所占用,如HTTP服务通常使用端口80,HTTPS服务使用端口443。

二、Socket通信的协议

Socket通信主要基于两种协议:TCP和UDP。

  1. TCP(Transmission Control Protocol,传输控制协议):

      • 面向连接的、可靠的、基于字节流的传输层通信协议。

      • 在socket之间进行数据传输之前必然要建立连接,所以需要连接时间。

      • TCP传输数据没有大小限制,一旦连接建立起来,双方的socket就可以按统一的格式传输大的数据。

      • 是一个可靠的协议,它确保接收方完全正确地获取发送方所发送的全部数据。

  2. UDP(User Datagram Protocol,用户数据报协议):

      • 面向无连接的传输层协议。

      • 每个数据报中都给出了完整的地址信息,因此无需要建立发送方和接收方的连接。

      • UDP传输数据时是有大小限制的,每个被传输的数据报必须限定在64KB之内。

      • 是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方。

三、Socket通信的Java实现

Java提供了java.net.Socket类和java.net.ServerSocket类来实现网络通信。

  1. ServerSocket类:

      • 主要用于服务器端,可以创建一个服务器套接字,绑定到指定的端口,并监听客户端的连接请求。

      • 当有客户端连接时,它会接受连接并返回一个Socket对象,通过这个Socket对象,服务器就可以与客户端进行通信。

  2. Socket类:

      • 用于客户端和服务器端建立连接后的通信。

      • 客户端通过创建Socket对象并指定服务器的IP地址和端口号来发起连接请求。

      • 连接成功后,就可以通过Socket对象的输入流和输出流进行数据的读写。

四、Socket通信的基本步骤

  1. 创建Socket/ServerSocket实例:

      • 服务器端创建ServerSocket实例,并绑定到指定的端口。

      • 客户端创建Socket实例,并指定服务器的IP地址和端口号。

  2. 建立连接:

      • 服务器端通过ServerSocket的accept()方法等待并处理客户端的请求。

      • 一旦请求被接受,便建立起连接Socket对象。

  3. 数据读写:

      • 利用getInputStream和getOutputStream方法在两端打开输入输出流。

      • 通过输入流读取数据,通过输出流发送数据。

  4. 关闭资源:

      • 关闭所有的流资源和套接字资源,以确保程序的正常结束。

五、Socket通信中的常见问题及解决方案

  1. 数据写入缓冲区未及时刷新至IO流:

      • 默认情况下,写入的数据会暂存于缓冲区中,待缓冲区满时,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协议概述

  • 定义:UDP(User Datagram Protocol)即用户数据报协议,是一种无连接的网络传输协议。

  • 特点:

      • 无连接:发送方直接发送数据,接收方直接接收数据,无需像TCP那样建立连接和维护状态,因此更加轻量级。

      • 不可靠:UDP不保证数据的可靠性和顺序性,数据可能会丢失、重复或乱序到达。协议本身不提供错误检测和重传机制。

      • 面向数据报:将数据分成小块,每个数据块称为数据报。每个UDP数据报都包含了目标地址和端口号,数据报之间相互独立,不建立连接。

      • 低开销:UDP的头部开销小,传输效率高。没有连接建立、维护和终止的开销,也没有复杂的错误控制和流量控制机制。

      • 支持广播和多播:可以向多个目标发送数据。

      • 实时性好:由于没有连接建立和维护的开销,加上较低的协议处理时间,UDP适合实时性要求高的应用,如视频会议、语音通信和在线游戏。

二、Java中的UDP通信

  • 主要类:

      • DatagramSocket:用于创建UDP套接字,用于发送和接收数据报。它提供了基本的网络通信功能,如绑定到特定的IP地址和端口、发送和接收DatagramPacket、管理网络连接的基本设置(例如超时、缓冲区大小)等。

      • DatagramPacket:用于表示一个数据包。它包含发送或接收的数据,以及目标或来源的IP地址和端口。可以封装数据(字节数组),并存储发送或接收数据包的目标或来源信息(IP地址和端口)。

  • 通信过程:

      1. 发送数据:

          • 创建一个DatagramSocket对象(可选地指定发送端的端口号)。

          • 创建一个DatagramPacket对象,将需要发送的数据封装到该对象中,并指定接收端的IP地址和端口号。

          • 调用DatagramSocket对象的send()方法发送数据报。

      2. 接收数据:

          • 创建一个DatagramSocket对象(指定接收端的端口号)。

          • 创建一个空的DatagramPacket对象,用于接收数据报。该对象需要指定一个字节数组来存储接收到的数据,以及该数组的长度。

          • 调用DatagramSocket对象的receive()方法接收数据报。该方法会阻塞,直到接收到一个数据报为止。

          • 从接收到的DatagramPacket对象中获取数据,并处理。

三、UDP通信示例

以下是一个简单的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进行通信时,需要注意数据丢失、超时设置、数据包大小限制和端口占用等问题。

你可能感兴趣的:(java,开发语言)