对 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 的一些思考的更多相关文章
- 对udp dns的思考2
上一篇文章写道了udp 使用reuseport 多线程编程!!! 但是有几个问题需要考虑一下: 之前hash使用sip sport dip dport为key, 很正常同一个客户端回hash到同一个s ...
- 对udp dns的一次思考
目前昨天查一个线上问题:""dns服务器在我们的设备, 有大量的终端到设备上请求解析域名,但是一直是单线程,dns报文处理不过来", 然而设备是多核,dns服务器一直不能 ...
- TCP的流模式与UDP的报文模式对比
1 案例背景 在学习TCP-IP协议详解卷一时,读到介绍TCP协议的部分,发现TCP的首部是没有报文总长度字段的,而在UDP中是有的,对这个问题的思考引出了两者之间的区别. 2 案例 ...
- OpenVPN多实例优化的思考过程
1.sss 当构建组件之间的关系已经错综复杂到接近于一张全然图的时候,就要换一个思路了,或者你须要重构整个系统,或者你将又一次实现一个. 2.TAP网卡和TUN网卡 2.1.TAP的优势 1.方便组网 ...
- java udp (使用类调用双通信)1
项目需要就使用了UDP通信,做了java的双方通信,其实代码还是来自之前的udp学习代码,自己加了注释,并且优化的使用类来封装关于通信类库的使用代码 目的是为了在安卓项目中使用时,可以通过实例化,调用 ...
- java udp socket通信(仅发送)
实现功能:客户端发送一个字符串(可以为汉字),服务器端接收并显示 服务器端程序: package udpServer; import java.io.*; import java.net.*; /** ...
- python3全栈开发-补充UDP的套接字、操作系统、并发的理论基础
一.基于UDP的套接字 udp套接字简单示例 import socket ip_port=('1.1.1.1',8181) BUFSIZE=1024 udp_server_client=socket. ...
- JAVA之旅(三十二)——JAVA网络请求,IP地址,TCP/UDP通讯协议概述,Socket,UDP传输,多线程UDP聊天应用
JAVA之旅(三十二)--JAVA网络请求,IP地址,TCP/UDP通讯协议概述,Socket,UDP传输,多线程UDP聊天应用 GUI写到一半电脑系统挂了,也就算了,最多GUI还有一个提示框和实例, ...
- 网络协议 7 - UDP 协议:性善碰到城会玩
网络协议五步登天路,我们一路迈过了物理层.链路层,今天终于到了传输层.从这一层开始,很多知识应该都是服务端开发必备的知识了,今天我们就一起来梳理下. 其实,讲到 UDP,就少不了 TC ...
随机推荐
- leetcode139
class Solution { public: bool wordBreak(string s, vector<string> wordDict) { vector<, false ...
- <记录>TP5 关联模型使用(嵌套关联、动态排序以及隐藏字段)
在数据库设计中,常常会有如下这种关联模型,分类表中一条分类对应多个商品表中的商品 如果要获得分类表中每条分类 以及 对应的商品的信息,则需要先查询分类表中的数据,然后根据结果遍历查询商品表,最后把数据 ...
- Linux网络编程学习计划
由于网络编程是很重要的一块,自己这一块也比较欠缺,只知道一些皮毛,从今天开始系统学习<Linux网络编程>一书,全书分为十四个章节: 第一章 概论 P1-16 第二章 UNIX ...
- 多层josn数据 修改
var aa = { a: 1, b: { c: 1, d: 1 }, e: [{ f: 1, g: 2 }, { h: 1, i: { j: 3, k: [{ l: 55, m: [1, 2, 3, ...
- 移动端的1px边框问题
最近在做一个移动端项目,涉及到1像素问题 其实质就是移动端的css里写1px,看起来比1px粗,这就是物理像素和逻辑像素的区别.物理像素和逻辑像素之间存在一个比例关系,在Javascript中可以用w ...
- 100-days: fifteen
Title: Disney(迪士尼) moves from behemoth to colossus with closing(使…结束,使停止) of Fox(福克斯) deal(商业上的交易/协议 ...
- Python基础-python数据类型(四)
python数据类型 在python中,变量就是变量,它没有类型,我们所说的类型是变量所指的内存中对象的类型. python中的数据类型: 1.数字 python中没有专门定义常量的方式,通常使用大写 ...
- hdpi对应分辨率
ldpi QVGA (240×320) mdpi HVGA (320×480) hdpi WVGA (480×800),FWVGA (480×854) xhdpi 720P(1280*720) ...
- 为了应对异常情况,提供最原始的python第三方库的安装方法:手动安装。往往是Windows用户需要用到这种方法。
进入pypi.python.org,搜索你要安装的库的名字,这时候有3中可能: 第一种是exe文件,这种最方便,下载满足你的电脑系统和python环境的对应的exe,再一路点击next就可以安装. 第 ...
- ajax的另一种成功和失败回调函数
第一种: function engline(){ var oldmsg = $('#lineso').val() if(oldmsg == null || oldmsg == '' || oldmsg ...