28 网络编程——Socket、TCP/UDP与HttpClient

目录

  • [🌐 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请求哪个用得多?欢迎在评论区分享!


参考资料

相关推荐
云飞云共享云桌面2 小时前
SolidWorks服务器+云飞云共享云桌面 = 10人共享方案
linux·运维·服务器·网络·制造
二月夜9 小时前
剖析Java正则表达式回溯问题
java·正则表达式
xuhaoyu_cpp_java10 小时前
项目学习(三)分页查询
java·经验分享·笔记·学习
皮皮学姐分享-ppx10 小时前
政府绿色采购数据库(2015-2024.3)
大数据·网络·数据库·人工智能·制造
程序员二叉10 小时前
【Java】集合面试全套精讲|HashMap/ArrayList高频考点完整版
java·面试·哈希算法
W_chuanqi10 小时前
联想M7615DNA网络打印方法
网络·联想·打印机网络连接
cfm_291410 小时前
JVM GC垃圾回收初步了解
java·开发语言·jvm
心之伊始10 小时前
LangChain4j RAG 实战:Java 后端如何把本地文档接入 Embedding 检索链路
java·架构·源码分析·csdn
许彰午11 小时前
17_synchronized关键字深度解析
java·开发语言