KCP源码解析系列(一)KCP协议介绍

一、什么是KCP

TCP是为流量设计的(每秒内可以传输多少KB的数据),讲究的是充分利用带宽。而 KCP是为流速设计的(单个数据包从一端发送到一端需要多少时间),以10%-20%带宽浪费的代价换取了比 TCP快30%-40%的传输速度。TCP信道是一条流速很慢,但每秒流量很大的大运河,而KCP是水流湍急的小激流。

1.1 代码仓库

https://github.com/skywind3000/kcp

1.2 KCP在网络协议中的位置

在这里插入图片描述

二、KCP协议特点

kcp 是一个快速可靠ARQ协议,相比于tcp,以 10%-20% 带宽浪费的代价换取了快 30%-40% 的传输速度。kcp 可以看做应用层协议,底层采用 udp 传输。

2.1 RTO不翻倍

RTO(Retransmission TimeOut),重传超时时间。TCP的RTO是指数翻倍的,当网络比较差的时候,指数延长RTO时间。因为TCP是大公无私的,如果发现网络状况持续较差,就会放慢自己的发送速度。而KCP就比较自私,网络比较差了基本还是照常发。

tcp x 2,kcp x 1.5,提高传输速度

2.2 选择重传

TCP丢包时会全部重传从丢失包开始之后的数据,而KCP会选择性的重传,只重传真正丢失的数据包。

2.3 快速重传

  • 超时重传:超过规定的时间 RTO 则重传

  • 快速重传:收到fastresend个冗余ack,不去等待RTO ,直接重传

2.4 非延迟ACK

TCP为了充分利用带宽,延迟发送ACK,RTT时间比较大,演唱了丢包时的判断过程。而KCP的ACK是否延迟发送可以调节。

在这里插入图片描述

在这里插入图片描述

2.4 UNA vs ACK + UNA

ARQ模型响应有两种,UNA(此编号前所有包已收到,如TCP)和ACK(该编号包已收到),光用UNA将导致全部重传,光用ACK则丢失成本太高,以往协议都是二选其一,而 KCP协议中,除去单独的 ACK包外,所有包都有UNA信息。

2.5 非退让流控

KCP(Kernel Congestion Protocol)中的非退让流控是其流控制机制的一个特点。
在传统的 TCP 协议中,当检测到网络拥塞时,会采取比较保守的退让策略,例如降低发送窗口大小以减少数据发送量。
而 KCP 的非退让流控相对更积极和激进。它不会像 TCP 那样轻易地大幅度降低发送速率,而是会在一定程度上保持较高的发送速度,并通过快速的重传和窗口调整机制来适应网络状况。
这种非退让的流控方式在一些对延迟和实时性要求较高的场景中,可能会有更好的性能表现,但也需要更精细的参数配置和对网络环境的准确判断,以避免过度占用网络资源导致拥塞加剧。

三、KCP基本使用

kcp的使用非常的简单,基本和socket差不多。

3.1 初始化

ikcpcb *kcp = ikcp_create(conv, user);
// 示例中,conv 是会话编号,通信双方需要保证conv相同,user 是用户自定义数据,可以用于在回调函数中传递上下文

3.2 设置发送回调

//kcp协议的输出函数,当kcp需要发送消息的时候,需要调用它
static int on_kcp_output(const char *buf, int len, ikcpcb *kcp, void *user_data){
   ......
}

kcp->output = on_kcp_output;

3.3 循环调用ikcp_update

ikcp_update是整个kcp事件驱动的核心,kcp数据的发送和接收都需要ikcp_update来完成。

    // 主循环
    while (true) {
        IUINT32 current = iclock();
        if (current >= nextUpdateTS) {
            ikcp_update(kcp, current);
            nextUpdateTS = ikcp_check(kcp, current); // 确定下次调用时间
        }

        // 计算到下次`ikcp_update`的时间
        IINT32 sleepTime = nextUpdateTS - iclock();
        if (sleepTime > 0) {
            usleep(sleepTime * 1000);  // 把睡眠时间转换为微秒
        } else {
            // 当 sleepTime <= 0 时,确保继续循环以避免错过更新时机
            usleep(1000); // 产生小的延迟,让出 CPU 资源
        }

        // 可以在这里处理其他网络事件,如接收数据包、发送数据
        // 例如:
        // recvData();
        // sendData();
    }

3.4 输入数据包

当udp收到数据包时,通过ikcp_input输入给kcp协议

ikcp_input(kcp, buffer, len);

3.5 收发数据

ikcp_send(kcp, buffer, len);
int len = ikcp_recv(kcp, buffer, sizeof(buffer));
  • 20
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值