2.2.3 TCP—UDP-QUIC

发布于:2025-03-13 ⋅ 阅读:(12) ⋅ 点赞:(0)

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如何选择

  1. tcp 面向字节流
    TCP将数据视为连续的字节流,而不是独立的数据包。发送方和接收方之间建立连接后,数据以字节流的形式传输,接收方按顺序接收并重组数据。
    类似打电话

  2. 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协议的关键技术
  1. ​序号机制
    为每个数据帧分配唯一的序号,用于标识帧的顺序和检测丢失帧。

  2. ​超时机制
    发送方为每个帧设置超时计时器,超时未收到ACK则触发重传。

  3. ​滑动窗口
    通过滑动窗口控制发送方和接收方的缓冲区大小,优化数据传输效率。

3.RTT和RTO

RTO(Retransmission Timeout)​:重传超时时间,动态计算,基于RTT(Round-Trip Time,往返时间)。
​RTT测量:通过时间戳或ACK的到达时间计算RTT,并更新RTO。

4. 流量控制

对发送方发送速率的控制,称之为流量控制(发的过快就放缓存,再发的多就TM丢了,大量的丢包会极大着浪费网络资源,要保持接收双方动态稳定)

  1. 通信双方各有两个滑动窗口:
    ​接收窗口:用于接收数据。
    ​发送窗口(拥塞窗口)​:用于发送数据。
    接收窗口大小的通知称为窗口通告。
  2. ​接收窗口的动态调整

接收窗口的大小不是固定的,而是根据某种算法动态调整,以适应网络环境和发送窗口的变化。
3. ​接收窗口的优化

接收窗口并非越大越好。当窗口达到一定值后,继续增大不会显著减少丢包率,反而会增加内存消耗。因此,接收窗口的大小需要根据网络环境和发送窗口动态调整。
4. ​发送窗口与接收窗口的关系

发送窗口和接收窗口不一定相等。接收方在发送确认报文时会告知发送方其接收窗口大小,发送方据此调整发送窗口。
由于接收方在处理缓存区数据的同时发送确认报文,因此一般情况下,​接收窗口 ≥ 发送窗口。

5. 拥塞控制

在这里插入图片描述

  1. ​慢开始

​初始阶段:拥塞窗口(cwnd)从1开始,​指数增长​(每轮次翻倍)。
​触发条件:连接建立或检测到网络超时(超时视为严重拥塞)。
​阈值作用:初始慢开始阈值(ssthresh)决定何时切换至拥塞避免阶段

  1. ​拥塞避免(Congestion Avoidance)​

​线性增长:当cwnd ≥ ssthresh时,进入“加法增大”阶段,每轮次cwnd加1。
​目标:避免因窗口过快膨胀引发网络拥塞。

  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一样使用公平退让法则,发送窗口大小由以下四要素决定:
      1. 发送缓存大小
      2. 接收端剩余接收缓存大小
      3. 丢包退让 (当检测到丢包时,减少发送窗口大小,避免进一步加剧网络拥塞。)
      4. 慢启动
    • 在传送及时性要求高的小数据场景中,可通过配置跳过后两步(​丢包退让和慢启动机制会降低发送速率,导致传输延迟增加),仅用前两项控制发送频率。

KCP通过牺牲少量带宽,显著提升了传输速度和实时性,特别适合高延迟、高丢包网络环境(如实时音视频、竞技类网游)。

1. kcp使用

在这里插入图片描述

1. 函数
  1. ​**kcp_create**
  • 功能:创建KCP对象。
  • 参数
    • conv:会话ID,用于标识KCP连接。
    • user:用户自定义数据,通常为NULL。
  • 返回值:KCP对象指针。
  • 示例
    ikcpcb *kcp = ikcp_create(conv, user);
    
  1. kcp_update
    ​功能:更新KCP状态,触发内部定时任务(如超时重传、窗口更新等)。
    ​参数:
    kcp:KCP对象指针。
    current:当前时间戳(毫秒)。
    ​示例:
ikcp_update(kcp, current);
  1. kcp_send
    ​功能:发送数据。
    ​参数:
    kcp:KCP对象指针。
    buffer:待发送的数据缓冲区。
    len:数据长度。
    ​返回值:成功返回0,失败返回负值。
    ​示例:
int ret = ikcp_send(kcp, buffer, len);
  1. kcp_input
    ​功能:接收数据并处理(如解析KCP协议头、更新ACK等)。
    ​参数:
    kcp:KCP对象指针。
    data:接收到的数据缓冲区。
    size:数据长度。
    ​返回值:成功返回0,失败返回负值。
    ​示例:
int ret = ikcp_input(kcp, data, size);
  1. kcp_recv
    ​功能:从KCP接收缓冲区中读取应用层数据。
    ​参数:
    kcp:KCP对象指针。
    buffer:接收数据的缓冲区。
    len:缓冲区长度。
    ​返回值:实际读取的数据长度。
    ​示例:
int len = ikcp_recv(kcp, buffer, sizeof(buffer));
2. KCP工作流程
  1. ​初始化阶段
    调用kcp_create创建KCP对象。
    设置KCP参数(如窗口大小、超时时间等)。
  2. ​数据发送流程
    应用层调用kcp_send发送数据。
    KCP内部将数据分片,添加KCP协议头(24字节)。
    调用output回调函数发送数据包。
    定时调用kcp_update触发重传和窗口更新。
  3. ​数据接收流程
    网络层接收到数据包,调用kcp_input处理。
    KCP解析协议头,更新ACK和窗口状态。
    应用层调用kcp_recv读取数据。
  4. ​定时任务
    定期调用kcp_update,处理超时重传、窗口更新等任务。
3. KCP示例代码
  1. ​初始化KCP
ikcpcb *kcp = ikcp_create(conv, user);
ikcp_wndsize(kcp, 128, 128); // 设置窗口大小
ikcp_nodelay(kcp, 1, 10, 2, 1); // 启用快速模式
  1. ​发送数据
char buffer[1024];
int len = sprintf(buffer, "Hello, KCP!");
ikcp_send(kcp, buffer, len);
  1. ​接收数据
char buffer[1024];
int len = ikcp_recv(kcp, buffer, sizeof(buffer));
if (len > 0) {
    printf("Received: %s\n", buffer);
}
  1. ​定时更新
while (1) {
    sleep_ms(10);
    ikcp_update(kcp, current_ms());
}
  1. 集成
#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实现可靠传输的核心机制

  1. ​Packet Number严格递增

每个数据包分配唯一且严格递增的序列号(Packet Number),即使重传数据包也会使用新序列号。

  • ​优势:
    消除TCP重传歧义问题,精确计算RTT(往返时间),优化超时重传策略。
    支持乱序确认,避免因单个数据包丢失阻塞后续传输(解决队头阻塞)。
  1. ​Frame Header设计

每个数据包包含多个Frame,通过以下字段保证数据顺序和可靠性:
​Stream ID:标识不同的并发数据流(类似HTTP/2的Stream)。
​Offset:标记数据在流中的偏移量(类似TCP的序列号)。
​Length:数据长度。

  • ​作用:通过Stream ID + Offset唯一标识数据内容,即使重传数据包的Packet Number不同,也能正确重组数据。
  1. ​流量控制

​Stream级流量控制:每个Stream独立维护滑动窗口,互不影响。
​Connection级流量控制:限制所有Stream的总数据量,防止整体过载。

  • ​实现方式:
    通过WINDOW_UPDATE帧动态调整窗口大小。
    通过BLOCKED帧通知发送方流量阻塞。
  1. ​拥塞控制改进

默认使用TCP的Cubic算法,同时支持BBR、PCC等算法。

  • ​优势:
    在应用层实现,无需内核支持,灵活升级算法。
    可为不同应用定制拥塞策略(如视频流与文件传输使用不同算法)。

2. ​QUIC解决TCP的四大缺陷

  1. ​协议升级困难

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数据之间添加三层头部:

  1. ​Long/Short Packet Header:管理连接ID与数据包编号。
  2. ​QUIC Frame Header:标识Stream及数据偏移。
  3. ​HTTP/3帧:承载实际应用数据。

网站公告

今日签到

点亮在社区的每一天
去签到