UDP和TCP协议
目录
1. UDP协议
1.1. UDP的特性
1.2. UDP的包头
1.3. UDP的三大使用场景和实际例子
1.4. TCP和UDP的区别
2. TCP协议
2.1. TCP包头格式
2.2. TCP包头和UDP包头对比
2.3. TCP协议的特点
2.4. TCP的三次握手(连接维护问题)
2.5. TCP的四次挥手
1. UDP协议
1.1. UDP的特性
- 简单高效: UDP的头部相对简单,只包含基本的字段,如源端口、目标端口、长度和校验和。这使得UDP的处理速度较快,头部开销相对较小。由于不需要建立连接和维护状态信息,UDP在某些情况下比TCP更高效。它适用于实时性要求较高、可以容忍一定数据丢失的应用场景,如音频、视频流传输等。
- 无连接性: UDP是无连接的协议,通信双方在传输数据之前不需要建立连接。每个数据包都是独立的,没有先后顺序,发送端不关心接收端的状态。
- 不可靠性: UDP不提供可靠性保证,它只是尽力而为地把数据发送出去,不保证数据包的顺序和完整性。因此,数据包在传输过程中可能会丢失、重复或者无序。
- 广播和多播: UDP支持广播和多播,能够向多个主机发送数据,而不需要为每个接收者建立单独的连接。这使得UDP在一对多或多对多通信中有一定的优势。
- 无拥塞控制:网络拥塞时仍按固定速率发送。
1.2. UDP的包头
UDP 头部(8 字节):
- 源端口(2 字节):发送方端口号(可选,可置 0)。
- 目标端口(2 字节):接收方端口号。
- 长度(2 字节):UDP 数据报总长度(含头部和数据)。
- 校验和(2 字节):校验数据完整性(IPv4 可选,IPv6 强制)。
UDP 头部极简,仅8字节,无连接管理和可靠性保证的字段。
1.3. UDP的三大使用场景和实际例子
三大使用场景:
- 需要资源少,在网络情况比较好的内网,或者对于丢包不敏感的应用。
- 不需要一对一沟通,建立连接,而是可以广播的应用。
- 需要处理速度快,时延低,可以容忍少数丢包,但是要求即便网络拥塞,也毫不退缩,一往无前的时候。
五个实际例子:
1. 网页或者 APP 的访问
QUIC(全称Quick UDP Internet Connections,快速 UDP 互联网连接)是 Google 提出的一种基于 UDP 改进的通信协议,其目的是降低网络通信的延迟,提供更好的用户互动体验。
QUIC 在应用层上,会自己实现快速连接建立、减少重传时延,自适应拥塞控制,是应用层“城会玩”的代表。
2. 流媒体的协议
当网络不好的时候,TCP 协议会主动降低发送速度,这对本来当时就卡的看视频来讲是要命的,应该应用层马上重传,而不是主动让步。因而,很多直播应用,都基于 UDP 实现了自己的视频传输协议。
3. 实时游戏
游戏对实时要求较为严格的情况下,采用自定义的可靠 UDP 协议,自定义重传策略,能够把丢包产生的延迟降到最低,尽量减少网络问题对游戏性造成的影响。
4. IoT 物联网
一方面,物联网领域终端资源少,很可能只是个内存非常小的嵌入式系统,而维护 TCP 协议代价太大;另一方面,物联网对实时性要求也很高,而 TCP 还是因为上面的那些原因导致时延大。
5. 移动通信领域
在 4G 网络里,移动流量上网的数据面对的协议 GTP-U 是基于 UDP 的。因为移动网络协议比较复杂,而 GTP 协议本身就包含复杂的手机上线下线的通信协议。如果基于 TCP,TCP 的机制就显得非常多余
1.4. TCP和UDP的区别
特性 | TCP | UDP |
连接方式 | 面向连接(三次握手建立连接) | 无连接 |
可靠性 | 可靠传输(无差错、不丢失、按序到达) | 不可靠传输(可能丢包、乱序) |
拥塞控制 | 有拥塞控制机制(动态调整发送速率) | 无拥塞控制(直接发送,不关心网络状态) |
头部开销 | 较大(20-60 字节,复杂字段) | 较小(固定 8 字节,简单字段) |
状态维护 | 维护连接状态(序列号、窗口等) | 无状态 |
适用场景 | 文件传输、网页浏览(需可靠性) | 实时音视频、在线游戏(需低延迟) |
1. 连接性:
- TCP是面向连接的协议,使用三次握手建立可靠的连接。数据传输前,必须先建立连接,之后再进行数据传输,最后释放连接。
- UDP是无连接的协议,通信双方在传输数据之前不需要建立连接。每个数据包都是独立的,发送端不关心接收端的状态。
2. 可靠性:
- TCP提供可靠的数据传输。它使用序号、确认和重传机制来确保数据的完整性和有序性。
- UDP不提供可靠性保证,它只是尽力而为地把数据发送出去,不保证数据包的顺序和完整性。
3. 流控制和拥塞控制:
- TCP具有流控制和拥塞控制机制,以避免网络拥塞和丢失数据。通过调整窗口大小和使用慢启动等算法,TCP可以适应网络的变化。
- UDP不提供流控制和拥塞控制,因此在网络拥塞时可能导致数据丢失。
4. 头部开销:
- TCP的头部开销相对较高,包含序号、确认号、窗口大小等字段,导致额外的网络开销。
- UDP的头部相对简单,只包含源端口、目标端口、长度和校验和等基本字段,开销较小。
5. 适用场景:
- TCP适用于对数据完整性和顺序有严格要求的应用,如文件传输、网页浏览等。
- UDP适用于实时性要求较高、可以容忍一定数据丢失的应用,如音频、视频流传输等
2. TCP协议
2.1. TCP包头格式
TCP 包头包含以下核心字段,用于实现可靠传输和连接管理:
- 源端口和目的端口(各16位):标识发送方和接收方的应用程序端口号。
- 序列号(32位):标记数据字节流的顺序,解决乱序问题。
- 确认号(32位):期望收到的下一个字节的序列号,用于确认数据接收。
- 数据偏移(4位):指示TCP头部的长度(以4字节为单位),最大60字节。
- 标志位(6位):
- SYN:发起连接;
- ACK:确认报文;
- FIN:关闭连接;
- RST:重置连接;
- URG:紧急指针有效;
- PSH:要求立即处理数据。
- 窗口大小(16位):接收方告知发送方可接收的数据量,实现流量控制。
- 校验和(16位):校验数据完整性。
- 紧急指针(16位):标识紧急数据的结束位置。
2.2. TCP包头和UDP包头对比
1. 复杂度
- TCP:头部 20-60 字节,除了UDP包头字段,还包含序列号、确认号、窗口、标志位等字段,支持可靠传输、流量控制、拥塞控制。
- UDP:固定 8 字节,仅含端口、长度、校验和,无连接管理功能。
2. 设计目的
- TCP:面向连接,保证数据可靠、有序,适用于文件传输、网页加载等场景。
- UDP:无连接,轻量高效,适用于实时音视频、在线游戏等低延迟场景。
3. 开销与性能
- TCP:头部开销大,处理逻辑复杂,延迟较高。
- UDP:头部极小,处理速度快,适合高频小包传输。
2.3. TCP协议的特点
掌握 TCP 协议,重点应该关注以下几个问题:
- 顺序问题 ,稳重不乱;
- 丢包问题,承诺靠谱;
- 连接维护,有始有终;
- 流量控制,把握分寸;
- 拥塞控制,知进知退。
2.4. TCP的三次握手(连接维护问题)
“请求 -> 应答 -> 应答之应答”
过程:
- SYN(客户端→服务端):客户端发送初始序列号 seq=x,进入 SYN-SENT 状态。
- SYN-ACK(服务端→客户端):服务端回复 seq=y 和 ack=x+1,进入 SYN-RCVD 状态。
- ACK(客户端→服务端):客户端发送 ack=y+1,双方进入 ESTABLISHED 状态。
一开始,客户端和服务端都处于 CLOSED 状态。先是服务端主动监听某个端口,处于 LISTEN 状态。然后客户端主动发起连接 SYN,之后处于 SYN-SENT 状态。服务端收到发起的连接,返回 SYN,并且 ACK 客户端的 SYN,之后处于 SYN-RCVD 状态。客户端收到服务端发送的 SYN 和 ACK 之后,发送 ACK 的 ACK,之后处于 ESTABLISHED 状态,因为它一发一收成功了。服务端收到 ACK 的 ACK 之后,处于 ESTABLISHED 状态,因为它也一发一收了。
Question:
为什么不是两次或四次?
两次握手:无法防止历史重复连接请求(如延迟的SYN包)导致资源浪费。
三次足够:确保双方确认彼此的发送和接收能力,四次会增加冗余。
三次握手除了双方建立连接外,主要还是为了沟通一件事情,就是TCP 包的序号的问题。
TCP 的 Keepalive 机制
- 作用:检测连接对端是否存活,防止因网络中断或主机崩溃导致的“半打开”连接。
- 工作原理:
- 空闲时间:默认2小时(tcp_keepalive_time)无数据交互后发送探测包。
- 探测机制:发送无数据ACK包,若连续多次(默认9次)无响应则断开连接。
- 与 HTTP Keep-Alive 区别:
TCP Keepalive:网络层保活,检测连接存活;
HTTP Keep-Alive:应用层复用TCP连接,减少握手开销
2.5. TCP的四次挥手
过程:
- FIN(主动方→被动方):主动方发送 FIN,进入 FIN-WAIT-1 状态。
- ACK(被动方→主动方):被动方确认 FIN,进入 CLOSE-WAIT 状态;主动方进入 FIN-WAIT-2。
- FIN(被动方→主动方):被动方处理完数据后发送 FIN,进入 LAST-ACK 状态。
- ACK(主动方→被动方):主动方确认 FIN,进入 TIME-WAIT 状态,等待 2MSL 后关闭。
断开的时候,我们可以看到,当 A 说“不玩了”,就进入 FIN_WAIT_1 的状态,B 收到“A 不玩”的消息后,发送知道了,就进入 CLOSE_WAIT 的状态。
A 收到“B 说知道了”,就进入 FIN_WAIT_2 的状态,如果这个时候 B 直接跑路,则 A 将永远在这个状态。TCP 协议里面并没有对这个状态的处理,但是 Linux 有,可以调整 tcp_fin_timeout 这个参数,设置一个超时时间。
如果 B 没有跑路,发送了“B 也不玩了”的请求到达 A 时,A 发送“知道 B 也不玩了”的 ACK 后,从 FIN_WAIT_2 状态结束,按说 A 可以跑路了,但是最后的这个 ACK 万一 B 收不到呢?则 B 会重新发一个“B 不玩了”,这个时候 A 已经跑路了的话,B 就再也收不到 ACK 了,因而 TCP 协议要求 A 最后等待一段时间 TIME_WAIT,这个时间要足够长,长到如果 B 没收到 ACK 的话,“B 说不玩了”会重发的,A 会重新发一个 ACK 并且足够时间到达 B。
A 直接跑路还有一个问题是,A 的端口就直接空出来了,但是 B 不知道,B 原来发过的很多包很可能还在路上,如果 A 的端口被一个新的应用占用了,这个新的应用会收到上个连接中 B 发过来的包,虽然序列号是重新生成的,但是这里要上一个双保险,防止产生混乱,因而也需要等足够长的时间,等到原来 B 发送的所有的包都死翘翘,再空出端口来。
等待的时间设为 2MSL,MSL是Maximum Segment Lifetime,报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。因为 TCP 报文基于是 IP 协议的,而 IP 头中有一个 TTL 域,是 IP 数据报可以经过的最大路由数,每经过一个处理他的路由器此值就减 1,当此值为 0 则数据报将被丢弃,同时发送 ICMP 报文通知源主机。协议规定 MSL 为 2 分钟,实际应用中常用的是 30 秒,1 分钟和 2 分钟等。
还有一个异常情况就是,B 超过了 2MSL 的时间,依然没有收到它发的 FIN 的 ACK,怎么办呢?按照 TCP 的原理,B 当然还会重发 FIN,这个时候 A 再收到这个包之后,A 就表示,我已经在这里等了这么长时间了,已经仁至义尽了,之后的我就都不认了,于是就直接发送 RST,B 就知道 A 早就跑了。
Question:
为什么不是三次或五次?
全双工特性:双方需独立关闭各自的发送通道。
被动方处理数据:被动方可能需额外时间处理数据后再关闭。