Java 网络编程基于 TCP/IP 协议栈,核心类位于 java.net 包中,核心是通过 Socket 抽象实现进程间通信。
一、网络编程基础原理
-
Socket 通信模型
- 本质:网络通信端点(IP地址 + 端口号),通过输入/输出流传输数据
- 通信流程:
-
TCP vs UDP 核心区别
特性 TCP UDP 连接方式 面向连接(三次握手) 无连接 可靠性 可靠传输(重传机制) 尽力交付(可能丢包) 数据边界 字节流(需处理粘包) 数据报文(自带边界) 适用场景 文件传输、HTTP 视频流、DNS查询 Java 实现类 Socket/ServerSocketDatagramSocket/DatagramPacket
二、TCP Socket 编程详解
1. 服务端实现(含多线程并发)
import java.net.*;
import java.io.*;
import java.util.concurrent.*;
public class ConcurrentServer {
public static void main(String[] args) throws IOException {
ExecutorService pool = Executors.newCachedThreadPool(); // 线程池
try (ServerSocket server = new ServerSocket(8080)) {
System.out.println("服务器启动,等待连接...");
while (true) {
Socket client = server.accept(); // 阻塞等待客户端
pool.execute(() -> handleClient(client)); // 线程处理
}
}
}
private static void handleClient(Socket client) {
try (BufferedReader in = new BufferedReader(
new InputStreamReader(client.getInputStream()));
PrintWriter out = new PrintWriter(client.getOutputStream(), true)) {
String request;
while ((request = in.readLine()) != null) { // 持续读取
System.out.println("客户端["+client.getPort()+"]: " + request);
out.println("ECHO: " + request); // 回传数据
}
} catch (IOException e) {
System.err.println("客户端异常断开: " + e.getMessage());
}
}
}
2. 客户端实现
import java.net.*;
import java.io.*;
public class AdvancedClient {
public static void main(String[] args) throws IOException {
try (Socket socket = new Socket("localhost", 8080);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
BufferedReader stdIn = new BufferedReader(
new InputStreamReader(System.in))) {
System.out.println("已连接服务器,输入消息(exit退出):");
String userInput;
while (!(userInput = stdIn.readLine()).equalsIgnoreCase("exit")) {
out.println(userInput); // 发送消息
System.out.println("服务器回复: " + in.readLine()); // 接收回复
}
}
}
}
三、UDP 编程实战
1. 发送端(支持超时重传)
import java.net.*;
import java.util.concurrent.*;
public class ReliableUDPSender {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket();
socket.setSoTimeout(3000); // 设置接收超时3秒
String message = "重要数据";
byte[] buffer = message.getBytes();
InetAddress address = InetAddress.getByName("localhost");
DatagramPacket packet = new DatagramPacket(
buffer, buffer.length, address, 9999);
// 重传机制(最多3次)
for (int i=0; i<3; i++) {
socket.send(packet);
try {
socket.receive(packet); // 等待ACK
System.out.println("确认送达");
break;
} catch (SocketTimeoutException e) {
System.out.println("超时,第"+(i+1)+"次重发...");
}
}
socket.close();
}
}
2. 接收端(含ACK响应)
import java.net.*;
public class UDPReceiverWithACK {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(9999);
byte[] buffer = new byte[1024];
while (true) {
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet); // 接收数据
String data = new String(
packet.getData(), 0, packet.getLength()
);
System.out.println("收到: " + data);
// 发送ACK确认
byte[] ack = "ACK".getBytes();
DatagramPacket ackPacket = new DatagramPacket(
ack, ack.length, packet.getAddress(), packet.getPort()
);
socket.send(ackPacket);
}
}
}
四、核心工作机制解析
-
TCP 三次握手(连接建立)
sequenceDiagram 客户端->>服务端: SYN=1, seq=x 服务端->>客户端: SYN=1, ACK=1, seq=y, ack=x+1 客户端->>服务端: ACK=1, seq=x+1, ack=y+1 -
粘包/拆包解决方案
- 定长协议:固定每个消息长度(如512字节)
- 分隔符:
out.println(msg)自动添加\n - 头部长度字段:
// 发送端 byte[] data = message.getBytes(); out.writeInt(data.length); // 先写长度 out.write(data); // 再写数据 // 接收端 int length = in.readInt(); byte[] buffer = new byte[length]; in.readFully(buffer); // 读满指定长度
-
NIO 与传统 BIO 对比
特性 BIO (阻塞I/O) NIO (非阻塞I/O) 线程模型 1连接=1线程 1线程处理多连接 资源消耗 高(线程上下文切换) 低(事件驱动) 适用场景 连接数<1000 高并发(如10万+连接) 核心类 ServerSocket/SocketSelector/Channel/Buffer
五、高级应用场景
-
HTTP 客户端实现
URL url = new URL("https://api.example.com/data"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); try (BufferedReader reader = new BufferedReader( new InputStreamReader(conn.getInputStream()))) { // 处理响应数据 } -
WebSocket 通信(需第三方库如
Java-WebSocket) -
RMI 远程方法调用
// 服务端 MyService impl = new MyServiceImpl(); LocateRegistry.createRegistry(1099); Naming.rebind("rmi://localhost/MyService", impl); // 客户端 MyService service = (MyService) Naming.lookup("rmi://localhost/MyService"); service.doSomething();
六、最佳实践与调试
-
资源关闭规范
try (Socket socket = new Socket(...); OutputStream os = socket.getOutputStream()) { // 使用资源 } // 自动关闭 -
网络诊断工具
telnet localhost 8080测试端口连通性- Wireshark 抓包分析协议细节
netstat -ano | findstr 8080查看端口占用
-
常见异常处理
ConnectException:目标服务未启动SocketTimeoutException:网络延迟或阻塞BindException:端口被占用
网络编程的核心是理解协议栈与数据流处理,通过 Socket 抽象实现端到端通信。
思维导图

2995

被折叠的 条评论
为什么被折叠?



