【计算机网络】第 5 篇:TCP 和 UDP 有什么区别?从 Java 后端场景理解两种传输协议

系列: 从 0 开始学习计算机网络

适合读者: 计算机专业学生、网络基础薄弱的开发者、Java 后端学习者

本文关键词: TCP、UDP、可靠传输、字节流、数据报、Java Socket

一、引言:为什么网络通信需要两种传输协议?

访问 Spring Boot 接口、连接 MySQL、进行实时语音通话,都需要在网络上交换数据。但不同应用的要求并不一样:文件下载希望数据完整、有序;实时语音更在意及时性;DNS 查询通常希望用较小的消息快速获得结果。

传输层提供了不同的通信方式,其中最常见的两种协议是 TCP 和 UDP。本文会从实际需求出发,讲清它们的区别、适用场景,以及 Java 中如何使用 Socket 进行简单通信。

二、先看结论:TCP 与 UDP 的核心区别

对比项 TCP UDP
通信方式 面向连接 无连接
数据形式 有序字节流 数据报
是否由协议保证可靠、有序交付 是,连接正常时提供可靠、有序的字节流服务 否
是否保留应用消息边界 不保留 保留数据报边界
确认与重传 TCP 提供相关机制 UDP 本身不提供
流量控制与拥塞控制 TCP 提供相关机制 UDP 本身不提供;上层可另行实现
常见用途 Web 通信、数据库连接、文件传输 DNS 常见查询、实时媒体、部分游戏通信

不要简单地记成"TCP 一定慢,UDP 一定快"。真实应用的速度和延迟还受网络状况、数据大小、连接复用、实现方式和上层协议影响。

三、TCP 是什么?为什么它能可靠、有序地传输数据?

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的传输层协议,为应用提供可靠、有序的字节流。

3.1 面向连接

通信双方在传输数据前,需要建立 TCP 连接。建立连接通常涉及三次握手,连接结束也有相应的关闭过程。"面向连接"不意味着两台电脑之间必须有一条独占的物理线路,而是指 TCP 双方维护连接状态,并按照 TCP 规则进行通信。

3.2 可靠、有序

TCP 使用序列号、确认应答、超时重传等机制处理丢失或乱序的数据。接收方会按字节序号整理数据,并向应用交付有序字节流。TCP 还使用接收窗口进行流量控制,并通过拥塞控制机制调节发送负载。

需要准确理解:TCP 的可靠性是传输层提供的服务,不代表网络故障、进程崩溃或连接中断时,应用一定能完成业务。 连接中断时,应用仍需要处理异常、超时和业务重试。

3.3 字节流:TCP 不保留消息边界

例如客户端连续写入两段数据:

java 复制代码
outputStream.write("hello".getBytes());
outputStream.write("world".getBytes());

接收端读取时,可能一次读到 helloworld,也可能先读到部分内容,再读到剩余内容。TCP 不保证一次 write() 对应一次对端 read(),也不保证一次写入对应一个 TCP 段。

如果业务需要明确的消息边界,应用层必须自行设计协议,例如使用固定长度、长度字段、分隔符,或采用已有的消息协议。

四、UDP 是什么?为什么它适合一些实时场景?

UDP(User Datagram Protocol,用户数据报协议)是一种无连接的数据报传输协议。应用可以把数据作为一个个数据报发送,接收方也按数据报接收。

UDP 的主要特点:

  • 发送前不需要像 TCP 那样建立连接;
  • 保留数据报边界;
  • UDP 本身不保证数据一定到达或按发送顺序到达;
  • UDP 本身不负责重传丢失的数据报,也不提供 TCP 那样的流量控制和拥塞控制。

这并不意味着使用 UDP 的应用完全不能可靠。应用或更高层协议可以在 UDP 之上增加确认、重传、拥塞控制等机制;这些能力不是 UDP 基础协议本身提供的。

实时语音或游戏状态更新有时更重视及时性。如果旧状态已经过时,应用可能选择忽略它,而不是等待重传。具体是否使用 UDP,要结合业务协议和实现判断。

五、TCP 和 UDP 的应用场景

5.1 常见 TCP 场景

  • HTTP/1.1、HTTP/2: 通常运行在 TCP 之上;
  • MySQL 连接: 常见部署中使用 TCP;
  • 文件传输: 通常需要完整、有序的数据;
  • 登录、支付等业务通信: 常需要可靠传输,但业务正确性仍需应用层保障。

5.2 常见 UDP 场景

  • DNS: 常见 DNS 查询使用 UDP,但 DNS 也可以使用 TCP;
  • 实时音视频: 部分实时媒体协议会使用 UDP,并由上层协议处理相关问题;
  • 游戏状态更新: 某些实时状态消息可使用 UDP,具体取决于游戏协议;
  • 局域网发现: 某些发现协议会使用 UDP 广播或组播。

注意:HTTP/3 使用 QUIC,而 QUIC 基于 UDP 传输,并在 QUIC 层实现可靠传输等能力。 不能把"HTTP/3 基于 UDP"理解为"HTTP/3 不可靠",也不能把 QUIC 的能力直接归到 UDP 本身。

六、Java 示例:通过 TCP Socket 发送一条消息

Java 提供 Socket 和 ServerSocket 等类用于 TCP 通信。下面是一个本机教学示例:服务端接收一行文本,并返回一行响应。

6.1 TCP 服务端

保存为 TcpServer.java:

java 复制代码
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

public class TcpServer {
    public static void main(String[] args) throws Exception {
        try (ServerSocket serverSocket = new ServerSocket(8088)) {
            System.out.println("TCP 服务端正在监听 8088 端口");

            try (Socket socket = serverSocket.accept();
                 BufferedReader in = new BufferedReader(
                         new InputStreamReader(
                                 socket.getInputStream(),
                                 StandardCharsets.UTF_8));
                 PrintWriter out = new PrintWriter(
                         socket.getOutputStream(), true,
                         StandardCharsets.UTF_8)) {

                String message = in.readLine();
                System.out.println("收到客户端消息:" + message);
                out.println("服务端已收到:" + message);
            }
        }
    }
}

6.2 TCP 客户端

保存为 TcpClient.java:

java 复制代码
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

public class TcpClient {
    public static void main(String[] args) throws Exception {
        try (Socket socket = new Socket("127.0.0.1", 8088);
             BufferedReader in = new BufferedReader(
                     new InputStreamReader(
                             socket.getInputStream(),
                             StandardCharsets.UTF_8));
             PrintWriter out = new PrintWriter(
                     socket.getOutputStream(), true,
                     StandardCharsets.UTF_8)) {

            out.println("hello TCP");
            System.out.println("服务端响应:" + in.readLine());
        }
    }
}

运行步骤

  1. 使用 JDK 8 或更高版本,将两个类分别保存为 TcpServer.java 和 TcpClient.java。
  2. 在文件所在目录编译:
bash 复制代码
javac TcpServer.java TcpClient.java
  1. 先在一个终端启动服务端:
bash 复制代码
java TcpServer
  1. 再打开另一个终端启动客户端:
bash 复制代码
java TcpClient

在服务端正常运行、端口可用的前提下,客户端会发送一行文本,并等待服务端返回一行响应。这里用 println() 与 readLine() 配合,是因为双方约定以换行符作为消息结束标记。

注意:这只是单客户端的教学示例,不是生产级服务器。生产服务通常还需要循环接收连接、并发处理、超时、异常处理等设计。

七、Java 示例:发送一个 UDP 数据报

UDP 使用 DatagramSocket 和 DatagramPacket。下面展示发送端的基本写法:

java 复制代码
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;

public class UdpSender {
    public static void main(String[] args) throws Exception {
        byte[] data = "hello UDP".getBytes(StandardCharsets.UTF_8);
        InetAddress address = InetAddress.getByName("127.0.0.1");

        try (DatagramSocket socket = new DatagramSocket()) {
            DatagramPacket packet = new DatagramPacket(
                    data, data.length, address, 9090);
            socket.send(packet);
            System.out.println("已调用 UDP 发送接口");
        }
    }
}

这个示例只演示发送端。要真正接收数据,需要另一个程序使用 DatagramSocket(9090) 监听端口并调用 receive()。打印信息只说明程序执行到了发送调用,不代表接收方一定收到数据报。

这正是 UDP 与 TCP 在基础协议语义上的区别之一:UDP 的 send() 调用成功,不等于对端应用已经收到并处理数据报。

八、常见误区

误区 1:TCP 永远比 UDP 慢

不准确。TCP 有连接管理、确认和重传等机制,但实际性能取决于网络状况、数据量、连接复用、实现方式和应用需求。

误区 2:UDP 不可靠,所以不能用于重要业务

不准确。UDP 本身不提供可靠、有序交付,但应用协议可以在 UDP 之上增加所需机制。

误区 3:TCP 一次 write(),对端就会一次 read() 完整读到

不对。TCP 是字节流,不保留应用层消息边界。应用协议需要自己定义消息如何分隔或组装。

误区 4:HTTP 一定使用 TCP

不对。HTTP/1.1 和 HTTP/2 通常使用 TCP;HTTP/3 使用基于 UDP 的 QUIC。

误区 5:TCP 保证业务一定成功

不对。TCP 处理传输层可靠性,但无法保证服务端业务逻辑执行成功、数据库事务提交成功,或客户端一定收到最终业务结果。

九、本篇总结

  1. TCP: 面向连接,提供可靠、有序的字节流;不保留应用写入的消息边界。
  2. UDP: 无连接,提供数据报服务;本身不保证送达、顺序和重传。
  3. 如何选择: 看业务对完整性、顺序、及时性和拥塞处理的要求,而不是简单地认为 TCP 慢、UDP 快。
  4. Java 开发: TCP 常用 Socket / ServerSocket,UDP 常用 DatagramSocket / DatagramPacket。
  5. 重要边界: TCP 的可靠传输不等于业务一定成功;UDP 的基础协议语义也不妨碍上层协议自行实现可靠机制。

下一篇预告:《【计算机网络】第 6 篇:TCP 三次握手和四次挥手,为什么不能少?》。我们会结合连接建立与关闭的状态变化,解释 SYN、ACK、FIN 分别代表什么,以及常见的连接问题。

我是程序员大海,我们下期不见不散.

参考资料

  1. RFC 9293:Transmission Control Protocol (TCP)
  2. RFC 768:User Datagram Protocol (UDP)
  3. RFC 9114:HTTP/3
  4. RFC 9000:QUIC: A UDP-Based Multiplexed and Secure Transport

本文中的地址、端口和代码均为教学示例;没有声称已经在特定环境中运行,也不预设固定的运行结果。

相关推荐
*小海豚*1 小时前
C盘占用大,windows系统清理C盘各软件 MSI 安装/修复缓存
1024程序员节
域智盾-终端安全管理1 小时前
终端安全管理系统:从“边界信任”到“终端零信任”的工程化落地
1024程序员节·终端安全管理系统
xiaogai_gai1 小时前
旺店通采购订单查询接口字段手册:queryWithDetail 实战权威教程
1024程序员节
黑旋风小威1 小时前
新手做网文漫改怎么提速 知漫剧自动拆分剧情分镜
人工智能·1024程序员节
东宇科技1 小时前
crmeb开源版本安装步骤2026-10-20
后端·php·crmeb
爱读书的小胖1 小时前
LeetCode 274 H 指数 C 语言解题分析
c语言·算法·leetcode·1024程序员节
B2_Proxy1 小时前
Scrapy 代理 IP 调度进阶:基于 Redis 与中间件的高可用架构实战
python·scrapy·1024程序员节
文慧的科技江湖1 小时前
2026年10月24日智慧农业行业早报:模型数到175个,棚里的账还按年算
开源·智慧农业·农业物联网·数字乡村·1024程序员节·农业机器人·农业数字化
tryCbest1 小时前
文字转语音Edge-TTS知识学习使用
1024程序员节·文字转语音·edge-tts