基于UDP的KCP协议

1.UDP对比于TCP的优缺点

​ UDP是用户数据报协议,它的传输是面向报文传输。TCP是传输控制协议,面向的是字节流。也就是说UDP的传输单位是整个报文,而TCP的传输最小单位是字节。他们都属于TCP/IP协议中的传输层协议,其都是由操作系统内核协议栈控制的。关于他们的控制逻辑,我们是没有办法轻易更改的。将二者进行对比,它主要由以下几点优缺点区别。

UDP的优点:

  1. 速度快:UDP协议无需建立连接,没有连接建立、维护和拆除的开销,因此数据传输速度快,吞吐效率高。
  2. 实时性好:由于UDP协议没有复杂的控制机制,因此在实时性要求较高的应用中具有显著优势,如在线游戏、视频流传输等。
  3. 适用于广播和多播:UDP协议支持一对多的通信方式,即广播和多播,可以方便地实现多个客户端同时接收数据。
  4. 安全性稍高:由于UDP没有TCP的握手、确认、窗口、重传、拥塞控制等机制,因此较TCP被攻击者利用的漏洞就要少一些。

UDP的缺点:

  1. 可靠性较低:UDP协议不提供数据包的排序、错误检查和重传机制,因此无法确保数据的可靠传输。数据包可能会丢失、乱序或重复,这在一些对数据完整性要求较高的应用中是不利的。
  2. 无流量控制:UDP协议没有流量控制机制,发送端可能会以超过接收端处理能力的速度发送数据,导致数据丢失或网络拥塞。
  3. 安全性问题:由于UDP协议简单且缺乏安全性设计,它容易受到各种网络攻击,如拒绝服务攻击(DoS)等。

TCP的优点:

  1. 可靠性和顺序性:TCP协议通过三次握手建立连接,并在数据传递过程中有确认、窗口(流量控制)、(超时)重传、拥塞控制机制,确保了数据的可靠传输和顺序性。这使得TCP适用于需要高可靠性的应用,如需要数据完整性保护的多媒体流或需要按顺序接收数据的实时应用。
  2. 安全性较高:由于TCP具有复杂的控制机制,它可以有效地防止各种网络攻击,如拒绝服务攻击(DoS)等。

TCP的缺点:

  1. 慢:TCP在传递数据之前要先建立连接,这会消耗时间。同时,在数据传递过程中基于TCP首部中信息进行的确认机制、重传机制、拥塞控制机制等都会消耗大量的时间。
  2. 效率低:TCP首部大小本身就比UDP首部大,而且在数据传递时还需要维护需要保持的传输连接,这会导致额外的开销和效率降低。
  3. 占用系统资源高:每个TCP连接都会占用系统的CPU、内存等硬件资源,因此在处理大量并发连接时可能会导致系统资源不足。

2.KCP和QUIC协议

​ 我们可以看到UDP的缺点是致命的,尽管我们可以知道,UDP传输速度快,但它确是不可靠的。假如我们发送了一段数据过去,如果不能保证对方能够准确收到怎么能行呢。基于这种情况,我们需要对UDP进行改造,那如何改造呢?因为UDP的控制和处理逻辑,是操作系统内核在维护的,我们是没有办法轻易去修改的。所以我们要在应用层,进行控制。也就是说,我们要基于UDP编写一个可靠且可控的传输层协议。基于这种情况,诞生了KCP和QUIC协议。

相似之处

  1. 目标:两者都旨在提供比传统TCP更快速、更可靠的数据传输。
  2. 基于UDP:KCP和QUIC都基于UDP协议,因此都具有UDP的优点,如无连接、轻量级和快速响应。
  3. 低延迟:两者都通过优化传输策略来降低延迟,特别是在高延迟或高丢包率的网络环境中。

主要区别

  1. 实现方式

    • KCP是一个纯算法实现的协议,它并不直接处理底层UDP数据包的收发,而是需要用户自己定义下层数据包的发送方式,并以callback的方式提供给KCP。KCP内部没有系统调用,整个协议的实现只有ikcp.h和ikcp.c两个源文件,可以方便地集成到用户自己的协议栈中。
    • QUIC则是一个完整的传输层协议,它基于UDP,但同时兼具TCP、TLS和HTTP/2等协议的可靠性与安全性。QUIC在UDP之上实现了连接建立、可靠传输、流量控制、拥塞控制等功能。
  2. 连接建立

    • KCP没有专门的连接建立过程,它依赖于用户自行实现底层UDP数据包的收发。
    • QUIC则实现了基于TLS的握手过程,可以实现0-RTT握手,从而加速连接建立和数据传输的过程。
  3. 多路复用

    • KCP本身并不支持多路复用,每个KCP连接只能传输一个数据流。
    • QUIC支持在同一连接上同时传输多个数据流,这意味着它可以在一个连接上同时处理多个HTTP请求,从而避免了TCP上的队头阻塞问题,提高了网络利用率和性能。
  4. 安全性

    • KCP本身不提供加密功能,但可以通过用户自定义的方式实现加密。
    • QUIC默认支持加密,所有数据在传输过程中都是加密的,提供更高的安全性和隐私保护。
  5. 应用场景

    • KCP被广泛用于在线游戏、实时通信、视频直播、P2P通信等领域,特别在对传输稳定性和实时性要求较高的应用中有很好的表现。
    • QUIC则更多地被用于Web应用,如HTTP/3协议就基于QUIC。

相比于kcp来说quic协议更加复杂一些。我们下面只讨论KCP的相关内容。

3.KCP相关对比

3.1 kcp与TCP对比

关于KCP,我们可以把它理解为我们自定义了一个可靠的传输协议,它的底层协议采用的UDP,对于UDP我们可以理解成,操作系统的协议栈,给我们提供的最小的一个传输单元。我们可以根据业务需求,在此基础之上自定义我们的传输协议。KCP采用了以下手段来保证数据的传输效率和可靠性。

  1. 数据包分片:当用户数据很大,大于一个UDP包能承担的范围时,KCP会将用户数据分片存储在多个KCP包中。
  2. 快速重传和选择性重传:KCP采用快速重传和选择性重传机制,只重传真正丢失的数据包,而不是像TCP那样在丢包时重传从该包开始以后的所有数据。这减少了丢包等待时间,提高了传输效率。
  3. RTO不翻倍:KCP的重传超时时间(RTO)不像TCP那样翻倍增长,而是采用一个较小的增长因子(如1.5),这有助于更快地恢复网络拥堵时的传输。
  4. 非延迟ACK:KCP的ACK是否延迟发送可以调节,这有助于更快地确认数据包的接收情况,减少丢包等待时间。

由于TCP的设计,考虑的因素比较全面,它是一个非常智能的协议,会根据RTT来判断当时网络的拥塞情况,然后来设置RTO。KCP协议相比于TCP,他的传输效率提高了,但却浪费了更多的网络带宽。下面使关于TCP和UDP协议的对比。

TCP的这种智能性主要体现在以下几个方面:

  1. 拥塞控制:TCP使用慢启动(Slow Start)、拥塞避免(Congestion Avoidance)、快重传(Fast Retransmit)和快恢复(Fast Recovery)等机制来避免和缓解网络拥塞。这些机制的核心就是根据观察到的网络行为(如RTT和丢包率)来调整发送方的发送速率。
  2. 动态RTO计算:TCP会根据测量的RTT来动态地计算RTO。当数据包发送出去后,TCP会启动一个定时器,等待接收方的确认。如果在这个RTO时间内没有收到确认,TCP就会认为数据包已经丢失,并触发重传机制。为了更准确地估计网络状况,TCP会不断地测量RTT,并根据最新的RTT值来调整RTO。
  3. 流量控制:TCP使用滑动窗口(Sliding Window)机制来实现流量控制。接收方会告诉发送方自己当前可以接收多少数据(即窗口大小),发送方则根据这个窗口大小来发送数据。这样可以避免发送方发送过多的数据导致接收方缓冲区溢出。
  4. 错误检测与恢复:TCP使用校验和(Checksum)来检测数据包的完整性。如果数据包在传输过程中发生错误,接收方会丢弃该数据包,并发送一个否定确认(NACK)给发送方。发送方收到NACK后会触发重传机制,重新发送丢失的数据包。

关于KCP

  1. 速度和可靠性:KCP的设计目标是在保证可靠性的同时提高传输速度。它采用了一系列的技术手段,如多个连接的并发传输、数据包编码、前向纠错(FEC)、流量控制、拥塞控制等,以提高数据传输的效率和可靠性。
  2. UDP作为基础:KCP没有规定下层传输协议,但通常使用UDP作为下层传输协议。KCP层协议的数据包在UDP数据报文的基础上增加控制头,以实现更高效的传输。
  3. 数据包分片:当用户数据很大,大于一个UDP包能承担的范围时,KCP会将用户数据分片存储在多个KCP包中。每个KCP包称为一个分片。
  4. 快速重传和选择性重传:KCP使用快速重传和选择性重传机制,只重传真正丢失的数据包,而不是像TCP那样在丢包时重传从该包开始以后的所有数据。这减少了丢包等待时间,提高了传输效率。
  5. RTO调整:KCP的重传超时时间(RTO)不像TCP那样翻倍增长,而是采用一个较小的增长因子(如1.5),这有助于更快地恢复网络拥堵时的传输。
  6. 流量控制和拥塞控制:KCP使用滑动窗口和拥塞窗口等流量控制机制,有效地管理发送和接收的数据流量。同时,它使用基于拥塞窗口的拥塞控制算法,通过动态调整发送速率和窗口大小来适应网络拥塞情况。
  7. 自适应调整:KCP具有自适应调整的能力,可以根据网络环境的变化自动调整参数和策略,以适应不同网络条件下的传输需求。
  8. 快速建立和关闭连接:KCP采用三次握手的方式来确保双方的连接能够正确建立,并支持快速关闭连接的特性。

我们之前说过,KCP相比于TCP,浪费了百分之20左右的带宽,换取了百分之40左右的速度。

我们可以把他想象成一个水流很急,但流量不是很多。

3.2 RTO翻倍VS不翻倍

TCP超时计算是RTO*2。也就是说,当发送超时后,我们会对RT0进行双倍累计。连续丢三次包就成了RTO×8.这是非常恐怖的。而KCP启动了快速重传模式后,采用的是1.5倍。通过试验证明1.5这个值是比较好的。

重传1234
TCP2004008001600
UDP200300450675

3.3 选择重传VS全部重传

我们知道TCP在丢包后,会选择全部重传从丢的哪个包开始以后的数据,而KCP是选择性重传的,只重传我们丢的真正的包。这样的

选择重传:

原理

  • 当发送方检测到某个数据包丢失时,它只会重传那个特定的丢失数据包,而不是重传所有后续的数据包。
  • 接收方会为每个数据包发送一个单独的确认(ACK),这样发送方就能准确地知道哪些数据包已经成功接收,哪些数据包需要重传。

优点

  • 网络带宽利用率高:因为只重传丢失的数据包,所以减少了不必要的重传。
  • 延迟较低:由于不需要等待多个数据包一起重传,所以能够更快地恢复数据传输。

缺点

  • 实现复杂:需要为每个数据包维护单独的序列号、确认号和重传定时器。
  • 需要更多的缓冲区空间:接收方需要缓存所有按序到达的数据包,直到丢失的数据包被重传并成功接收。
全部重传:

原理

  • 当发送方检测到某个数据包丢失时,它会重传从丢失数据包开始的所有后续数据包。
  • 接收方通常只发送一个累积确认(Cumulative ACK),表示它已经成功接收了到某个序列号为止的所有数据包。

优点

  • 实现简单:只需要维护一个序列号、一个确认号和一个重传定时器。
  • 缓冲区需求较少:接收方只需要缓存按序到达的数据包,直到所有数据包都成功接收。

缺点

  • 网络带宽利用率低:由于可能重传多个未丢失的数据包,所以浪费了带宽。
  • 延迟较高:在丢失数据包被重传并成功接收之前,接收方可能无法继续处理后续的数据包。

3.4 快速重传

当选择了快速重传,发送端发送了1,2,3,4,5几个包,然后远端的ACK:1,3,4,5.当收到了ack3时,返端不需要等待RTO超时,直接重新发送。这样可以做到更快的重传,但对带宽的浪费更大。

3.5延迟ACKvs非延迟ACK

tcp为了充分的利用带宽,延迟发送ACK,这样做的目的是等待一段时间,看看有没有新的数据到来,以便一起发送ACK确认。这样做的目的是为了充分利用网络带宽。而KCP是否延迟ack是可以自定义控制的和调节的。这就是KCP相比于TCP这种内核协议来说,我们可以更灵活的根据需求进行调节和控制。

3.6 UNAvsACK+UNA

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

KCP协议的这种设计有几个优点:

  1. 减少了ACK的数量:因为数据包本身就携带了UNA信息,所以不需要为每个接收到的数据包都发送一个单独的ACK,这有助于减少网络中的小包数量,降低网络负载。
  2. 提高了传输效率:通过数据包中的UNA信息,发送方可以更快地了解到哪些数据包已经被成功接收,从而可以更快地发送后续的数据包,提高了数据的吞吐量。
  3. 选择性重传:结合ACK和UNA信息,KCP可以实现选择性重传。当某个数据包丢失时,只需要重传丢失的数据包,而不是像某些协议那样需要重传从丢失数据包开始的所有后续数据包。
  4. 灵活性:KCP允许调节ACK的发送频率,这样可以根据网络条件和应用需求来优化性能。

4.kcp实现和协议解析

因为kcp的底层采用的是UDP协议,而UDP协议是一个面向无连接的,所以我们需要对每个KCP连接创建一个唯一的会话ID。

以下是为什么我们需要为每个KCP连接创建唯一会话ID的几个原因:

  1. 区分连接:当多个KCP连接同时运行时,每个连接都需要一个唯一的标识符来确保数据包能够正确地发送到相应的接收方。
  2. 状态管理:KCP连接需要维护诸如发送和接收缓冲区、序列号、确认号、重传定时器等的状态信息。使用唯一的会话ID可以帮助我们在多个连接之间正确地管理和跟踪这些状态信息。
  3. 并发处理:在服务器环境中,通常需要同时处理来自多个客户端的连接。使用会话ID可以帮助服务器区分不同的客户端,并并行处理它们的数据包。
  4. 安全性:虽然会话ID本身不直接提供安全性,但结合其他安全措施(如身份验证和加密),它可以增加系统的安全性。

在实现KCP时,通常会为每个连接创建一个KCP对象,并在该对象中存储会话ID以及其他相关的状态信息。当接收到一个UDP数据包时,KCP库会解析数据包中的会话ID,并使用该ID来确定应该将数据包发送到哪个KCP对象进行处理。

请注意,会话ID的生成和分配应该是唯一的,并且应该避免在多个连接之间使用相同的会话ID。这可以通过使用递增的计数器、UUID或其他唯一标识符生成算法来实现。如果是客户端生成的ID,我们需要采用一种策略在服务器进行验证,以确保群是否是唯一的ID。我们可以在建立KCP通信之前,采用TCP通信,先做好KCP通信的准备和初始化后,再进行后续的KCP通信。

下图是KCP的协议报文
在这里插入图片描述

字段说明
conv会话ID:这是KCP连接的一个唯一标识符,用于区分不同的通信会话。当两个端点想要建立KCP连接时,它们需要协商一个共同的conv值。
cmd命令类型:这个字段标识了数据包的类型。例如,它可能是一个普通的数据包、一个ACK包(用于确认接收到的数据包)、一个窗口探测包(用于探测接收方的窗口大小)等。
frg分片索引:KCP支持数据分片,这意味着一个大的数据包可以被分割成多个小的数据包进行传输。frg字段用于标识数据包的分片索引,以便在接收端重新组装原始数据。
wnd窗口大小:这是一个流控制字段,用于防止发送方发送过多的数据而导致接收方缓冲区溢出。wnd字段表示接收方当前可用的缓冲区大小。
ts时间戳:KCP使用时间戳来计算往返时间(RTT),这对于拥塞控制和重传策略非常重要。每个数据包都包含一个时间戳,接收方在发送ACK时会回显这个时间戳。
sn序列号:每个KCP数据包都有一个唯一的序列号,用于在接收端对数据进行排序和去重。当数据包乱序到达时,接收方可以根据序列号重新排序它们。
una未确认的序列号:这是KCP的ACK机制中的一个关键字段。在ACK包中,una字段表示接收方已经成功接收并处理了序列号小于una的所有数据包。发送方可以根据这个信息来确定哪些数据包需要重传。
len数据长度:这个字段表示随协议头一起发送的数据部分的长度。它告诉接收方在数据包中应该读取多少字节的数据。

5.KCP的相关配置

  1. 会话编号(Conv):这是一个整数,用于标识KCP会话。通信双方需要确保Conv相同,以便相互的数据包能够被正确识别。
  2. 用户数据指针(User):这是一个给回调函数的指针,允许用户将自定义数据与KCP连接相关联。
  3. 传输模式:KCP支持多种传输模式,如普通模式(normal mode)和快速模式(fast mode)。快速模式通常具有更低的延迟,但可能会增加丢包的风险。普通模式则更注重数据的完整性和可靠性。
  4. 拥塞控制:KCP使用了一种基于速率的拥塞控制算法,可以根据网络状况动态调整发送速率。关键参数包括cwnd(拥塞窗口),它表示发送方可发送多少个KCP数据包,与接收方窗口、网络状况(拥塞控制)和发送窗口大小有关。
  5. 最大传输单元(MTU):MTU定义了KCP每次发送的最大数据量。较大的MTU可以提高吞吐量,但也可能增加丢包的风险。因此,需要根据网络环境和应用需求来选择合适的MTU大小。
  6. 重传策略:KCP使用了一种基于快速重传和选择性确认(SACK)的算法来处理丢包问题。当检测到数据包丢失时,KCP会重传丢失的数据包,并根据ACK信息来确认哪些数据包已经成功接收。
  7. 加密方式:KCP支持数据加密功能,以保护数据的机密性和完整性。可以配置加密算法和密钥来启用加密功能。
  8. 监听地址和端口:在配置KCP服务器时,需要指定监听地址和端口,以便客户端能够连接到服务器。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值