外观
Java 里套接字的 API
⭐ 题目日期:
腾讯 - 2024/12/20
📝 题解:
Java 提供了基于 java.net
包的套接字 API,支持 TCP(面向连接)和 UDP(无连接)协议的网络通信。以下是核心类和关键 API 的详细说明:
一、TCP 套接字(面向连接)
1. 服务端(ServerSocket)
步骤:创建服务端套接字 → 监听连接 → 处理客户端请求 → 关闭资源。 核心类:ServerSocket
、Socket
、InputStream
/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)
步骤:连接服务端 → 发送数据 → 接收响应 → 关闭资源。 核心类:Socket
、InputStream
/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)
核心类:DatagramSocket
、DatagramPacket
(数据包)。 步骤:创建套接字 → 发送/接收数据包 → 关闭资源。
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) | 创建发送数据包。 |
四、注意事项
- 资源释放:
- 使用
try-with-resources
(Java 7+)自动关闭Socket
、ServerSocket
和流。 - 手动调用
close()
确保释放端口和连接。
- 使用
- 异常处理:
- 所有网络操作可能抛出
IOException
,需捕获或声明抛出。
- 所有网络操作可能抛出
- 性能优化:
- 多线程: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 流、资源释放和异常,根据需求选择阻塞或非阻塞模型。