计算机网络:TCP 和 UDP 的区别是什么?

#计算机网络#操作系统#面试八股

计算机网络:TCP 和 UDP 的区别是什么?

结论:TCP 提供面向连接、可靠、有序的字节流,代价是握手、确认、重传与拥塞控制带来的延迟和开销; UDP 只提供"尽力而为"的数据报,把可靠性、顺序、拥塞控制全部交给应用层,换来低延迟和可自由定制的传输语义。

1. 对比

维度TCPUDP
连接三次握手建立、四次挥手释放无连接,直接发
可靠性确认 + 重传,保证不丢不保证,可能丢、可能重复
有序性序号重排,按序交付不保证顺序
消息边界无,是字节流有,一个数据报一个边界
首部20 字节起,含选项可到 608 字节
流量/拥塞控制有(rwnd、cwnd)无,应用自行处理
传输方式仅单播单播、广播、组播
典型协议HTTP/1.1、MySQL、SSHDNS、DHCP、QUIC、音视频、游戏

2. 首部对比

TCP(20 字节固定首部)
 0        16        31
+---------+---------+
| 源端口  | 目的端口 |
|      序号 seq      |
|    确认号 ack      |
|头长|保留|标志| 窗口 |
| 校验和  | 紧急指针  |
|     选项 + 填充     |
+---------+---------+

UDP(8 字节)
+---------+---------+
| 源端口  | 目的端口 |
|   长度   |  校验和  |
+---------+---------+

多出来的字段就是可靠性的成本:序号与确认号负责排序与重传,窗口负责流量控制, 内核还要为每条连接维护状态(四元组、发送/接收缓冲、若干定时器)。

3. 一个最小的 UDP 服务

// UDP 回显:没有连接、没有重传,丢包由业务自己决定要不要补偿
pc, err := net.ListenPacket("udp", ":9000")
if err != nil {
    log.Fatal(err)
}
defer pc.Close()

buf := make([]byte, 1400) // 留出 IP/UDP 首部余量,避免超过 MTU 触发分片
for {
    n, addr, err := pc.ReadFrom(buf)
    if err != nil {
        return
    }
    if _, err := pc.WriteTo(buf[:n], addr); err != nil {
        log.Printf("write to %s: %v", addr, err)
    }
}

用 nc -u 127.0.0.1 9000 发一行就能验证;把服务端 kill 掉再发包,客户端收不到任何错误—— 这正是"无连接"的直观体现:没人替你记着对端是否还在。

4. 常见追问

Q:DNS 为什么用 UDP? 一问一答、报文小,UDP 省掉握手,解析快一个 RTT。 响应超过 512 字节或带 TC 标志时,解析器会改用 TCP 重查;DoT / DoH 则直接跑在 TCP/TLS 上。

Q:视频会议、游戏为什么用 UDP? 它们要"最新的一帧",不是"完整的历史帧"。丢包重传回来已经过期,反而增加延迟。 所以宁可丢,也要低延迟,再在应用层做 FEC、抖动缓冲、关键帧请求。

Q:QUIC 为什么基于 UDP? TCP 的实现固化在内核与大量中间设备里,改拥塞算法、加多流、做 0-RTT 都很难推进。 UDP 只是一层"可编程管道",QUIC 在用户态实现可靠传输、TLS 1.3 和多路复用,还能绕开 TCP 的队头阻塞。

Q:TCP 一定比 UDP 慢吗? 不一定。连接复用后,TCP 的确认开销在局域网里很小;大流量下拥塞控制反而更"讲道理"。 UDP 快在"建立连接"和"不被重传拖住",不是绝对带宽更高。

Q:UDP 会粘包吗? 不会。UDP 保留消息边界,一次 recvfrom 对应一个数据报。 但超过 MTU 时 IP 层会分片,任一分片丢失整个数据报作废,所以应用层通常把报文控制在 1200~1400 字节。

Q:在 UDP 上做可靠传输要补什么? 包号、确认与重传、乱序缓冲、去重、拥塞控制、流控,再加连接 ID 以支持 NAT 重绑定——这些正是 QUIC 干的事。

小结

TCP 把复杂度收进内核,换来"发出去就当它到了"的编程体验;UDP 把复杂度推给应用,换来延迟与自由。 选型只看业务对"丢一个包"的容忍度:账目、配置、RPC 用 TCP;实时音视频、游戏、DNS 更适合 UDP。 既想可靠又想低延迟时,答案是 QUIC,而不是把 TCP 参数一路调到极限。

笔记加载中…