目录
- [🌐 28 网络编程------Socket、TCP/UDP与HttpClient](#🌐 28 网络编程——Socket、TCP/UDP与HttpClient)
-
- 一、网络编程基础
-
- [1.1 网络通信三要素](#1.1 网络通信三要素)
- [1.2 TCP与UDP对比](#1.2 TCP与UDP对比)
- [1.3 InetAddress](#1.3 InetAddress)
- 二、TCP编程
-
- [2.1 TCP通信模型](#2.1 TCP通信模型)
- [2.2 TCP服务端](#2.2 TCP服务端)
- [2.3 TCP客户端](#2.3 TCP客户端)
- [2.4 文件传输示例](#2.4 文件传输示例)
- 三、UDP编程
-
- [3.1 UDP发送端](#3.1 UDP发送端)
- [3.2 UDP接收端](#3.2 UDP接收端)
- [四、HttpClient(Java 11+)](#四、HttpClient(Java 11+))
-
- [4.1 同步请求](#4.1 同步请求)
- [4.2 异步请求](#4.2 异步请求)
- [4.3 HttpClient vs 传统HttpURLConnection](#4.3 HttpClient vs 传统HttpURLConnection)
- 五、WebSocket基础
-
- [5.1 WebSocket简介](#5.1 WebSocket简介)
- [5.2 Java WebSocket客户端(Java 11+)](#5.2 Java WebSocket客户端(Java 11+))
- 六、实战:简易聊天室
- 七、常见面试题解析
- 八、总结与下篇预告
-
- 本篇要点
- [📢 下篇预告](#📢 下篇预告)
- [💬 互动话题](#💬 互动话题)
🌐 28 网络编程------Socket、TCP/UDP与HttpClient
更新日期 :2026年5月 | Java入门到精通系列 · 第四阶段·高级特性
© 版权声明:本文为原创技术文章,转载请联系作者并注明出处。
一、网络编程基础
1.1 网络通信三要素
| 要素 | 说明 | 示例 |
|---|---|---|
| IP地址 | 设备的网络标识 | 192.168.1.100 |
| 端口号 | 应用程序的标识(0-65535) | 8080 |
| 协议 | 通信规则 | TCP、UDP、HTTP |
1.2 TCP与UDP对比
| 特性 | TCP | UDP |
|---|---|---|
| 连接方式 | 面向连接(三次握手) | 无连接 |
| 可靠性 | 可靠,保证数据完整 | 不可靠,可能丢包 |
| 传输方式 | 字节流 | 数据报 |
| 速度 | 较慢 | 较快 |
| 适用场景 | 文件传输、网页、邮件 | 视频直播、游戏、DNS |
| Java实现 | Socket / ServerSocket | DatagramSocket / DatagramPacket |
1.3 InetAddress
java
import java.net.InetAddress;
public class InetAddressDemo {
public static void main(String[] args) throws Exception {
// 获取本机地址
InetAddress local = InetAddress.getLocalHost();
System.out.println("本机IP:" + local.getHostAddress());
System.out.println("本机名:" + local.getHostName());
// 根据域名获取地址
InetAddress baidu = InetAddress.getByName("www.baidu.com");
System.out.println("百度IP:" + baidu.getHostAddress());
// 判断是否可达
System.out.println("百度是否可达:" + baidu.isReachable(3000));
}
}
二、TCP编程
2.1 TCP通信模型
服务端(ServerSocket) 客户端(Socket)
│ │
│ accept()等待连接 │ connect()发起连接
│<─────── 三次握手 ──────────────>│
│ │
│ Socket(连接) │ Socket(连接)
│ │
│ getInputStream() │ getOutputStream()
│ 读取客户端数据 │ 发送数据
│ │
│ getOutputStream() │ getInputStream()
│ 发送响应数据 │ 读取响应
│ │
│ close() │ close()
│<─────── 四次挥手 ──────────────>│
2.2 TCP服务端
java
import java.io.*;
import java.net.*;
/**
* TCP服务端
*/
public class TCPServer {
public static void main(String[] args) throws IOException {
// 创建ServerSocket,监听8888端口
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("✅ 服务端启动,监听端口 8888...");
while (true) {
// 等待客户端连接(阻塞)
Socket clientSocket = serverSocket.accept();
System.out.println("客户端已连接:" + clientSocket.getInetAddress());
// 为每个客户端创建一个线程处理
new Thread(() -> handleClient(clientSocket)).start();
}
}
private static void handleClient(Socket clientSocket) {
try (
// 获取输入流(读取客户端数据)
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
// 获取输出流(发送数据给客户端)
PrintWriter out = new PrintWriter(
clientSocket.getOutputStream(), true)
) {
String message;
while ((message = in.readLine()) != null) {
System.out.println("收到:" + message);
// 回复客户端
out.println("服务端收到:" + message);
}
} catch (IOException e) {
System.out.println("客户端断开连接");
} finally {
try { clientSocket.close(); } catch (IOException e) {}
}
}
}
2.3 TCP客户端
java
import java.io.*;
import java.net.*;
import java.util.Scanner;
/**
* TCP客户端
*/
public class TCPClient {
public static void main(String[] args) throws IOException {
// 连接服务端
Socket socket = new Socket("127.0.0.1", 8888);
System.out.println("✅ 已连接服务端");
try (
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(
socket.getOutputStream(), true);
Scanner scanner = new Scanner(System.in)
) {
// 启动接收线程
new Thread(() -> {
try {
String response;
while ((response = in.readLine()) != null) {
System.out.println("服务端:" + response);
}
} catch (IOException e) {}
}).start();
// 主线程发送数据
System.out.println("请输入消息(输入bye退出):");
while (scanner.hasNextLine()) {
String message = scanner.nextLine();
out.println(message);
if ("bye".equalsIgnoreCase(message)) {
break;
}
}
} finally {
socket.close();
System.out.println("已断开连接");
}
}
}
2.4 文件传输示例
java
import java.io.*;
import java.net.*;
/**
* TCP文件传输 - 服务端
*/
public class FileServer {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(9999);
System.out.println("文件服务启动...");
Socket socket = server.accept();
System.out.println("客户端已连接");
try (
DataInputStream dis = new DataInputStream(socket.getInputStream());
FileOutputStream fos = new FileOutputStream("D:/received_" + dis.readUTF())
) {
long fileSize = dis.readLong();
byte[] buffer = new byte[4096];
long totalRead = 0;
int len;
while (totalRead < fileSize && (len = dis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
totalRead += len;
System.out.printf("接收进度:%.1f%%\n", (totalRead * 100.0 / fileSize));
}
System.out.println("✅ 文件接收完成!");
}
socket.close();
server.close();
}
}
/**
* TCP文件传输 - 客户端
*/
class FileClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 9999);
File file = new File("D:/test/document.pdf");
try (
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
FileInputStream fis = new FileInputStream(file)
) {
dos.writeUTF(file.getName()); // 发送文件名
dos.writeLong(file.length()); // 发送文件大小
byte[] buffer = new byte[4096];
int len;
while ((len = fis.read(buffer)) != -1) {
dos.write(buffer, 0, len);
}
dos.flush();
System.out.println("✅ 文件发送完成!");
}
socket.close();
}
}
三、UDP编程
3.1 UDP发送端
java
import java.net.*;
/**
* UDP发送端
*/
public class UDPSender {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket();
String message = "Hello, UDP!";
byte[] data = message.getBytes();
// 创建数据包
DatagramPacket packet = new DatagramPacket(
data, data.length,
InetAddress.getByName("127.0.0.1"), 9998
);
// 发送
socket.send(packet);
System.out.println("消息已发送:" + message);
socket.close();
}
}
3.2 UDP接收端
java
import java.net.*;
/**
* UDP接收端
*/
public class UDPReceiver {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(9998);
System.out.println("UDP接收端已启动,等待消息...");
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
// 接收(阻塞)
socket.receive(packet);
// 解析数据
String message = new String(packet.getData(), 0, packet.getLength());
System.out.println("收到来自 " + packet.getAddress() + " 的消息:" + message);
socket.close();
}
}
四、HttpClient(Java 11+)
4.1 同步请求
java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
/**
* HttpClient同步请求
*/
public class HttpClientSyncDemo {
public static void main(String[] args) throws Exception {
// 创建HttpClient
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.build();
// GET请求
HttpRequest getRequest = HttpRequest.newBuilder()
.uri(URI.create("https://httpbin.org/get"))
.header("User-Agent", "Java HttpClient")
.GET()
.build();
HttpResponse<String> getResponse = client.send(
getRequest, HttpResponse.BodyHandlers.ofString());
System.out.println("GET状态码:" + getResponse.statusCode());
System.out.println("GET响应:" + getResponse.body().substring(0, 200));
// POST请求
HttpRequest postRequest = HttpRequest.newBuilder()
.uri(URI.create("https://httpbin.org/post"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(
"{\"name\":\"张三\",\"age\":25}"))
.build();
HttpResponse<String> postResponse = client.send(
postRequest, HttpResponse.BodyHandlers.ofString());
System.out.println("\nPOST状态码:" + postResponse.statusCode());
}
}
4.2 异步请求
java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.concurrent.CompletableFuture;
/**
* HttpClient异步请求
*/
public class HttpClientAsyncDemo {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://httpbin.org/get"))
.build();
// 异步发送
CompletableFuture<HttpResponse<String>> future =
client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
// 处理响应
future.thenApply(HttpResponse::body)
.thenAccept(body -> System.out.println("异步响应:" + body.substring(0, 100)))
.join(); // 等待完成
// 批量异步请求
for (int i = 0; i < 5; i++) {
final int num = i;
client.sendAsync(
HttpRequest.newBuilder()
.uri(URI.create("https://httpbin.org/get?id=" + num))
.build(),
HttpResponse.BodyHandlers.ofString()
).thenAccept(resp ->
System.out.println("请求" + num + " 完成,状态:" + resp.statusCode())
);
}
Thread.sleep(3000); // 等待所有异步请求完成
}
}
4.3 HttpClient vs 传统HttpURLConnection
| 特性 | HttpClient (Java 11+) | HttpURLConnection |
|---|---|---|
| API设计 | 现代化,流畅API | 老旧,使用繁琐 |
| 异步支持 | 原生支持 | 不支持 |
| HTTP/2 | 支持 | 不支持 |
| WebSocket | 支持 | 不支持 |
| 推荐程度 | ⭐⭐⭐⭐⭐ | ⭐⭐(遗留代码) |
五、WebSocket基础
5.1 WebSocket简介
WebSocket是一种在单个TCP连接上进行全双工通信的协议,适合实时通信场景(聊天、推送、游戏等)。
| 特性 | HTTP | WebSocket |
|---|---|---|
| 通信方式 | 请求-响应(单向) | 全双工(双向) |
| 连接方式 | 短连接(每次请求建立) | 长连接(一次握手) |
| 实时性 | 需要轮询 | 服务端主动推送 |
| 开销 | 每次带HTTP头 | 握手后数据帧开销小 |
5.2 Java WebSocket客户端(Java 11+)
java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.WebSocket;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CompletableFuture;
/**
* WebSocket客户端
*/
public class WebSocketClient {
public static void main(String[] args) throws Exception {
CompletableFuture<WebSocket> wsFuture = new CompletableFuture<>();
WebSocket ws = HttpClient.newHttpClient()
.newWebSocketBuilder()
.buildAsync(URI.create("ws://localhost:8080/ws"), new WebSocket.Listener() {
@Override
public void onOpen(WebSocket webSocket) {
System.out.println("✅ WebSocket连接已建立");
webSocket.request(1); // 请求接收消息
}
@Override
public CompletionStage<?> onText(WebSocket webSocket,
CharSequence data, boolean last) {
System.out.println("收到消息:" + data);
webSocket.request(1); // 请求下一条消息
return null;
}
@Override
public CompletionStage<?> onClose(WebSocket webSocket,
int statusCode, String reason) {
System.out.println("连接关闭:" + reason);
return null;
}
})
.join();
// 发送消息
ws.sendText("Hello, WebSocket!", true);
ws.sendText("这是一条WebSocket消息", true);
Thread.sleep(5000);
ws.sendClose(WebSocket.NORMAL_CLOSURE, "客户端关闭");
}
}
六、实战:简易聊天室
java
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
/**
* TCP聊天室 - 服务端
*/
public class ChatServer {
private static final int PORT = 8888;
// 所有连接的客户端输出流
private static final Set<PrintWriter> clients = ConcurrentHashMap.newKeySet();
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(PORT);
System.out.println("💬 聊天室服务端已启动,端口:" + PORT);
while (true) {
Socket socket = server.accept();
System.out.println("新用户加入:" + socket.getInetAddress());
new ClientHandler(socket).start();
}
}
// 广播消息给所有客户端
private static void broadcast(String message) {
for (PrintWriter writer : clients) {
writer.println(message);
}
}
// 客户端处理线程
static class ClientHandler extends Thread {
private Socket socket;
private String nickname;
private PrintWriter out;
private BufferedReader in;
public ClientHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
// 获取昵称
out.println("请输入你的昵称:");
nickname = in.readLine();
clients.add(out);
broadcast("📢 " + nickname + " 加入了聊天室!(" + clients.size() + "人在线)");
// 接收消息
String message;
while ((message = in.readLine()) != null) {
if ("bye".equalsIgnoreCase(message.trim())) {
break;
}
broadcast(nickname + ":" + message);
}
} catch (IOException e) {
System.out.println(nickname + " 连接异常");
} finally {
clients.remove(out);
broadcast("📢 " + nickname + " 离开了聊天室 (" + clients.size() + "人在线)");
try { socket.close(); } catch (IOException e) {}
}
}
}
}
java
import java.io.*;
import java.net.*;
import java.util.Scanner;
/**
* TCP聊天室 - 客户端
*/
public class ChatClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 8888);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
Scanner scanner = new Scanner(System.in);
// 接收线程
new Thread(() -> {
try {
String message;
while ((message = in.readLine()) != null) {
System.out.println(message);
}
} catch (IOException e) {
System.out.println("与服务器断开连接");
}
}).start();
// 发送消息
while (scanner.hasNextLine()) {
String message = scanner.nextLine();
out.println(message);
if ("bye".equalsIgnoreCase(message)) {
break;
}
}
socket.close();
}
}
七、常见面试题解析
Q1:TCP三次握手和四次挥手的过程?
三次握手:客户端发送SYN → 服务端回复SYN+ACK → 客户端发送ACK。确认双方的发送和接收能力正常。
四次挥手:客户端发送FIN → 服务端回复ACK → 服务端发送FIN → 客户端回复ACK。因为TCP是全双工,需要双向关闭。
Q2:HttpClient比HttpURLConnection好在哪?
HttpClient支持异步请求、HTTP/2、WebSocket,API更现代简洁。HttpURLConnection是Java早期的实现,使用繁琐,功能有限。
八、总结与下篇预告
本篇要点
| 要点 | 说明 |
|---|---|
| TCP编程 | Socket/ServerSocket实现可靠通信 |
| UDP编程 | DatagramSocket/DatagramPacket实现快速通信 |
| HttpClient | Java 11+的现代化HTTP客户端 |
| WebSocket | 全双工实时通信 |
| 网络三要素 | IP、端口、协议 |
📢 下篇预告
第29篇:反射机制------我们将学习Class类、动态代理,了解框架底层的秘密!
💬 互动话题
你做过网络编程相关的项目吗?Socket编程和HTTP请求哪个用得多?欢迎在评论区分享!
参考资料: