22 - Java 网络编程

基础知识

网络分层

通信三要素

  • IP 地址:IP 地址是一个 32 位(32bit)或 128 位的二进制数,用于唯一地标识网络中的一个通信实体IPv4 地址被分成了 A、B、C、D、E 五类IPv4 地址通常用“点分十进制”表示成(a.b.c.d)的形式,其中,a, b, c, d 都是 0~255 之间的十进制整数IPv6 有 3 种表示方法,分别是冒分十六进制表示法(如 0:0:0:0:0:0:0:0)、0 位压缩表示法、内嵌 IPv4 地址表示法表示本机:127.0.0.1 localhost 本机 IP本地局域网:10.0.0.0 - 10.255.255.255、192.168.0.0 - 192.168.255.255
  • 端口:端口是一个 16 位的整数,用于表示数据交给哪个通信程序处理,分为:
    • 公认端口:从 0 到 1023
    • 注册端口:从 1024 到 49151
    • 动态和/或私有端口:从 49152 到 65535
  • 协议:Java 默认提供了对 file、ftp、gopher、http、https、jar、mailto、netdoc 协议的支持

软件结构

  • C/S 结构:全称为Client/Server结构,是指客户端和服务器结构。常见程序有QQ、微信等软件。
  • B/S 结构:全称为Browser/Server结构,是指浏览器和服务器结构。常见浏览器有IE、谷歌、火狐等。

socket

socket(套接字):源 IP 地址和目的 IP 地址以及源端口号和目的端口号的组合不同主机之间的进程进行双向通信的端点。
JAVA 中的 Socket 编程是网络编程中非常重要的一部分,它允许不同设备之间进行数据传输。

1.Socket的基本概念

‌定义‌:Socket是网络编程中的一个概念,表示通信的两端。在Java中,Socket类用于表示一个客户端或服务器端的套接字。
‌作用‌:Socket是网络编程中必不可少的一部分,它建立在TCP/IP协议上,用于管理连接、传输数据。客户端Socket用于连接远程服务器,服务器Socket用于侦听客户端请求并与其建立连接。

2. Java中的Socket编程

‌主要类‌:
ServerSocket‌:用于在服务器端监听客户端的连接请求。
服务器应用程序通过使用 java.net.ServerSocket 类以获取一个端口,并且侦听客户端请求。
ServerSocket 类有四个构造方法:
序号
方法描述
1
public ServerSocket(int port) throws IOException
创建绑定到特定端口的服务器套接字。
2
public ServerSocket(int port, int backlog) throws IOException
利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。
3
public ServerSocket(int port, int backlog, InetAddress address) throws IOException
使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。
4
public ServerSocket() throws IOException
创建非绑定服务器套接字。
创建非绑定服务器套接字。 如果 ServerSocket 构造方法没有抛出异常,就意味着你的应用程序已经成功绑定到指定的端口,并且侦听客户端请求。
这里有一些 ServerSocket 类的常用方法:
序号
方法描述
1
public int getLocalPort()
  返回此套接字在其上侦听的端口。
2
public Socket accept() throws IOException
侦听并接受到此套接字的连接。
3
public void setSoTimeout(int timeout)
 通过指定超时值启用/禁用 SO_TIMEOUT,以毫秒为单位。
4
public void bind(SocketAddress host, int backlog)
将 ServerSocket 绑定到特定地址(IP 地址和端口号)。
Socket‌:用于在客户端和服务器端进行通信。
java.net.Socket 类代表客户端和服务器都用来互相沟通的套接字。
客户端要获取一个 Socket 对象通过实例化 ,而 服务器获得一个 Socket 对象则通过 accept() 方法的返回值。
Socket 类有五个构造方法.
序号
方法描述
1
public Socket(String host, int port) throws UnknownHostException, IOException.
创建一个流套接字并将其连接到指定主机上的指定端口号。
2
public Socket(InetAddress host, int port) throws IOException
创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
3
public Socket(String host, int port, InetAddress localAddress, int localPort) throws IOException.
创建一个套接字并将其连接到指定远程主机上的指定远程端口。
4
public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException.
创建一个套接字并将其连接到指定远程地址上的指定远程端口。
5
public Socket()
通过系统默认类型的 SocketImpl 创建未连接套接字
当 Socket 构造方法返回,并没有简单的实例化了一个 Socket 对象,它实际上会尝试连接到指定的服务器和端口。
下面列出了一些感兴趣的方法,注意客户端和服务器端都有一个 Socket 对象,所以无论客户端还是服务端都能够调用这些方法。
序号
方法描述
1
public void connect(SocketAddress host, int timeout) throws IOException
将此套接字连接到服务器,并指定一个超时值。
2
public InetAddress getInetAddress()
 返回套接字连接的地址。
3
public int getPort()
返回此套接字连接到的远程端口。
4
public int getLocalPort()
返回此套接字绑定到的本地端口。
5
public SocketAddress getRemoteSocketAddress()
返回此套接字连接的端点的地址,如果未连接则返回 null。
6
public InputStream getInputStream() throws IOException
返回此套接字的输入流。
7
public OutputStream getOutputStream() throws IOException
返回此套接字的输出流。
8
public void close() throws IOException
关闭此套接字。
InputStream/OutputStream‌:用于数据的读取和写入。
‌基本步骤‌:
1.服务器端通过ServerSocket类创建一个监听特定端口的Socket,等待客户端连接。
2.客户端通过Socket类连接服务器端的IP和端口。
3.连接建立后,双方通过输入/输出流进行数据的读写操作。
4.通信结束后,双方关闭Socket以释放资源。

3. 示例代码

‌服务器端代码‌:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class SimpleServer {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(8888);
            System.out.println("服务器已启动,等待客户端连接...");
            Socket socket = serverSocket.accept();
            System.out.println("客户端已连接:" + socket.getInetAddress().getHostAddress());
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String clientMessage = reader.readLine();
            System.out.println("收到客户端消息:" + clientMessage);
            PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
            writer.println("你好,客户端!");
            reader.close();
            writer.close();
            socket.close();
            serverSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

‌客户端代码‌:
import java.io.*;
import java.net.Socket;

public class SimpleClient {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("localhost", 8888);
            System.out.println("已连接到服务器");
            PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
            writer.println("你好,服务器!");
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String serverMessage = reader.readLine();
            System.out.println("收到服务器消息:" + serverMessage);
            reader.close();
            writer.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

4.常用的协议

‌TCP‌:提供可靠的、面向连接的数据传输服务。适用于要求可靠性和有序性的应用场景,如文件传输、电子邮件和网页浏览等。
‌UDP‌:提供不可靠的、无连接的数据传输服务。适用于实时性要求较高、数据丢失可以容忍的应用场景,如音视频传输和游戏等。

5. 高级应用 

‌多线程服务器‌:为了提高服务器的性能和并发处理能力,可以使用多线程来处理客户端的请求。
‌非阻塞I/O‌:在某些情况下,使用多线程来处理客户端的请求可能会导致资源浪费和性能下降。为了解决这个问题,可以使用非阻塞I/O来处理网络通信。

注意事项

如果某个端口已经被占用,创建ServerSocket时会抛出BindException。此时需要检查该端口是否已经被其他进程使用,可以更换端口或结束冲突的进程。
在使用BufferedReader或其他流读取数据时,通常会出现阻塞的情况,直到对方发送的数据包含换行符或流关闭。因此,使用PrintWriter发送数据时要注意调用println(),而不是print()。
默认情况下,Socket的accept()和read()方法是阻塞的。如果需要设置超时时间,可以使用setSoTimeout(int timeout)方法,避免程序长时间阻塞。

TCP 编程

基础知识

TCP(传输控制协议)是一种面向连接的协议。这意味着在数据传输之前,TCP需要建立一个可靠的连接,确保数据能够按照顺序、无错误地传输到目标端。这种连接是通过“三次握手”过程来建立的,具体包括以下几个步骤:
第一次握手‌:客户端向服务器发送一个SYN(同步序列编号)报文,表示客户端希望建立连接,并包含客户端的初始序列号。
第二次握手‌:服务器收到SYN报文后,会向客户端发送一个SYN-ACK(同步序列编号-确认)报文,表示服务器同意建立连接,并包含服务器的初始序列号和确认号(通常是客户端序列号加1)。
第三次握手‌:客户端收到SYN-ACK报文后,会向服务器发送一个ACK(确认)报文,表示客户端确认了服务器的连接请求,并包含确认号(通常是服务器序列号加1)。
完成这三次握手后,TCP连接就建立起来了,双方就可以开始传输数据了。TCP协议通过序列号、确认号、重传机制、拥塞控制等手段来保证数据传输的可靠性和顺序性。
面向连接的特点使得TCP非常适合需要可靠传输的应用场景,如HTTP、FTP、SMTP等协议都是基于TCP的。然而,面向连接也带来了一些开销,如建立连接和断开连接需要时间和资源,以及传输过程中需要维护连接状态等。因此,在一些对实时性要求较高、数据丢失可以容忍的应用场景中,可能会选择使用无连接的UDP协议。
TCP(传输控制协议)编程在多种网络通信场景中都发挥着关键作用。
以下是一些常见的TCP编程应用场景:
Web浏览‌:HTTP(超文本传输协议)使用TCP作为传输层协议,用于Web页面的加载和数据传输。当用户通过浏览器访问网页时,浏览器会与Web服务器建立TCP连接,请求网页内容,服务器则将网页内容通过TCP连接发送给浏览器。
电子邮件‌:SMTP(简单邮件传输协议)和POP3(邮局协议)等电子邮件协议都使用TCP进行邮件的传输和接收。发送方通过SMTP将邮件发送到服务器,接收方通过POP3从服务器接收邮件,整个过程中TCP确保了邮件数据的完整性和顺序性。
文件传输‌:FTP(文件传输协议)使用TCP进行文件的上传和下载。用户通过FTP客户端与FTP服务器建立TCP连接,进行文件的传输,TCP保证了文件传输的可靠性和顺序性。
远程登录‌:SSH(安全外壳协议)等远程登录协议使用TCP提供安全的远程登录功能。用户通过SSH客户端与远程服务器建立TCP连接,进行远程登录和操作。
即时通讯‌:许多即时通讯应用,如QQ、微信等,使用TCP确保消息的可靠传输。TCP的可靠性和有序性使得这些应用能够提供稳定的即时通讯服务,防止消息的丢失或乱序。
数据库访问‌:数据库管理系统(如MySQL、PostgreSQL等)使用TCP协议实现客户端与服务器之间的可靠数据传输。开发人员通过TCP协议与数据库服务器建立连接,并执行SQL语句进行查询、更新、删除等操作。
远程桌面连接‌:远程桌面协议(如Windows远程桌面、VNC等)使用TCP进行远程桌面连接。用户通过远程桌面客户端与远程服务器建立TCP连接,进行远程操作和访问。
在线游戏和视频会议‌:尽管UDP常用于这些对实时性要求高的应用,但TCP也在某些情况下使用,特别是在需要确保关键数据(如玩家位置更新、控制信号等)的可靠传输时。
分布式数据库系统‌:在分布式数据库系统中,TCP协议也被用于节点之间的通信和数据同步,确保数据的一致性和可靠性。

基本流程

服务器端基本流程:
创建 ServerSocket‌:使用指定的端口号创建一个 ServerSocket 实例。这个实例将监听来自客户端的连接请求。
等待连接‌:调用 ServerSocket 的 accept 方法,该方法会阻塞直到接收到一个连接请求。一旦接收到请求,它会返回一个与客户端通信的 Socket 实例。
获取输入/输出流‌:使用返回的 Socket 实例的 getInputStream 和 getOutputStream 方法获取输入流和输出流,以便与客户端进行数据传输。
处理数据‌:通过输入流读取客户端发送的数据,并通过输出流发送响应数据给客户端。
关闭连接‌:完成数据传输后,调用 Socket 实例的 close 方法关闭连接,并调用 ServerSocket 的 close 方法关闭监听端口(如果不再需要监听其他连接请求)。
客户端基本流程:
创建 Socket‌:使用服务器的 IP 地址或主机名以及端口号创建一个 Socket 实例。这个实例将尝试与服务器建立连接。
获取输入/输出流‌:使用 Socket 实例的 getInputStream 和 getOutputStream 方法获取输入流和输出流,以便与服务器进行数据传输。
发送请求‌:通过输出流发送请求数据给服务器。
接收响应‌:通过输入流读取服务器发送的响应数据。
关闭连接‌:完成数据传输后,调用 Socket 实例的 close 方法关闭连接。

代码示例

以下是一个简单的 Java TCP/IP Socket 编程示例,包括一个服务器程序和一个客户端程序。
服务器程序(Server.java)
import java.io.*;
import java.net.*;

public class Server {
    public static void main(String[] args) {
        int port = 12345; // 服务器监听的端口号
        try (ServerSocket serverSocket = new ServerSocket(port)) {
            System.out.println("服务器已启动,等待客户端连接...");

            // 等待客户端连接
            Socket socket = serverSocket.accept();
            System.out.println("客户端已连接");

            // 获取输入流和输出流
            InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream();

            // 读取客户端发送的数据
            byte[] buffer = new byte;
            int bytesRead = inputStream.read(buffer);
            String message = new String(buffer, 0, bytesRead);
            System.out.println("收到客户端消息: " + message);

            // 发送响应给客户端
            String response = "服务器已收到消息";
            outputStream.write(response.getBytes());

            // 关闭连接
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端程序(Client.java)
import java.io.*;
import java.net.*;

public class Client {
    public static void main(String[] args) {
        String hostname = "localhost"; // 服务器的主机名或IP地址
        int port = 12345; // 服务器的端口号

        try (Socket socket = new Socket(hostname, port)) {
            // 获取输出流和输入流
            OutputStream outputStream = socket.getOutputStream();
            InputStream inputStream = socket.getInputStream();

            // 发送消息给服务器
            String message = "你好,服务器!";
            outputStream.write(message.getBytes());

            // 读取服务器的响应
            byte[] buffer = new byte;
            int bytesRead = inputStream.read(buffer);
            String response = new String(buffer, 0, bytesRead);
            System.out.println("收到服务器响应: " + response);

            // 关闭连接
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行步骤

  1. 先运行服务器程序 Server.java,它会监听指定的端口等待客户端连接。
  2. 然后运行客户端程序 Client.java,它会连接到服务器并发送消息。
  3. 服务器接收到消息后,会打印出来并发送响应给客户端。
  4. 客户端接收到服务器的响应后,也会打印出来。
在这个示例中,服务器和客户端都使用了 Socket 类来建立连接,并使用 InputStream 和 OutputStream 来读取和发送数据。服务器通过 ServerSocket 类来监听端口并接受客户端连接。注意,在实际应用中,应该添加更多的错误处理和资源管理代码来确保程序的健壮性和安全性。

UDP 编程

Java UDP Socket 编程的基本流程可以分为发送方和接收方两个部分。

发送方(客户端)基本流程:

创建 DatagramSocket‌:创建一个 DatagramSocket 实例,它不需要绑定到特定的端口,因为 UDP 是无连接的。
准备数据‌:将要发送的数据转换为字节数组。
创建 DatagramPacket‌:使用目标地址(接收方的 IP 地址或主机名)和端口号,以及准备好的字节数组和数组长度,创建一个 DatagramPacket 实例。
发送数据‌:调用 DatagramSocket 的 send 方法,将 DatagramPacket 发送到接收方。
关闭 DatagramSocket‌(可选):如果不再需要发送数据,可以关闭 DatagramSocket。

接收方(服务器)基本流程:

‌创建并绑定 DatagramSocket‌:创建一个 DatagramSocket 实例,并将其绑定到特定的端口,以便接收来自发送方的数据包。
准备接收缓冲区‌:创建一个字节数组作为接收缓冲区。
创建 DatagramPacket‌:使用接收缓冲区创建一个 DatagramPacket 实例,此时不需要指定目标地址和端口号,因为接收方是等待接收数据的。
接收数据‌:调用 DatagramSocket 的 receive 方法,该方法会阻塞直到接收到数据包,并将数据包的信息填充到 DatagramPacket 实例中。
处理接收到的数据‌:从 DatagramPacket 中提取数据(如使用 getData 方法和 getLength 方法),并进行相应的处理。
关闭 DatagramSocket‌(可选):如果不再需要接收数据,可以关闭 DatagramSocket。

注意事项:

  • UDP 是无连接的,因此发送方不需要等待接收方的响应或确认。
  • UDP 不保证数据包的可靠传输、顺序传输或重复传输。
  • 在实际应用中,可能需要实现一些额外的逻辑来处理数据包的丢失、重复或乱序。
  • DatagramSocket 和 DatagramPacket 类都位于 java.net 包中,因此需要在代码中导入该包。
通过遵循上述基本流程,您可以在 Java 中实现简单的 UDP Socket 通信。

代码示例

发送方程序(Sender.java)
import java.io.*;
import java.net.*;

public class Sender {
    public static void main(String[] args) {
        String hostname = "localhost"; // 接收方的主机名或IP地址
        int port = 9876; // 接收方的端口号

        try (DatagramSocket socket = new DatagramSocket()) {
            // 要发送的消息
            String message = "你好,接收方!";
            byte[] buffer = message.getBytes();

            // 创建DatagramPacket对象,封装消息和接收方地址
            InetAddress address = InetAddress.getByName(hostname);
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length, address, port);

            // 发送数据包
            socket.send(packet);
            System.out.println("消息已发送");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

接收方程序(Receiver.java)
import java.io.*;
import java.net.*;

public class Receiver {
    public static void main(String[] args) {
        int port = 9876; // 接收方监听的端口号

        try (DatagramSocket socket = new DatagramSocket(port)) {
            System.out.println("接收方已启动,等待接收数据...");

            // 创建一个缓冲区来接收数据
            byte[] buffer = new byte;
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

            // 接收数据包
            socket.receive(packet);

            // 从数据包中提取消息
            String message = new String(packet.getData(), 0, packet.getLength());
            System.out.println("收到消息: " + message);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行步骤

  1. 先运行接收方程序 Receiver.java,它会监听指定的端口等待数据包。
  2. 然后运行发送方程序 Sender.java,它会向接收方发送数据包。
  3. 接收方接收到数据包后,会打印出消息内容。
在这个示例中,发送方使用了 DatagramSocket 类来发送数据包,而接收方也使用了 DatagramSocket 类来接收数据包。DatagramPacket 类用于封装要发送或接收的数据以及目标地址和端口信息。注意,由于 UDP 是无连接的,发送方不需要等待接收方的响应,数据包发送后就完成了通信。同时,UDP 也不保证数据包的可靠传输,因此在实际应用中可能需要实现一些错误处理和重传机制来确保数据的可靠性。

URL 编程

URL

  • URI 实例代表一个统一资源标识符,不能用于定位任何资源,唯一作用是解析(resolve)
  • URL 对象代表一个统一资源定位符,通过定位的方式确定一个资源
  • URL 可以由协议名、主机、端口和资源名组成格式:protocol://host:port/resourceName,如 http://www.crazyit.org/index.php
  • 创建 URL 对象URL(String spec):根据 String 表示形式创建 URL 对象URL(String protocol, String host, int port, String file):根据指定协议、主机、端口号(-1,表示使用指定协议的默认端口)和资源文件(如 "/index.php")创建 URL 对象
  • 访问 URL 对应的资源
    • String getFile():获取该 URL 的资源名
    • String getHost():获取该 URL 的主机名
    • String getPath():获取该 URL 的路径部分
    • int getPort():获取该 URL 的端口号
    • String getProtocol():获取该 URL 的协议名称
    • String getQuery():获取该 URL 的査询字符串部分
    • URLConnection openConnection():返回一个 URLConnection 对象,它代表了与 URL 所引用的远程对象的连接
    • InputStream openStream():打开与此 URL 的连接,并返回一个用于读取该 URL 资源的输入流

URLConnection

  • 封装访问远程网络资源一般方法的类
  • 通过 URLConnection 实例向该 URL 发送请求、读取 URL 引用的资源
  • 实例方法
    • InputStream getInputStream():返回该 URLConnection 对应的输入流,用于获取 URLConnection 响应的内容
    • OutputStream getOutputStream():返回该 URLConnection 对应的输出流,用于向 URLConnection 发送请求参数
  • 发送 GET 请求时只需将请求参数放在 URL 字符串之后,以?隔开,程序直接调用 URLConnection 对象的connect() 方法即可
  • 发送 POST 请求,则需要先设置 doln 和 doOut 两个请求头字段的值,再使用 URLConnection 对应的输出流来发送请求参数

基本步骤

‌创建 URL 对象‌:使用要访问的资源的 URL 字符串创建一个 URL 对象。
打开连接‌:通过 URL 对象的 openConnection 方法打开一个到资源的连接,返回一个 URLConnection 对象。
对于需要读取资源内容的场景,通常使用 URL 对象的 openStream 方法直接获取一个输入流。
读取数据‌:如果使用了 openStream 方法,可以直接从返回的 InputStream 读取数据。
如果使用了 openConnection 方法,则可以通过 URLConnection 对象的 getInputStream 方法获取输入流,然后读取数据。
处理异常‌:捕获并处理可能发生的异常,如 MalformedURLException、IOException 等。
关闭资源‌:完成数据读取后,关闭所有打开的资源,包括输入流、连接等。

示例代码

以下是一个简单的 Java URL 编程示例,它从一个网页读取内容并将其打印到控制台:
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.net.URL;
import java.net.MalformedURLException;

public class URLReadExample {
    public static void main(String[] args) {
        String urlString = "http://www.example.com"; // 替换为你要访问的URL

        try {
            // 创建URL对象
            URL url = new URL(urlString);

            // 打开连接并获取输入流
            InputStream inputStream = url.openStream();

            // 使用BufferedReader读取输入流的内容
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }

            // 关闭输入流和BufferedReader
            reader.close();
            inputStream.close();

        } catch (MalformedURLException e) {
            System.err.println("URL格式错误: " + e.getMessage());
        } catch (IOException e) {
            System.err.println("IO异常: " + e.getMessage());
        }
    }
}

Java URL 高级应用通常涉及到更复杂的网络交互,比如发送HTTP请求(GET、POST等)、处理HTTP响应、设置请求头、管理连接超时、处理重定向以及使用HTTPS等安全协议。在Java中,除了基础的java.net.URL类,还可以使用java.net.HttpURLConnection类来更精细地控制HTTP通信。
以下是一个Java URL高级应用的实例,它演示了如何使用HttpURLConnection类发送一个带有请求头的POST请求,并读取响应内容:
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;

public class HttpURLConnectionExample {

    public static void main(String[] args) {
        String targetURL = "https://example.com/api/endpoint"; // 替换为你的目标URL
        String requestMethod = "POST";
        String requestBody = "{\"key1\":\"value1\", \"key2\":\"value2\"}"; // 替换为你的请求体

        HttpURLConnection connection = null;
        BufferedReader reader = null;

        try {
            // 创建URL对象
            URL url = new URL(targetURL);

            // 打开连接
            connection = (HttpURLConnection) url.openConnection();

            // 设置请求方法
            connection.setRequestMethod(requestMethod);

            // 设置请求头
            connection.setRequestProperty("Content-Type", "application/json; utf-8");
            connection.setRequestProperty("Accept", "application/json");
            // 如果需要发送cookie或其他自定义头,也可以在这里设置

            // 允许向连接中写入数据(对于POST请求是必要的)
            connection.setDoOutput(true);

            // 发送请求体
            try (DataOutputStream os = new DataOutputStream(connection.getOutputStream())) {
                byte[] input = requestBody.getBytes(StandardCharsets.UTF_8);
                os.write(input, 0, input.length);
            }

            // 读取响应码
            int responseCode = connection.getResponseCode();
            System.out.println("Response Code: " + responseCode);

            // 读取响应内容
            if (responseCode == HttpURLConnection.HTTP_OK) { // 200
                reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8));
                String line;
                StringBuilder response = new StringBuilder();
                while ((line = reader.readLine()) != null) {
                    response.append(line);
                }
                System.out.println("Response Body: " + response.toString());
            } else {
                System.err.println("Request failed: " + responseCode);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            try {
                if (reader != null) {
                    reader.close();
                }
                if (connection != null) {
                    connection.disconnect();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

注意事项

‌异常处理‌:网络操作容易抛出各种异常,如IOException、ProtocolException等,因此需要进行适当的异常处理。
‌连接管理‌:确保在finally块中关闭所有打开的资源,包括HttpURLConnection和任何用于读取响应的流。
‌请求头和响应头‌:可以通过setRequestProperty方法设置请求头,通过getHeaderField方法读取响应头。
‌超时设置‌:可以使用setConnectTimeout和setReadTimeout方法设置连接超时和读取超时,以避免网络延迟导致的程序挂起。
‌HTTPS支持‌:如果目标URL使用HTTPS协议,Java会自动处理SSL/TLS握手,但你可能需要配置SSL上下文或信任管理器来处理自签名证书或其他SSL相关问题。
‌请求体格式‌:确保请求体的格式与Content-Type头相匹配。在本例中,我们发送的是JSON格式的请求体,因此设置了Content-Type为application/json。
‌响应码检查‌:在读取响应内容之前,先检查响应码(如200表示成功)。对于错误响应码(如404、500等),应进行相应的错误处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿垂爱挖掘

谢谢大家的鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值