先放两个链接

快速可靠协议-KCP

可靠 UDP 传输

最近在玩王者荣耀,发觉两件事:

1. 可以 4G 和 wifi 无痛切换

2. 当网络不好的时候,发出去的消息并不保证到达服务器。比如你在很卡的时候做了某些操作,等网络恢复之后你会发现,你还是在某个没有做那些操作之前的状态

结合这两周阅读的 KCP,我能想到的是,对于第 1 点基于 KCP 就可以实现。

初读 KCP 的时候,对 conv 变量的存在十分不理解,为什么要用它来表示一个会话,直接由 recvfrom 返回的源 IP 和 port 做 key,找到对应的 ikcpcb 不好么。

有这个想法是因为脑海中始终还想着 TCP 那一套,也就是 用一个四元组来唯一确定一个连接。直到我后来再次想到上面第 1 个问题,才想明白,在 UDP 之上定义连接的概念,如果还是将它跟四元组绑在一起,那无非是实现了另一个 TCP。而当你用一个 conv 变量来标识一个连接时,这个协议的连接也就天然的跟源 IP 和 port 无关,也就是随便你变换 IP 地址和端口,只要你发来的 conv 是一样的,我就认为你是同一个用户。当然,代价就是你得开始关心 conv 的生成与校验,这又是另一个话题。

对于第 2 种情况(暂且不论这种做法是否玩家体验最好),却不像 KCP 的行为,因为 KCP 是能保证发出去的数据包一定到达服务器的。

而云风那篇博客里提到的以请求的方式来保证 UDP 的可靠,貌似恰好可以做到符合王者荣耀的表现。也就是可以做到:1. 允许丢包  2. sn 严格递增

可问题是 服务器发给客户端的数据是不允许丢失的,这可怎么办。。

协议层没给的承诺,只好有业务层来做咯~

首先是帧同步,并且服务器会保存当前这一场的所有帧的数据。那么如果客户端收到了编号为 1,2,5 的数据帧,当收到编号 5 的数据帧时,发现没有收到 3,4 帧,就要向服务端索要丢失的这两帧数据。也就是在客户端的业务层也实现一套请求机制,只不过客户端业务层请求的是数据帧而不是协议层的数据包,服务端对数据帧是没有过期时间的,所以客户端发了请求就一定能求来数据帧!

还有一个问题,就是在游戏大厅时,服务器发给客户端的消息,也要保证送达,这个怎么办?因为大厅里的消息并非所谓帧同步,理论上服务器也不会保存那些临时消息,所以如果还是基于这种请求模式的话貌似就不太靠谱了。我个人感觉这个时候用 KCP 比较好。当然,场内也可以用 KCP,只不过是另外一种效果。

总结一下这两种模式:

1. ack + 超时重传  ->   KCP    可靠     快速重传    但是当网络差到快速重传也发不到的时候,服务器会堆积大量需要重传的数据包

2.  req  -> rudp   会丢包    但是保证包的顺序     不管网络好坏,服务器发送数据都很平稳

更新

修改 KCP 也可以实现王者荣耀的效果。

ikcp_send 前,先检查 ikcp_waitsnd,如果 waitsnd 大于某个阈值比如 64,则认为当前网络太差,然后不调用 ikcp_send,丢弃这个数据(或者上层消息队列继续缓存这个数据,从王者的表现来看是直接丢弃的)。同时启动一个计时器,如果 waitsnd 持续 10s 都大于 64,则认为网络奇差无比,根本无法游戏,销毁 kcpcb,断线处理。如果 10s 内 waitsnd 一旦小于 32,则认为网络恢复正常,取消掉前面的计时器。

对 UDP 的一些思考的更多相关文章

  1. 对udp dns的思考2

    上一篇文章写道了udp 使用reuseport 多线程编程!!! 但是有几个问题需要考虑一下: 之前hash使用sip sport dip dport为key, 很正常同一个客户端回hash到同一个s ...

  2. 对udp dns的一次思考

    目前昨天查一个线上问题:""dns服务器在我们的设备, 有大量的终端到设备上请求解析域名,但是一直是单线程,dns报文处理不过来", 然而设备是多核,dns服务器一直不能 ...

  3. TCP的流模式与UDP的报文模式对比

    1       案例背景 在学习TCP-IP协议详解卷一时,读到介绍TCP协议的部分,发现TCP的首部是没有报文总长度字段的,而在UDP中是有的,对这个问题的思考引出了两者之间的区别. 2    案例 ...

  4. OpenVPN多实例优化的思考过程

    1.sss 当构建组件之间的关系已经错综复杂到接近于一张全然图的时候,就要换一个思路了,或者你须要重构整个系统,或者你将又一次实现一个. 2.TAP网卡和TUN网卡 2.1.TAP的优势 1.方便组网 ...

  5. java udp (使用类调用双通信)1

    项目需要就使用了UDP通信,做了java的双方通信,其实代码还是来自之前的udp学习代码,自己加了注释,并且优化的使用类来封装关于通信类库的使用代码 目的是为了在安卓项目中使用时,可以通过实例化,调用 ...

  6. java udp socket通信(仅发送)

    实现功能:客户端发送一个字符串(可以为汉字),服务器端接收并显示 服务器端程序: package udpServer; import java.io.*; import java.net.*; /** ...

  7. python3全栈开发-补充UDP的套接字、操作系统、并发的理论基础

    一.基于UDP的套接字 udp套接字简单示例 import socket ip_port=('1.1.1.1',8181) BUFSIZE=1024 udp_server_client=socket. ...

  8. JAVA之旅(三十二)——JAVA网络请求,IP地址,TCP/UDP通讯协议概述,Socket,UDP传输,多线程UDP聊天应用

    JAVA之旅(三十二)--JAVA网络请求,IP地址,TCP/UDP通讯协议概述,Socket,UDP传输,多线程UDP聊天应用 GUI写到一半电脑系统挂了,也就算了,最多GUI还有一个提示框和实例, ...

  9. 网络协议 7 - UDP 协议:性善碰到城会玩

        网络协议五步登天路,我们一路迈过了物理层.链路层,今天终于到了传输层.从这一层开始,很多知识应该都是服务端开发必备的知识了,今天我们就一起来梳理下.     其实,讲到 UDP,就少不了 TC ...

随机推荐

  1. Gitlab安装与备份恢复

    GitHub是2008年由Ruby on Rails编写而成,与业界闻名的Github类似;但要将代码上传到GitHub上面,而且将项目设为私有还要收费.GitLab是一个用于仓库管理系统的开源项目, ...

  2. 一次sendmsg的改造过程

    比较蛋疼的一个改造过程,简单记录一下. 场景:用户态使用sendmsg发包,tcp报文,由于内核实现过程中存在一次kernel_read,也就是存在将pagecache中的内容拷贝一次的问题. 为了减 ...

  3. Nginx 工作原理

    Nginx 工作原理 Nginx由内核和模块组成. Nginx本身做的工作实际很少,当它接到一个HTTP请求时,它仅仅是通过查找配置文件将此次请求映射到一个location block,而此locat ...

  4. 在网站中使用UEditor富文本编辑器

    UEditor是由百度WEB前端研发部开发的所见即所得的开源富文本编辑器,具有轻量.可定制.用户体验优秀等特点. 官网链接 进入到下载页面,选择相应的版本下载 这里我们使用ASP.NET开发,所以选择 ...

  5. shell一出手

    1.查看有多少个IP访问: awk '{print $1}' log_file|sort|uniq|wc -l 2.查看某一个页面被访问的次数: grep "/index.php" ...

  6. 手游开发之lua的table 元表的运用

    元表在项目中的运用,其中就包括元方法这点.元方法是指__index和__newIndex,下面我总结下,更详细的例子讲解可以参考<lua程序设计 第2版>的第13章内容.长h短说,简言之有 ...

  7. Block学习总结

    最近网上浏览了一些关于Block的文章,自己进行一下消化吸收. Void (^blockName)(parma)-> Block声明 Void (^) (parma){};  ->Bloc ...

  8. vue获取后台图片验证码,并点击刷新验证码

    <--url为需要访问的接口地址--> <span style="display: inline-block;width: 130px;height: 53px;borde ...

  9. cmd中sudo以后显示password不能输入密码

    文本界面还是图形界面下输入密码都不会有回显,这是为了安全考虑. 其实你不是不能输入密码只是你看不到而已,事实上你已经输入进去了,回车后就能看到效果了. 来源于:https://zhidao.baidu ...

  10. python中type、class、object之间的关系

    先看一段代码 # -*- coding:UTF-8 -*- __autor__ = 'zhouli' __date__ = '2018/11/13 18:40' a = 1 b = 'abc' pri ...