惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
爱范儿
爱范儿
H
Help Net Security
Last Week in AI
Last Week in AI
The Cloudflare Blog
博客园 - 三生石上(FineUI控件)
小众软件
小众软件
IT之家
IT之家
aimingoo的专栏
aimingoo的专栏
大猫的无限游戏
大猫的无限游戏
Jina AI
Jina AI
Google DeepMind News
Google DeepMind News
B
Blog
C
Check Point Blog
T
Tailwind CSS Blog
云风的 BLOG
云风的 BLOG
D
Docker
Recent Announcements
Recent Announcements
Vercel News
Vercel News
博客园 - 聂微东
阮一峰的网络日志
阮一峰的网络日志
MyScale Blog
MyScale Blog
The GitHub Blog
The GitHub Blog
Stack Overflow Blog
Stack Overflow Blog
雷峰网
雷峰网
人人都是产品经理
人人都是产品经理
月光博客
月光博客
F
Fortinet All Blogs
Blog — PlanetScale
Blog — PlanetScale
B
Blog RSS Feed
The Register - Security
The Register - Security
V
Visual Studio Blog
F
Full Disclosure
Hugging Face - Blog
Hugging Face - Blog
T
Threat Research - Cisco Blogs
Latest news
Latest news
PCI Perspectives
PCI Perspectives
Cisco Talos Blog
Cisco Talos Blog
博客园 - Franky
D
DataBreaches.Net
A
Arctic Wolf
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
G
Google Developers Blog
P
Palo Alto Networks Blog
Engineering at Meta
Engineering at Meta
Microsoft Azure Blog
Microsoft Azure Blog
T
Tenable Blog
L
LINUX DO - 热门话题
Spread Privacy
Spread Privacy

蛮荆

如何获取更多的免费服务器 Kubernetes 调度器队列 - 设计与实现 Kubernetes 调度器 - 核心流程 Kubernetes Networking Model & CNI Kubernetes 控制器管理总结 Kubernetes CronJob 设计与实现 Kubernetes Job 设计与实现 Kubernetes HPA 设计与实现 Kubernetes Deployment 滚动更新实现原理 Kubernetes GC 设计与实现 Kubernetes Pod 驱逐 - 设计与实现 Kubernetes Daemonset 设计与实现 Kubernetes ReplicaSet 设计与实现 Kubernetes EndPoint 设计与实现 Kubernetes Informer 设计与实现 降本增效之应用优化 (三) 日志存储与检索 Kubernetes Pod 设计与实现 - 创建流程 Kubernetes 探针设计与实现 Unix 编程艺术名句摘录 Kubernetes - CRI 概述 Golang 编译速度为什么这么快? Kubernetes Pod 设计与实现 - Pause 容器 Kubernetes - kube-proxy 代理模式工程优化 Kubernetes 应用最佳实践 - 优雅关闭长连接 Kubernetes Service 类型和会话亲和性 Kubernetes 为什么需要 Ingress Kubernetes 架构 - 控制平面和数据平面 降本增效之应用优化 (二) 大报表 Go 语言如何获取 CPU 利用率 降本增效之应用优化 (一) Redis 业务规则引擎演变过程简述 微服务中的熔断算法 漏桶算法和令牌桶算法 jsonparser 为什么比标准库的 encoding/json 快 10 倍 ? zap 高性能设计与实现 HTTP Router 算法演进 fastcache 高性能设计与实现 Web 常见的三个安全问题 ants Code Reading Go 线程安全 map 方案选型 布隆过滤器 死锁、活锁、饥饿、自旋锁 sync.Pool Code Reading Go 内存管理概述 Go netpoll Code Reading goroutine 泄漏与检测 time/Timer Code Reading GMP Scheduler Code Reading Go channel 的 15 条规则和底层实现 为什么 Linux “一切皆文件” context.Context Code Reading runtime/HACKING.md Goland 最佳实践 互联网开发与金庸武学 为什么 Redis 6.0 引入多线程模型? Kubernetes 应用最佳实践 - 金丝雀发布 容器中如何正确配置 GOMAXPROCS ? singleflight Code Reading sync.Map Code Reading sync.Cond Code Reading sync.WaitGroup Code Reading sync.RWMutex Code Reading sync.Mutex Code Reading sync.Once Code Reading Go 无锁编程 sync/atomic Code Reading goroutine 交替打印奇偶数 GODEBUG Go 并发模式 Go 汇编 UUID 通用技术选型 Kubernetes 应用最佳实践 - 水平自动伸缩 Go 高性能 Tips fasthttp 为什么比标准库 net/http 快 10 倍 ? 技术文章配图指南 ChatGPT 初体验 Docker 网络原理概览 iptables 的五表五链 Kubernetes 应用最佳实践 - 亲和性和污点容忍度 Go 的反射与三大定律 Docker 官方提供的最佳实践 Go 语言内置的设计模式 HTTP1 到 HTTP3 的工程优化 Kubernetes 应用最佳实践 - Sidecar 模式 Kubernetes 应用最佳实践 - init 容器和钩子函数 为什么 recover 必须在 defer 中调用? 为什么 defer 的执行顺序和注册顺序不同? Go map 设计与实现 Go 切片扩容底层实现 Go 语言中的零拷贝 Go Delve 云原生和边缘计算简介 Kubernetes Pod 服务质量等级 Kubernetes 应用最佳实践 - 探针 Kubernetes 应用最佳实践 - 资源请求和限制 CDN 原理 Kubernetes 应用最佳实践 - 开篇 缓存策略和模式 Go 内存模型 Kubernetes 核心概念
TCP VS UDP 区别
2017-12-12 · via 蛮荆

2017-12-12 计算机网络

概述

TCP 是面向连接的,提供可靠交付、流量控制,拥塞控制,提供全双工通信,面向字节流(把应用层的数据看成字节流,然后根据 MSS 把字节流组织成大小不等的数据段,最后添加 TCP 首部),每个 TCP 连接只能是点对点(一对一)通信。

UDP 是无连接的,尽最大可能交付 (网络 IP 层),不提供流量控制,拥塞控制,面向报文(对于应用程序的数据不合并也不拆分,直接添加 UDP 首部),支持一对一、一对多、多对一和多对多 (也就是多播和广播) 通信。

上面这张图已经概括地很好了,下面就一些细节问题,结合自己的理解进行补充。

头部格式

TCP 头部格式

图片来源: https://nmap.org/book/tcpip-ref.html

UDP 头部格式

图片来源: https://nmap.org/book/tcpip-ref.html

在 UDP 协议头中,只有端口号、包长度和校验码,总共 8 个字节,小巧的头部给它带来了一些优势:

  • 由于 UDP 头部长度还不到 TCP 头部的一半,所以在同样大小的 (IP) 数据包里,UDP 包携带的净数据比 TCP 包多一些
  • 由于 UDP 没有 Seq 和 Ack 等概念,不需要维持一个连接,所以没有建立连接、关闭连接等额外的开销 (这个优势在 DNS 查询中体现得淋漓尽致)

性能

TCP 传输数据时,会有建立连接的三次握手和断开连接的四次 (或者三次) 挥手开销,在短连接业务场景中,建立连接和断开连接占据相当一大部分比重,所以 UDP 的性能要比 TCP 高。

但是如果在长连接业务场景中,当连接持续的时间很长,并且传输了大量的数据,TCP 的性能要比 UDP 高。

MTU

TCP 通信双方会告知对方自己的 MTU, 通信过程中发送的数据包大小以 MTU 较小的一方为基准。同时,TCP 可以避免应用数据被发送方 (网络层) 分片,因为应用数据到了传输层就会被 (TCP) 分片,然后再将切分好的小数据段交给网络层。其中,最大的分段大小称为 MSS(Maximum SegmentSize),它等于把 MTU 大小减去 IP 头部 + TCP 头部之后的大小,所以一个 MSS 正好可以装进一个 MTU 中。

图片来源: Wireshark 网络分析的艺术

$$ MSS = MTU - IP \ Header - TCP\ Header $$

但是有的时候 TCP 头部超过 20 字节,所以会侵占一些 MSS 的空间,比如下图的例子中就占用 12 字节作为 TCPOptions,那传输层真正用来承载数据的就剩下 1500-20-20-12=1448 字节了,这些字节数都能在 Wireshark 中抓包时都可以看到。

图片来源: Wireshark 网络分析的艺术

UDP 无视通信双方的 MTU 大小,获取到应用数据之后,添加上 UDP 头部后直接交给网络层。如果数据 MTU 大小的话,发送方的网络层负责分片 (数据允许分片的前提下),接收方的网络层再将分片后的包组装起来。相对 TCP 来说,数据分片再组装的过程会带来额外的性能消耗。

重传

TCP 要保证所有的数据包可以到达接受端 (传输可靠性),所以必须要有重传机制 (细节本文先省略,后面专门写一篇文章来说一说)。

图片来源: Wireshark 网络分析的艺术

UDP 没有重传机制,所以丢包需要由应用层来处理,所以健壮的 UDP 程序至少需要处理以下两个问题:

  • 发送方在 RTO 时间内,没有收到接收方确认应答,应该重传报文
  • 接收方确保确认应答和请求是正确匹配的

如果某项操作中的一个 (或多个) 数据包丢包了,应用层需要重传该操作中的所有数据包。相比之下,TCP 只需要重传丢失的数据包即可。在海量连接场景中,一个操作可能需要数十个包来完成,UDP 的劣势就会被放大。

但是在理想的网络传输下 (例如内网),数据传输 (几乎) 不会丢包,UDP 要优于 TCP。

不安全因素

网络层的数据分片机制存在弱点 (缺陷),会成为黑客的攻击目标。接收方组装分片的依据是,每个包里都有 More fragments = 1 的 Flag, 1 表示后续还有分片,0 则表示这是最后一个分片。

如果黑客持续快速地发送 More fragments = 1 的 UDP 包,接收方永远无法将这些包组装起来,最终内存耗尽。

多播和广播

UDP 还有一个明显的优势: 支持多播和广播,对于需要在内网中通知多个节点的场景,非常方便和高效。

而如果使用 TCP 实现多播和广播,就需要多个独立的连接才可以完成。


UDP 优化

  1. 增大套接字缓冲区大小以及 UDP 缓冲区范围;
  2. 增大本地端口号的范围;
  3. 根据 MTU 大小,(应用层主动) 调整 UDP 数据包的大小,减少或者避免分片的发生 (例如以太网中,UDP 包大小可以参考 1500-8-20 = 1472 这个值)


UDP VS DNS

由于历史的原因,互联网上物理链路的 最小 MTU = 576,基于 UDP 传输的 DNS 为了限制报文不超过 576,所以将 DNS 报文限制在 512 字节。一旦 DNS 查询应答超过 512 字节,基于 UDP 的 DNS 就只有截短为 512 字节,那么用户得到的 DNS 应答就是不完整的。

为了解决这个问题,最简单的方式就是使用 TCP 重新查询,虽然查询时间可能比较长,但可以得到完整的应答。

那么对大于 576 字节的数据传输,UDP 如何解决呢?答案:网络层数据分片。也就是说,只有 DNS 会限制 UDP 报文的长度,那么,当基于 UDP 传输的 DNS 有 1000 字节需要传输时,会将 1000 字节切成两个 500 字节的报文传输吗?不会!只会保留前面的 512 字节,剩下的 488 字节直接丢掉。


扩展阅读