Vico Bill< 刘 利 波 > 的个人网站

记录关于学习、工作中的技术点滴

C,C++,Rust,Ruby爱好者;热衷于游戏开发、任务自动化与跨平台;沉迷于游戏引擎与图形表现;深信'简单、多元'哲学的力量。


访问主页

笔记集锦-Lisp

参考 各个Reliable UDP对比

Reliable UDP一览:那些能替代TCP的RUDP方案

背景:

笔者负责的一个项目在实时性方面有着较高要求,低延时是一个技术指标,希望能够尽可能减少延迟,来优化服务体验。

所以需要在UDP方面进行一些调研。

而我们的数据协议是建立在可靠网络传输协议之上的,它的数据包之间有一些关联,不允许丢包。

因而将TCP迁移到使用Reliable UDP可能是一个优化的方向。

ps:本文系搬运、整理、部分翻译,再加上自己的一些理解,实验数据来源于网络。本文还处于调研阶段,没有亲自对各个RUDP方案进行实验对比,但本文的数据和理论都来源于业界大佬,希望能提供给大家作为参考。也欢迎大家和我沟通交流,若有不对的地方,欢迎指正!

UDP简介:

TCP 是面向连接的、可靠的、有序的传输层协议,而 UDP 是面向数据报的、不可靠的、无序的传输协议,所以 UDP 不会建立什么连接。

每次 UDP 发送的数据报大小由哪些因素共同决定呢?

  • UDP协议本身,UDP协议中有16位的UDP报文长度,那么UDP报文长度不能超过2^16=65536;
  • 以太网(Ethernet)数据帧的长度,数据链路层的MTU(最大传输单元);
  • socket的UDP发送缓存区大小。

UDP 本身协议的报文长度为 2^16 – 1,UDP 包头占 8 个字节,IP 协议本身封装后包头占 20 个字节,所以最终长度为: 2^16 – 1 – 20 – 8 = 65507 字节。 因为 UDP 属于不可靠协议,我们应该尽量避免在传输过程中,数据包被分割。所以这里有一个非常重要的概念 MTU — 也就是最大传输单元。 在 Internet 下 MTU 的值为 576 字节,所以在 Internet 下使用 UDP 协议,每个数据报最大的字节数为: 576 – 20 – 8 = 548

参考UDP中一个包的大小最大能多大?,文中建议,局域网环境下UDP数据应控制在1472字节以下,Internet编程时UDP数据应控制在548字节以下。

什么情况会导致 UDP 丢包?:

  • 数据报分片重组丢失:UDP 协议本身规定的大小是 64kb,但是在数据链路层有 MTU 的限制,大小大概在 5kb,所以当你发送一个很大的 UDP 包的时候,这个包会在 IP 层进行分片,然后重组。这个过程就有可能导致分片的包丢失。UDP 本身有 CRC 检测机制,会抛弃掉丢失的 UDP 包;

  • UDP 缓冲区填满:当 UDP 的缓冲区已经被填满的时候,接收方还没有处理这部分的 UDP 数据报,这个时候再过来的数据报就没有地方可以存了,自然就都被丢弃了。

client发送两次UDP数据,第一次 500字节,第二次300字节,server端阻塞模式下接包,第一次recvfrom( 1000 ),收到是 1000,还是500,还是300,还是其他? 由于UDP通信的有界性,接收到只能是500或300,又由于UDP的无序性和非可靠性,接收到可能是300,也可能是500,也可能一直阻塞在recvfrom调用上,直到超时返回(也就是什么也收不到)。

在假定数据包是不丢失并且是按照发送顺序按序到达的情况下,server端阻塞模式下接包,先后三次调用:recvfrom( 200),recvfrom( 1000),recvfrom( 1000),接收情况如何呢? 由于UDP通信的有界性,第一次recvfrom( 200)将接收第一个500字节的数据包,但是因为用户空间buf只有200字节,于是只会返回前面200字节,剩下300字节将丢弃。第二次recvfrom( 1000)将返回300字节,第三次recvfrom( 1000)将会阻塞。

  • UDP socket缓冲区过小:如果Client发送的UDP报文很大,而socket缓冲区过小无法容下该UDP报文,那么该报文就会丢失。
  • ARP缓存过期:ARP 的缓存时间约10分钟,APR 缓存列表没有对方的 MAC 地址或缓存过期的时候,会发送 ARP 请求获取 MAC 地址,在没有获取到 MAC 地址之前,用户发送出去的 UDP 数据包会被内核缓存到 arp_queue 这个队列中,默认最多缓存3个包,多余的 UDP 包会被丢弃。

经过这么多年的发展 TCP 已经拥有足够多的算法和优化,在网络状态不错的情况下,TCP 的整体性能是优于 UDP 的。 那在什么时候我们非用 UDP 不可呢?

  • 实时性要求高:比如实时会议,实时视频这种情况下,如果使用 TCP,当网络不好发生重传时,画面肯定会有延时,甚至越堆越多。如果使用 UDP 的话,即使偶尔丢了几个包,但是也不会影响什么,这种情况下使用 UDP 比较好;

  • 多点通信:TCP 需要保持一个长连接,那么在涉及多点通讯的时候,肯定需要和多个通信节点建立其双向连接,然后有时在NAT环境下,两个通信节点建立其直接的 TCP 连接不是一个容易的事情,而 UDP 可以无需保持连接,直接发就可以了,所以成本会很低,而且穿透性好。这种情况下使用 UDP 也是没错的。

  • 需要进行NAT穿越

以下介绍一些Reliable UDP相关或者类似UDP的传输协议。

1、QUIC

全称Quick UDP Internet Connections,是由 Google 提出的使用 UDP 进行多路并发传输的协议。

优点:

  • 连接建立延时低:

HTTPS 的一次完全握手的建连过程,需要 3 个 RTT。就算是 Session Resumption,也需要至少 2 个 RTT。 而 QUIC 呢?由于建立在 UDP 的基础上,同时又实现了 0RTT 的安全握手,所以在大部分情况下,只需要 0 个 RTT 就能实现数据发送,在实现前向加密的基础上,并且 0RTT 的成功率相比 TLS 的 Sesison Ticket 要高很多。

  • 改进的拥塞控制:

QUIC 协议当前默认使用了 TCP 协议的 Cubic 拥塞控制算法,同时也支持 CubicBytes, Reno, RenoBytes, BBR, PCC 等拥塞控制算法。应用程序不需要停机和升级就能实现拥塞控制的变更。

  • 没有队头阻塞的多路复用:

QUIC 的多路复用和 HTTP2 类似。在一条 QUIC 连接上可以并发发送多个 HTTP 请求 (stream)。但是 QUIC 的多路复用相比 HTTP2 有一个很大的优势。 QUIC 一个连接上的多个 stream 之间没有依赖。这样假如 stream2 丢了一个 udp packet,也只会影响 stream2 的处理。不会影响 stream2 之前及之后的 stream 的处理。

  • 连接迁移:

那 QUIC 是如何做到连接迁移呢?很简单,任何一条 QUIC 连接不再以 IP 及端口四元组标识,而是以一个 64 位的随机数作为 ID 来标识,这样就算 IP 或者端口发生变化时,只要 ID 不变,这条连接依然维持着,上层业务逻辑感知不到变化,不会中断,也就不需要重连。

由于这个 ID 是客户端随机产生的,并且长度有 64 位,所以冲突概率非常低。

问题:

虽然经过多年的推广的应用,但QUIC协议目前仍未达到大量普及的阶段,在 IETF上的QUIC 依然还是草稿,并且还存在Google QUIC与IETF QUIC两类不稳定的协定。

  • 1)路由封杀UDP 443端口( 这正是QUIC 部署的端口);
  • 2)UDP包过多,由于QS限定,会被服务商误认为是攻击,UDP包被丢弃;
  • 3)无论是路由器还是防火墙目前对QUIC都还没有做好准备。

Chrome 浏览器从 2014 年开始已经实验性的支持了 QUIC 协议。可以通过在 Chrome 浏览器中输入 chrome://flags 搜索quic字样查看是否支持quic。

目前支持 QUIC 协议的 web 服务只有 0.9 版本以后的 Caddy 。其他常用 web 服务如 nginx、apache 等都未开始支持。

开源实现:

  • *Chromium*

    这个是官方支持的。优点自然很多,Google 官方维护基本没有坑,随时可以跟随 chrome 更新到最新版本。不过编译 Chromium 比较麻烦,它有单独的一套编译工具。暂时不建议考虑这个方案。

  • *proto-quic*

    从 chromium 剥离的一个 QUIC 协议部分,但是其 github 主页已宣布不再支持,仅作实验使用。不建议考虑这个方案。

  • *goquic*

    goquic 封装了 libquic 的 go 语言封装,而 libquic 也是从 chromium 剥离的,好几年不维护了,仅支持到 quic-36, goquic 提供一个反向代理,测试发现由于 QUIC 版本太低,最新 chrome 浏览器已无法支持。不建议考虑这个方案。

  • *quic-go*

    quic-go 是完全用 go 写的 QUIC 协议栈,开发很活跃,已在 Caddy 中使用,MIT 许可,目前看是比较好的方案。

移动端没有开源实现。不过可以从Chromium移动端拿到动态库来使用,腾讯有一个demo,https://github.com/52im/clb-quic-demo。参考让互联网更快:新一代QUIC协议在腾讯的技术实践分享

2、WebRTC及DataChannel

WebRTC,名称源自网页实时通信(Web Real-Time Communication)的缩写,是一个支持网页浏览器进行实时语音通话或视频聊天的技术,是谷歌2010年以6820万美元收购Global IP Solutions公司而获得的一项技术。

WebRTC提供了实时音视频的核心技术,包括音视频的采集、编解码、网络传输、显示等功能,并且还支持跨平台:windows,linux,mac,android。 虽然WebRTC的目标是实现跨平台的Web端实时音视频通讯,但因为核心层代码的Native、高品质和内聚性,开发者很容易进行除Web平台外的移殖和应用。很长一段时间内WebRTC是业界能免费得到的唯一高品质实时音视频通讯技术。

优点:

  • Chrome浏览器支持;跨平台;免费;
  • 优秀的算法和技术,音视频算法;拥塞控制算法GCC/BBR;
  • 强大的打洞穿透能力。

问题:

  • 缺乏服务器方案的设计和部署。可以参考第三方的方案,如Kurento、Janus、Licode。
  • 传输质量难以保证。P2P,难以保障传输质量,优化手段也有限,只能做一些端到端的优化,难以应对国内复杂的互联网环境,如跨地区、跨运营商、低带宽、高丢包等场景。
  • 对Native开发的支持不够。Android端的Demo从2016年就没有更新过了,然而接口已经变更了。文档不全面。由于涉及到的领域知识(音视频采集、处理、编解码、实时传输等)较多,整个框架设计比较复杂,API粒度也比较细,导致连工程项目的编译都不是一件容易的事。早期由于缺少对于 H.264 编解码器的支持,使得移动端很长一段时间只能使用 VP8 软件编解码(Google自己的编解码标准),导致在中低端手机上的表现较差,加上安卓自身碎片化的属性,如果不针对不同机型做适配,很难有统一的用户体验。

WebRTC是否靠谱?

大的方向上,WebRTC是靠谱的:

  • 使跨平台、跨浏览器通讯成为可能,而且大大加速了这个进程,这就是GoogleWebRTC大受欢迎的主要原因;
  • 大厂商都在跟进,从底层芯片厂商到上层应用厂商,如英特尔、ARM、微软、苹果、宝利通、Vidyo等等;
  • 国内提供音视频PaaS和SaaS服务的厂商都是基于WebRTC开发的,包括QQ、微信,以及从腾讯和YY出来创业的小伙伴;
  • Google已经基于WebRTC做出了成功应用Hangout和Duo;
  • WebRTC很适合直播场景:推流采用WebRTC,观看采用现有的CDN方案,结合使用,花椒直播、千帆直播就是最好的案例;
  • 还有很多单独抽取部分模块进行使用的例子。

但对于小团队,难度不小:

  • WebRTC代码庞大,环境配置复杂,门槛比较高;
  • WebRTC只是一个客户端,更适合1对1,并不适合多对多的视频通话,如视频会议,想支持多方,还得借助其他服务端,但这块是个比较有门槛的技术活;
  • WebRTC虽然提供了很多信号处理、回声消除、编解码的库,但直接拿过来就想达到QQ和微信的水平,还得下很大功夫去优化,不然也只是微信的6~7分水平;
  • 服务端部署问题,微信效果能这么好,是因为他在很多地方都有部署服务器,可以最大限度降低延迟和保证通话质量,但如果完全采用P2P,是很难达到同等水准的;

第3方实时音视频云服务SDK:

  • 1、腾讯SDK;
  • 2、声网,YY团队;
  • 3、即构,QQ团队;
  • 4、叁体,WebEx/Cisco团队;
  • 5、Zoom,思科团队;
  • 6、vidyo,钉钉方案供应商;
  • 7、世纪鼎点,映客方案供应商;
  • 8、一块,尚未提供sdk,但技术确实牛;
  • 9、anyRTC。

参考基于开源WebRTC开发实时音视频靠谱吗?第3方SDK有哪些?

img

参考开源实时音视频工程WebRTC的架构详解与实践总结

参考网页端实时音视频技术WebRTC:看起来很美,但离生产应用还有多少坑要填?

总结就是,WebRTC在尝试把音视频、流媒体技术做成白菜价,但是在复杂的网络环境中使用,还需要投入很多的专业技术和开发成本。回到Reliable UDP,WebRTC的技术栈如下:imgDataChannel可以当做Reliable UDP通道,用于发送数据。它是基于SCTP协议,QUIC有可能会被当做SCTP协议的替代方案,目前正在试验。

webrtc使用的是改良剪切版的SCTP协议。本来SCTP协议是处在传输层,跟UDP处于同一级,可以看到,这里的SCTP实际上是SCTP over UDP。

由于SCTP协议是承载在DTLS协议上,所以SCTP的Multi homing功能,在webrtc的数据通道没有被使用。有两个草案描述WebRTC的改良方法《draft-ietf-rtcweb-data-channel-13》、《draft-ietf-rtcweb-data-protocol-09》,根据描述webrtc根据实际场景,引入了:可靠传输模式、部分可靠传输模式、不可靠传输模式等。而WebRTC的音视频通道是基于SRTP协议来实现的,在SRTP上实现了GCC/BBR这些拥塞控制算法。

DataChannel自然也不能使用这些拥塞控制算法。为了使用Reliable UDP,而引入WebRTC这种技术,成本有点高。

3、SCTPSCTP (Stream Control Transmission Protocol)是一种2000年由IETF定义,位于传输层,和TCP/UDP平行等级的传输协议,它兼有TCP和UDP的特性。TCP是以字节为单位传输的,SCTP是以数据块为单位传输的TCP通常是单路径传输,SCTP可以多路径传输TCP是单流有序传输,SCTP可以多流独立有序/无序传输TCP连接的建立过程需要三步握手,SCTP连接的建立过程需要四步握手SCTP有heartbeat机制来管理路径的可用性SCTP 被吸纳到 2.6 版本的 Linux 内核中。(但是有些路由器不支持这个传输层协议?)

最早STCP是把窄带7号信令的可靠性传输机制引入到IP协议、优化TCP协议的不能分帧传输的局限性提出来的。由于出现的较晚,而且SCTP设计之初是专门用来传输信令,主要适应了多流的应用,在电信领域使用较多。但在终端就很少使用,甚至Windows都不支持这个协议,因而没有广泛应用起来。img结合WebRTC的经验,直接使用socket标准接口提供的STCP不太可取,使用 SCTP over UDP才是明智的选择。不过这方面的开源项目很少,生态很匮乏。接下来是Reliable UDP的开源方案。

4、KCPgithub: https://github.com/skywind3000/kcp 7.7k stars

TCP是为流量设计的(每秒内可以传输多少KB的数据),讲究的是充分利用带宽。而 KCP是为流速设计的(单个数据包从一端发送到一端需要多少时间),以10%-20%带宽浪费的代价换取了比 TCP快30%-40%的传输速度。TCP信道是一条流速很慢,但每秒流量很大的大运河,而KCP是水流湍急的小激流。KCP为了保证可扩展性,提供最基本的Reliable UDP能力,所以它是纯算法实现的,并不负责底层协议(如UDP)的收发,需要使用者自己定义下层数据包的发送方式,以 callback的方式提供给 KCP。 连时钟都需要外部传递进来,内部不会有任何一次系统调用。支持多路复用。KCP相当于是对TCP的一些流控算法做了一些优化,它最大的意义是把这些算法的配置搬到了应用层,以对外提供扩展性和可定制能力。基于KCP的一些扩展库和应用也比较多。

案例:

  • 明日帝国:Game K17 的 《明日帝国》 (Google Play),使用 KCP 加速游戏消息,让全球玩家流畅联网

  • 仙灵大作战:4399 的 MOBA游戏,使用 KCP 优化游戏同步

  • CC:网易 CC 使用 kcp 加速视频推流,有效提高流畅性

  • BOBO:网易 BOBO 使用 kcp 加速主播推流

  • 云帆加速:使用 KCP 加速文件传输和视频推流,优化了台湾主播推流的流畅度

  • SpatialOS: 大型多人分布式游戏服务端引擎,BigWorld 的后继者,使用 KCP 加速数据传输。

  • Lantern:更好的 VPN,Github 50000 星,使用 kcpgo 加速

5、UDT官网:https://sourceforge.net/projects/udt/

UDT(UDP-based Data Transfer Protocol)主要针对当前TCP进行长距离传输大量数据时的性能表现较差而提出,建立在UDP之上,引入新的拥塞控制以及可靠性,支持可靠的流式传输(类似TCP),以及部分可靠的数据报传输(增强UDP)。

UDT原生控制算法被设计给海量数据在高带宽时延积网络传输数据的。所以在日常使用中有些应用场景下会提出UDT效果不佳的问题,尤其在无线网络环境下。6、ENetgithub: lsalzman/enet 1.5k stars官网介绍:http://enet.bespin.org/Features.html提供了可选的数据包传送可靠性性能介于TCP与UDP之间

7、Raknetgithub: facebookarchive/RakNet 2.8k stars官网:http://www.jenkinssoftware.com/features.htmlRaknet初始是为多人对战游戏而设计的网络库,之后得到不断完善并转向商用。2014年在BSD协议下开源(可以自由的使用,修改源代码)。 Raknet除了支持可靠和多通道传输,还包含游戏在应用的通用功能,如http收发、语音收发、NAT穿透、email发送和信息加密等。优点:跨平台安全的传输 RakNet在你的代码中自动使用SHA1, AES128, SYN,用RSA避免传输受到攻击。音频传输 用Speex编码解码,8位的音频只需要每秒500字节传输。远程终端 用RakNet,你能远程管理你的程序,包括程序的设置,密码的管理和日志的管理。目录服务器 目录服务器允许服务器列举他们自己需要的客户端,并与他们连接。Raknet在单个连接上增加了传输通道的概念(复用socket),来提高数据传输效率。传输通道只面向对发送端,接收端看不到通道概念。可以根据数据包的需求特性,利用Raknet的传输模式和传输通道,细化发送规则,压榨性能。以RPG游戏玩法为例,以下列出数据包特性,并尝试推理它们的传输模式和传输通道:数据包需求PacketReliabilityOrderingChannel英雄位置只关心最新的角色位置RELIABLE_SEQUENCED1英雄技能技能连招效果需要严格顺序关系RELIABLE_ORDERED1英雄生命值缺失的数据包影响对战结果,生命值ui没有明显的过渡只显示最新生命数值RELIABLE_SEQUENCED2文字聊天严格的对话顺序、缺失的内容可能产生模糊的话题RELIABLE_ORDERED2快捷聊天错误队友信息顺序并不影响战斗数据,RELIABLE无参考Raknet研究。缺点:Raknet理论上可以支持多个客户端和服务器之间每秒4W个消息的ping-pong测试。但是不稳定,如果某些原因导致消息堆积,则会严重影响发送和接受的响应时间,会达到秒级。最近一次更新已经是2015年。很多业务层的功能,而且缺少维护,基本处于废弃状态。***

8、Aerongithub:real-logic/aeron 4.9k stars官网:https://real-logic.co.uk/Aeron设计的目的是用于UDP单播、组播,和大量数据的IPC通信。提供了Java/C++/.Net客户端,这几个客户端可以高效的在不同计算机之间,或者在同一计算机内通过IPC的方式非常高效地传输数据。此外消息流可以被归档模块持久化存储下来,以供以后(或实时)重放。The Aeron protocol is designed to be run directly over many different types of transmission media, including shared memory/IPC, InfiniBand/RDMA, UDP, TCP, Raw IP, HTTP, WebSocket, BLE, etc.性能是Aeron关注的重点,它旨在在任何消息传输系统中实现最高的吞吐量和最低的可预测的延时。其中的二进制编码模块SBE,号称比Google的ProtoBuf快8倍。另外加,Aeron还宣称,它在吞吐量方面击败了最好的产品,而在延迟方面能匹敌90%的最佳商业产品。它可以以每秒600万条的速度推送40字节的小数据包消息。Aeron的目标和使用场景如下:单播和组播的高吞吐量和低延迟通信支持多种传输介质(UDP/InfiniBand/共享内存等)支持多个流,且能提供不同的QoS单播和组播的有效的流控算法接收器程序可以按流进行速度控制Aeron比较现代化,参考了SPDY,HTTP2,WebSocket等协议。目前Aeron的中文文档比较少,但官方文档很详细,且维护力度比较强。参考它的传输协议定义。它可以根据自己的需要实现不同的拥塞控制算法,目前只提供了Cubic拥塞控制算法。参考Aeron: Do We Really Need Another Messaging System?。总结来说,Aeron是一个相对比较复杂的框架,它针对的不仅仅是Reliable UDP,而跨端、跨协议的高效通信,使用成本、定制成本也相对较高。但它有着专门的团队来维护。在微服务,RPC领域会有比较好的应用场景。

9、RSocketgithub:rsocket/rsocketRSocket是一种新的应用层网络协议,它由Facebook,Netifi和Pivotal等工程师开发,提供Java、Kotlin、JavaScript、Go、.NET 和 C++ 等语言的实现。RSocket 可以使用不同的底层传输层,包括 TCP、WebSocket 和 Aeron。TCP 适用于分布式系统的各个组件之间交互,WebSocket 适用于浏览器和服务器之间的交互,Aeron 是基于 UDP 协议的传输方式,这就保证了 RSocket 可以适应于不同的场景。RSocket 支持的四种交互模式:模式说明请求-响应(request/response)这是最典型也最常见的模式。发送方在发送消息给接收方之后,等待与之对应的响应消息。请求-响应流(request/stream)发送方的每个请求消息,都对应于接收方的一个消息流作为响应。发后不管(fire-and-forget)发送方的请求消息没有与之对应的响应。通道模式(channel)在发送方和接收方之间建立一个双向传输的通道。RSocket的通讯模式是对等通讯,不再介于传统的理解是Client -> Server模式,RSocket没有这个概念,大家的地位是对等的,都可以在server端,我调用你的服务,你也可以调用我的服务。应用场景和生态:RSocket && dubbo,Dubbo 在 3.0.0-SNAPSHOT 版本里基于 RSocket 对响应式编程提供了支持,用户可以非常方便的使用RSocket的语法。RSocket && Spring,Spring Framework 5.2 即将要把RSocket作为缺省的通讯协议,springBoot中也提供了支持。RSocket && 微服务,RSocket的主要障碍是应用程序之间必须要用RSocket通讯。微服务普及后,其为了“简化”微服务之间的通讯,引入了很多层的技术栈。参考使用 RSocket 进行反应式数据传输响应式编程之网络新约:RSocket。总结:RSocket是对一些可靠的网络传输协议的应用层封装,提供了很友好的API供上层使用,能方便的实现TCP/WebSocket/UDP等传输层和应用层的协议切换。在分布式系统集成中,RSocket 是很好的选择。

开源RUDP方案性能对比

TCP和RUDP弱网络丢包情况下的传输性能对比:imgimg横轴表示RTT(往返时间)、纵轴表完成输出占比量。 右上角的图例尤其突显RUDP在高丢包率网络环境下的优势,RUDP在[50-150]毫秒内完成约70%的数据传输量,而TCP完成的传输量较为平均地分布在各个延时区。再依据另外3个数据图,更能反映出RUDP相比TCP在更短的延时内完成了大部分数据量的传输。1、raknet对比libenet:服务端逻辑 单进程1us帧率运行,转回客户端数据包客户端逻辑 每个进程按30ms的频率随机操作:与目标服务器重建connection向目标服务器发送保活ping包随机传输模式和传输通道等组合参数,向目标服务器发送乱序数据包imgimg2、UDT、KCP、ENet对比(*原始文档*):这个测试的场景主要是针对实时对战游戏,比如第一人称的多人枪战游戏。

实时pvp游戏的特点是数据包小而频繁。它要求延迟尽可能小一点。测试环境:测试的服务端部署在互联网上,带宽是5M在电脑上运行client,ADSL的带宽是10M以上两个带宽的数值都比实际需要的带宽大很多(10倍左右)客户端每50毫秒将 500 bytes数据作为一个数据包发送出去。

(另一个测试是50字节)服务器收到数据包后发回数据。

测试结果:UDT:UDT在实时pvp游戏中表现不好但在正常情况下,延迟很完美网络发生延迟时,UDT表现很差严重的情况是超过数秒的延迟,甚至十秒钟。并且预计不会恢复

ENet:在实时PVP游戏方面,enet的表现比UDT好enet的延迟时间大约是1秒。而且从延迟到恢复只要几秒钟比kcp差,但是有些游戏允许1秒的延迟

KCP:kcp的延迟始终小于1秒。kcp比UDT和enet更好。当发生网络延迟时,KCP的延迟小于2秒。

总结:kcp是实时pvp游戏的首选(文档是中文的)当发生网络延迟时,kcp的延迟小于1秒,效率是enet的3倍如果您的游戏允许2秒的延迟,那么enet是一个不错的选择(enet文档较少)img

3、KCP、RakNet对比(原始文档,大型多人游戏服务端引擎 SpatialOS):imgimg在不可靠的网络上,KCP在延迟方面优于TCP和RakNet。对于25个实体,436271个数据包的最大RTT是51ms,而RakNet是114ms。对于50个实体,KCP表现更好。99.8%的数据,KCP的RTT是44ms,而RakNet的RTT是243ms。KCP的最大RTT是83ms,而RakNet是327ms。

4、腾讯云游戏对enet的深度测试(原文地址):原始enet保留了tcp重传的指数避让特性,每次重传间隔还是乘以2,默认rto也较高,这可能是上面测试中enet表现不如kcp的主要原因,如果对enet代码稍作调整,结果又当如何?作者对libenet略微做一些调整——默认rtt从500ms调整成50ms, 去除超时重传的指数避让策略。imgimgimg在平均响应方面,TCP协议的劣势不明显,在延迟为30ms,丢包率为1%时,改进后的enet平均rtt为69ms, 原始enet平均rtt为67ms, tcp平均rtt为67ms;但是从响应时间超过300ms的比例看,在延迟为30ms,丢包率为1%时,改进后的enet rtt超过300ms的包为0,而tcp rtt超过300ms的比例则超过了2%,如果是在游戏中,这个表现已经能明显影响游戏体验了。结果表明,tcp在网络稍不稳定的情况下就已经有比较大的问题了,改进后的enet有明显优势。应用案例学霸君及袁荣喜大佬的应用:全局250毫秒延迟的实时1V1答疑,采用的是RUDP + 多点relay智能路由方案。500毫秒1080P视频连麦互动系统,采用的是RUDP + PROXY调度传输方案。6方实时同步书写系统,采用的是RUDP + redo log的可靠传输技术。弱网WIFI下Pad的720P同屏传输系统,采用的是RUDP+ GCC实时流控技术。大型直播的P2P分发系统,通过RUDP + 多点并联relay技术节省了75%以上的分发带宽。

参考RUDP传输那些事儿 。MOBA类和“吃鸡”游戏使用UDP。参考https://juejin.im/post/5a2f78d1f265da431b6d2c02

总结:TCP发展了多年,比UDP更加稳定。但如果在延时、吞吐量等方面有较高的要求,一些RUDP的方案也考虑用于替换TCP。

笔者对这些RUDP库的总结如下:

  • KCP在一些多人对战游戏中使用的比较多,生态相对完善,定制能力也很强。
  • Aeron是一个比较现代化的RUDP方案,它的目标不是RUDP,而是跨端高效数据传输,它的文档也很全面。但是它的内部实现比较复杂,使用和定制需要一定的成本。
  • RSocket相当与是对Aeron的封装,目标是点对点通信,同时有着Spring框架的支持。如果有业务需要,可以比较方便的把传输协议在TCP/WebSocket/RUDP之间切换、迁移。但这种高度封装的库,自然在底层传输协议上的定制能力就会差一些。
  • WebRTC的DataChannel可以当做RUDP使用,但是它是对STCP over UDP的一种实现,定制能力比较差。况且,为了使用RUDP而引入WebRTC这种复杂的技术框架带来的成本是很高的。
  • SCTP over UDP,短期看不可行。
  • QUIC也是个比较复杂的协议,定制能力稍差些,不过可以在业务层配置不同的拥塞控制算法,内部的实现也很先进、现代化。但缺乏生态。
  • UDT/ENet/raknet更新力度不行,感觉像是被放弃了。
最近的文章

笔记集锦-Elixir

核心:匹配=号是匹配.表示左边和右边互相匹配值.<- 匹配,但匹配失败时,不会报错,而是返回nil值.不可变所有值,一旦创建就不可再改变.基础 整数: 任意大小的整数 浮点数 原子: 全局唯一名称 区间Range: start..end 正则表达式: 可用~r/../ 或其他~r{..} 等sigil包裹. 在Regex模块中. PID和端口: 进程ID.端口表示可读写的资源引用.self表示自身进程. 引用.全局唯一引用.复合数据类型: 元组...…

继续阅读
更早的文章

笔记集锦-Lisp

语法:() 空表(obj1 obj2 ...)(procedure arg ...)(car (list)) 取第一个元素(cdr (list)) 取列表剩余元素(cons a b) 将2个参数构建成列表(list a b ...) 与cons相同,构建列表,但可允许任意参数(quote (expr)) 将表达式当作列表 '(expr) 引用的语法糖((car (list + - * /)) 2 3)(let ((var expr) ...) bo...…

继续阅读