文章目录
- 2.2.3 TCP—UDP-QUIC
- 1. TCP如何做到可靠性传输
- 1. ACK机制
- 2. 重传机制
- 3. 序号机制
- 4. 窗口机制
- 5. 流量机制
- 6. 带宽机制
- 2. tcp和udp如何选择
- 1. tcp和udp格式对比
- 2. ARQ协议(Automatic Repeat reQuest,自动重传请求)
- 1. ARQ协议的主要类型
- 2. ARQ协议的关键技术
- 3.RTT和RTO
- 4. 流量控制
- 5. 拥塞控制
- 6. udp并发编程
- 3. udp如何可靠,kcp协议在那些方面有优势
- KCP能否比TCP有更高的带宽?
- KCP协议的优势
- 1. kcp使用
- 1. 函数
- 2. KCP工作流程
- 3. KCP示例代码
- 4. QUIC
- 1. QUIC实现可靠传输的核心机制
- 2. QUIC解决TCP的四大缺陷
- 3. QUIC与HTTP/3的关系
2.2.3 TCP—UDP-QUIC
1. TCP如何做到可靠性传输
1. ACK机制
接收方在成功接收到数据后,会向发送方发送一个确认信号(ACK),告知发送方数据已正确接收。通过ACK机制,发送方可以确认数据是否成功到达接收方,从而决定是否需要重传。
2. 重传机制
重传机制是TCP确保数据可靠传输的核心。当发送方未收到ACK或检测到数据丢失时,会触发重传。主要包括:
- 超时重传:发送方为每个数据段设置重传计时器(RTO),超时未收到ACK则重传。
- 快速重传:发送方收到3个重复ACK后,立即重传丢失的数据段,无需等待超时。
3. 序号机制
TCP通过序号机制为每个数据段分配唯一的序列号(Sequence Number),接收方根据序号对数据段进行排序和重组。序号机制确保数据的有序性和完整性,避免数据丢失或乱序。
4. 窗口机制
窗口机制用于控制发送方的数据发送速率,避免接收方缓冲区溢出。主要包括:
- 接收窗口(RWND):接收方告知发送方当前可接收的数据量。
- 拥塞窗口(CWND):发送方根据网络拥塞情况动态调整发送速率。
- 滑动窗口:发送方在窗口范围内连续发送数据,提高传输效率。
5. 流量机制
流量机制通过控制数据发送速率,避免网络拥塞和接收方过载。主要包括:
- 流量控制:根据接收方的缓冲区大小动态调整发送速率。
- 拥塞控制:通过慢启动、拥塞避免等算法,动态调整发送速率,避免网络拥塞。
6. 带宽机制
带宽机制用于优化网络资源利用率,确保数据传输的高效性。主要包括:
- 带宽分配:根据网络状况和优先级合理分配带宽。
- 带宽限制:通过流量整形和速率限制,避免带宽滥用。
- 带宽监测:实时监测网络带宽使用情况,动态调整传输策略。
2. tcp和udp如何选择
-
tcp 面向字节流
TCP将数据视为连续的字节流,而不是独立的数据包。发送方和接收方之间建立连接后,数据以字节流的形式传输,接收方按顺序接收并重组数据。
类似打电话 -
udp 面向报文
UDP将数据视为独立的数据报(报文),每个数据报都有明确的边界。发送方和接收方之间无需建立连接,数据报直接发送。
类似发短信,每个信息之间是独立的
1. tcp和udp格式对比
特性 | TCP | UDP |
---|---|---|
头部长度 | 20字节(不含选项) | 8字节 |
可靠性 | 可靠传输(确认、重传、排序机制) | 不可靠传输(无确认、重传机制) |
连接性 | 面向连接(需三次握手建立连接) | 无连接(直接发送数据报) |
数据边界 | 无边界(面向字节流) | 有边界(面向报文) |
控制位 | 有(SYN、ACK、FIN等) | 无 |
流量控制 | 有(窗口机制) | 无 |
拥塞控制 | 有(慢启动、拥塞避免等) | 无 |
校验和 | 强制 | 可选 |
适用场景 | 文件传输、网页浏览、电子邮件等 | 视频流、语音通话、在线游戏等 |
可靠指的是可以正常收到而且是顺序收到,ARQ协议就是干这个的
2. ARQ协议(Automatic Repeat reQuest,自动重传请求)
ARQ协议通过确认(ACK)和重传机制,确保数据在传输过程中不丢失、不重复、不乱序
1. ARQ协议的主要类型
(1)停等ARQ(Stop-and-Wait ARQ)
发送方每发送一个数据帧后,等待接收方的ACK。如果收到ACK,则发送下一个帧;如果超时未收到ACK,则重传当前帧
(2)回退N帧ARQ(Go-Back-N ARQ)
发送方可以连续发送多个数据帧,无需等待ACK。如果某个帧丢失或损坏,发送方从该帧开始重传所有后续帧。
(3)选择性重传ARQ(Selective Repeat ARQ)
发送方可以连续发送多个数据帧,接收方对每个帧单独确认。如果某个帧丢失或损坏,发送方仅重传该帧,而不影响其他帧。
2. ARQ协议的关键技术
-
序号机制
为每个数据帧分配唯一的序号,用于标识帧的顺序和检测丢失帧。 -
超时机制
发送方为每个帧设置超时计时器,超时未收到ACK则触发重传。 -
滑动窗口
通过滑动窗口控制发送方和接收方的缓冲区大小,优化数据传输效率。
3.RTT和RTO
RTO(Retransmission Timeout):重传超时时间,动态计算,基于RTT(Round-Trip Time,往返时间)。
RTT测量:通过时间戳或ACK的到达时间计算RTT,并更新RTO。
4. 流量控制
对发送方发送速率的控制,称之为流量控制(发的过快就放缓存,再发的多就TM丢了,大量的丢包会极大着浪费网络资源,要保持接收双方动态稳定)
- 通信双方各有两个滑动窗口:
接收窗口:用于接收数据。
发送窗口(拥塞窗口):用于发送数据。
接收窗口大小的通知称为窗口通告。 - 接收窗口的动态调整
接收窗口的大小不是固定的,而是根据某种算法动态调整,以适应网络环境和发送窗口的变化。
3. 接收窗口的优化
接收窗口并非越大越好。当窗口达到一定值后,继续增大不会显著减少丢包率,反而会增加内存消耗。因此,接收窗口的大小需要根据网络环境和发送窗口动态调整。
4. 发送窗口与接收窗口的关系
发送窗口和接收窗口不一定相等。接收方在发送确认报文时会告知发送方其接收窗口大小,发送方据此调整发送窗口。
由于接收方在处理缓存区数据的同时发送确认报文,因此一般情况下,接收窗口 ≥ 发送窗口。
5. 拥塞控制
- 慢开始
初始阶段:拥塞窗口(cwnd)从1开始,指数增长(每轮次翻倍)。
触发条件:连接建立或检测到网络超时(超时视为严重拥塞)。
阈值作用:初始慢开始阈值(ssthresh)决定何时切换至拥塞避免阶段
- 拥塞避免(Congestion Avoidance)
线性增长:当cwnd ≥ ssthresh时,进入“加法增大”阶段,每轮次cwnd加1。
目标:避免因窗口过快膨胀引发网络拥塞。
- 快恢复(Fast Recovery)
触发条件:收到3个重复ACK(轻度拥塞信号)。
行为:
TCP Reno:将cwnd减半(图中从24降至12),更新ssthresh为新值(12),并直接进入拥塞避免(而非重新慢启动)。
TCP Tahoe(已废弃):直接重置cwnd=1并重新慢开始,效率较低。
6. udp并发编程
3. udp如何可靠,kcp协议在那些方面有优势
KCP能否比TCP有更高的带宽?
在网络通畅的情况下,KCP以10%-20%带宽浪费的代价,换取了比TCP快30%-40%的传输速度。
KCP协议的优势
-
流量不一定最多
KCP的传输速率可能低于TCP,但延迟更低,适合实时性要求高的场景。 -
RTO翻倍 vs 不翻倍
- TCP超时计算是RTO×2,连续丢三次包后RTO变为×8,非常保守。
- KCP在快速模式下RTO仅×1.5(实验证明1.5效果较好),显著提升传输速度。
-
选择性重传 vs 全部重传
- TCP丢包时会重传从丢失包开始后的所有数据(Go-Back-N)。
- KCP采用选择性重传,仅重传真正丢失的数据包,减少冗余。
-
快速重传
- 使用快速重传时,无需等待RTO超时。
- 示例:发送端发送1,2,3,4,5,收到ACK:1,3,4,5。当收到ACK3时,KCP知道2被跳过1次;收到ACK4时,知道2被跳过2次,立即重传2号包。
- 参数:
fastresend = 2
-
延迟ACK vs 非延迟ACK
- TCP为了充分利用带宽,延迟发送ACK,导致RTT时间计算偏大,延长丢包判断过程
- KCP的ACK延迟发送可调节,灵活性更高
-
UNA vs ACK+UNA
- ARQ模型有两种响应方式:UNA(此编号前所有包已收到,如TCP)和ACK(该编号包已收到)。
- 仅用UNA会导致全部重传,仅用ACK则增加网络负载
- KCP协议中,除单独的ACK包外,所有包都携带UNA信息,结合两者优势
比如:
发送端发送序列号1、2、3、4、5。
接收端收到1、2、4、5,丢失3。
接收端发送UNA=3(表示1、2已接收),并发送ACK=4、ACK=5(确认4、5已接收)。
发送端根据UNA=3知道3丢失,立即重传3,而无需重传4、5。
-
非退让流控
- KCP正常模式与TCP一样使用公平退让法则,发送窗口大小由以下四要素决定:
- 发送缓存大小
- 接收端剩余接收缓存大小
- 丢包退让 (当检测到丢包时,减少发送窗口大小,避免进一步加剧网络拥塞。)
- 慢启动
- 在传送及时性要求高的小数据场景中,可通过配置跳过后两步(丢包退让和慢启动机制会降低发送速率,导致传输延迟增加),仅用前两项控制发送频率。
- KCP正常模式与TCP一样使用公平退让法则,发送窗口大小由以下四要素决定:
KCP通过牺牲少量带宽,显著提升了传输速度和实时性,特别适合高延迟、高丢包网络环境(如实时音视频、竞技类网游)。
1. kcp使用
1. 函数
- **
kcp_create
**
- 功能:创建KCP对象。
- 参数:
conv
:会话ID,用于标识KCP连接。user
:用户自定义数据,通常为NULL。
- 返回值:KCP对象指针。
- 示例:
ikcpcb *kcp = ikcp_create(conv, user);
- kcp_update
功能:更新KCP状态,触发内部定时任务(如超时重传、窗口更新等)。
参数:
kcp:KCP对象指针。
current:当前时间戳(毫秒)。
示例:
ikcp_update(kcp, current);
- kcp_send
功能:发送数据。
参数:
kcp:KCP对象指针。
buffer:待发送的数据缓冲区。
len:数据长度。
返回值:成功返回0,失败返回负值。
示例:
int ret = ikcp_send(kcp, buffer, len);
- kcp_input
功能:接收数据并处理(如解析KCP协议头、更新ACK等)。
参数:
kcp:KCP对象指针。
data:接收到的数据缓冲区。
size:数据长度。
返回值:成功返回0,失败返回负值。
示例:
int ret = ikcp_input(kcp, data, size);
- kcp_recv
功能:从KCP接收缓冲区中读取应用层数据。
参数:
kcp:KCP对象指针。
buffer:接收数据的缓冲区。
len:缓冲区长度。
返回值:实际读取的数据长度。
示例:
int len = ikcp_recv(kcp, buffer, sizeof(buffer));
2. KCP工作流程
- 初始化阶段
调用kcp_create创建KCP对象。
设置KCP参数(如窗口大小、超时时间等)。 - 数据发送流程
应用层调用kcp_send发送数据。
KCP内部将数据分片,添加KCP协议头(24字节)。
调用output回调函数发送数据包。
定时调用kcp_update触发重传和窗口更新。 - 数据接收流程
网络层接收到数据包,调用kcp_input处理。
KCP解析协议头,更新ACK和窗口状态。
应用层调用kcp_recv读取数据。 - 定时任务
定期调用kcp_update,处理超时重传、窗口更新等任务。
3. KCP示例代码
- 初始化KCP
ikcpcb *kcp = ikcp_create(conv, user);
ikcp_wndsize(kcp, 128, 128); // 设置窗口大小
ikcp_nodelay(kcp, 1, 10, 2, 1); // 启用快速模式
- 发送数据
char buffer[1024];
int len = sprintf(buffer, "Hello, KCP!");
ikcp_send(kcp, buffer, len);
- 接收数据
char buffer[1024];
int len = ikcp_recv(kcp, buffer, sizeof(buffer));
if (len > 0) {
printf("Received: %s\n", buffer);
}
- 定时更新
while (1) {
sleep_ms(10);
ikcp_update(kcp, current_ms());
}
- 集成
#include "ikcp.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
// 回调函数:发送 KCP 数据包
int output(const char *buf, int len, ikcpcb *kcp, void *user) {
int sockfd = *(int*)user;
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8888);
inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
sendto(sockfd, buf, len, 0, (struct sockaddr*)&addr, sizeof(addr));
return 0;
}
int main() {
// 创建 UDP 套接字
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket");
exit(1);
}
// 初始化 KCP 对象
ikcpcb *kcp = ikcp_create(0x11223344, &sockfd);
ikcp_wndsize(kcp, 128, 128); // 设置窗口大小
ikcp_nodelay(kcp, 1, 10, 2, 1); // 启用快速模式
ikcp_setoutput(kcp, output); // 设置回调函数
// 发送数据
char send_buffer[1024];
int send_len = sprintf(send_buffer, "Hello, KCP!");
ikcp_send(kcp, send_buffer, send_len);
// 接收数据
char recv_buffer[1024];
while (1) {
// 接收网络数据
struct sockaddr_in addr;
socklen_t addr_len = sizeof(addr);
int recv_len = recvfrom(sockfd, recv_buffer, sizeof(recv_buffer), 0, (struct sockaddr*)&addr, &addr_len);
if (recv_len > 0) {
// 处理 KCP 协议包
ikcp_input(kcp, recv_buffer, recv_len);
// 读取应用数据
int len = ikcp_recv(kcp, recv_buffer, sizeof(recv_buffer));
if (len > 0) {
printf("Received: %s\n", recv_buffer);
}
}
// 定时更新 KCP 状态
ikcp_update(kcp, current_ms());
usleep(10000); // 10ms
}
// 释放 KCP 对象
ikcp_release(kcp);
close(sockfd);
return 0;
}
4. QUIC
1. QUIC实现可靠传输的核心机制
- Packet Number严格递增
每个数据包分配唯一且严格递增的序列号(Packet Number),即使重传数据包也会使用新序列号。
- 优势:
消除TCP重传歧义问题,精确计算RTT(往返时间),优化超时重传策略。
支持乱序确认,避免因单个数据包丢失阻塞后续传输(解决队头阻塞)。
- Frame Header设计
每个数据包包含多个Frame,通过以下字段保证数据顺序和可靠性:
Stream ID:标识不同的并发数据流(类似HTTP/2的Stream)。
Offset:标记数据在流中的偏移量(类似TCP的序列号)。
Length:数据长度。
- 作用:通过Stream ID + Offset唯一标识数据内容,即使重传数据包的Packet Number不同,也能正确重组数据。
- 流量控制
Stream级流量控制:每个Stream独立维护滑动窗口,互不影响。
Connection级流量控制:限制所有Stream的总数据量,防止整体过载。
- 实现方式:
通过WINDOW_UPDATE帧动态调整窗口大小。
通过BLOCKED帧通知发送方流量阻塞。
- 拥塞控制改进
默认使用TCP的Cubic算法,同时支持BBR、PCC等算法。
- 优势:
在应用层实现,无需内核支持,灵活升级算法。
可为不同应用定制拥塞策略(如视频流与文件传输使用不同算法)。
2. QUIC解决TCP的四大缺陷
- 协议升级困难
TCP协议栈内置于操作系统,升级依赖内核更新;QUIC在应用层实现,通过更新浏览器或应用即可部署新特性。
2. 连接建立延迟
1-RTT握手:QUIC将TLS 1.3集成到协议中,首次连接仅需1个RTT完成密钥协商和连接建立。
0-RTT恢复:会话恢复时可直接发送数据,无需握手。
3. 队头阻塞问题
Stream独立滑动窗口:每个HTTP请求(Stream)拥有独立窗口,某个Stream丢包不影响其他Stream。
乱序确认:基于Packet Number和Offset,允许接收方乱序确认数据包。
4. 网络迁移需重建连接
连接ID标识:QUIC通过连接ID(而非IP+端口)标识连接,网络切换(如4G转WiFi)时无需重建连接,实现无缝迁移。
3. QUIC与HTTP/3的关系
HTTP/3基于QUIC协议,将传输层从TCP替换为QUIC,彻底解决HTTP/2的TCP队头阻塞问题。
QUIC在UDP报文头部与HTTP数据之间添加三层头部:
- Long/Short Packet Header:管理连接ID与数据包编号。
- QUIC Frame Header:标识Stream及数据偏移。
- HTTP/3帧:承载实际应用数据。