Skip to content

Java 里套接字的 API

约 1058 字大约 4 分钟

Java基础腾讯

2025-03-18

⭐ 题目日期:

腾讯 - 2024/12/20

📝 题解:

Java 提供了基于 java.net 包的套接字 API,支持 TCP(面向连接)和 UDP(无连接)协议的网络通信。以下是核心类和关键 API 的详细说明:


一、TCP 套接字(面向连接)

1. 服务端(ServerSocket)

步骤:创建服务端套接字 → 监听连接 → 处理客户端请求 → 关闭资源。 核心类ServerSocketSocketInputStream/OutputStream

import java.net.*;
import java.io.*;

public class TCPServer {
    public static void main(String[] args) throws IOException {
        // 1. 创建服务端套接字,监听端口 8888
        try (ServerSocket serverSocket = new ServerSocket(8888)) {
            System.out.println("Server started, waiting for clients...");
            
            // 2. 接受客户端连接(阻塞等待)
            Socket clientSocket = serverSocket.accept();
            System.out.println("Client connected: " + clientSocket.getInetAddress());
            
            // 3. 获取输入输出流
            BufferedReader in = new BufferedReader(
                new InputStreamReader(clientSocket.getInputStream()));
            PrintWriter out = new PrintWriter(
                clientSocket.getOutputStream(), true);
            
            // 4. 读取客户端数据并回传
            String request;
            while ((request = in.readLine()) != null) {
                System.out.println("Received: " + request);
                out.println("Echo: " + request); // 发送响应
            }
        }
    }
}

2. 客户端(Socket)

步骤:连接服务端 → 发送数据 → 接收响应 → 关闭资源。 核心类SocketInputStream/OutputStream

import java.net.*;
import java.io.*;

public class TCPClient {
    public static void main(String[] args) throws IOException {
        // 1. 连接服务端(IP: 127.0.0.1, Port: 8888)
        try (Socket socket = new Socket("127.0.0.1", 8888)) {
            System.out.println("Connected to server");
            
            // 2. 获取输入输出流
            BufferedReader in = new BufferedReader(
                new InputStreamReader(socket.getInputStream()));
            PrintWriter out = new PrintWriter(
                socket.getOutputStream(), true);
            
            // 3. 发送数据并接收响应
            out.println("Hello Server!"); // 发送请求
            String response = in.readLine();
            System.out.println("Server response: " + response);
        }
    }
}

二、UDP 套接字(无连接)

1. 服务端与客户端(DatagramSocket)

核心类DatagramSocketDatagramPacket(数据包)。 步骤:创建套接字 → 发送/接收数据包 → 关闭资源。

import java.net.*;

public class UDPServer {
    public static void main(String[] args) throws IOException {
        // 1. 创建 UDP 套接字,监听端口 9999
        try (DatagramSocket socket = new DatagramSocket(9999)) {
            byte[] buffer = new byte[1024];
            
            // 2. 接收数据包
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
            socket.receive(packet); // 阻塞等待
            String message = new String(packet.getData(), 0, packet.getLength());
            System.out.println("Received: " + message);
            
            // 3. 发送响应
            InetAddress clientAddress = packet.getAddress();
            int clientPort = packet.getPort();
            String response = "Echo: " + message;
            byte[] responseData = response.getBytes();
            DatagramPacket responsePacket = new DatagramPacket(
                responseData, responseData.length, clientAddress, clientPort);
            socket.send(responsePacket);
        }
    }
}
import java.net.*;

public class UDPClient {
    public static void main(String[] args) throws IOException {
        // 1. 创建 UDP 套接字(无需指定端口)
        try (DatagramSocket socket = new DatagramSocket()) {
            InetAddress serverAddress = InetAddress.getByName("127.0.0.1");
            String message = "Hello Server!";
            byte[] data = message.getBytes();
            
            // 2. 发送数据包到服务端(端口 9999)
            DatagramPacket sendPacket = new DatagramPacket(
                data, data.length, serverAddress, 9999);
            socket.send(sendPacket);
            
            // 3. 接收响应
            byte[] buffer = new byte[1024];
            DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length);
            socket.receive(receivePacket); // 阻塞等待
            String response = new String(receivePacket.getData(), 0, receivePacket.getLength());
            System.out.println("Server response: " + response);
        }
    }
}

三、关键 API 说明

1. TCP 相关

类/方法说明
ServerSocket(int port)创建服务端套接字,绑定指定端口。
Socket.accept()监听并接受客户端连接(阻塞),返回 Socket 对象。
Socket.getInputStream()获取输入流(接收数据)。
Socket.getOutputStream()获取输出流(发送数据)。

2. UDP 相关

类/方法说明
DatagramSocket(int port)创建 UDP 套接字,绑定指定端口(服务端)。
DatagramSocket()创建未绑定的 UDP 套接字(客户端)。
DatagramPacket(byte[] buf, int length)创建接收数据包。
DatagramPacket(byte[] buf, int length, InetAddress address, int port)创建发送数据包。

四、注意事项

  1. 资源释放
    • 使用 try-with-resources(Java 7+)自动关闭 SocketServerSocket 和流。
    • 手动调用 close() 确保释放端口和连接。
  2. 异常处理
    • 所有网络操作可能抛出 IOException,需捕获或声明抛出。
  3. 性能优化
    • 多线程:TCP 服务端需为每个客户端连接创建新线程,避免阻塞主线程。
    • 缓冲区大小:UDP 数据包大小受网络 MTU 限制(通常 ≤ 1500 字节)。

五、扩展:NIO 非阻塞套接字

Java NIO(java.nio 包)提供非阻塞 IO 模型,适合高并发场景。核心类:

  • Selector:多路复用器,监听多个通道事件。
  • SocketChannel:TCP 通道。
  • DatagramChannel:UDP 通道。

示例片段(NIO TCP 服务端)

Selector selector = Selector.open();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8888));
serverChannel.configureBlocking(false);
serverChannel.register(selector, SelectionKey.OP_ACCEPT); // 注册 Accept 事件

while (true) {
    selector.select(); // 阻塞直到有事件就绪
    Set<SelectionKey> keys = selector.selectedKeys();
    for (SelectionKey key : keys) {
        if (key.isAcceptable()) {
            // 处理新连接
        } else if (key.isReadable()) {
            // 处理读数据
        }
    }
    keys.clear();
}

总结

Java 套接字 API 提供了灵活的网络通信能力:

  • TCP:可靠传输,适合文件传输、HTTP 等场景。
  • UDP:低延迟,适合实时音视频、游戏等场景。
  • 关键点:正确处理 IO 流、资源释放和异常,根据需求选择阻塞或非阻塞模型。