闲聊:最近想要做一个用在网络游戏领域的网络控制协议小玩具,大体聊聊构思的想法

51 篇文章 2 订阅

这个控制协议跟 “猛禽 UDP/IP Aggligator 宽频聚合器”,是不同的,因为预期该网络控制协议,预计侧重在网络游戏加速这块。

所以它与多数网络控制协议,会有一定的不同。

但要先分析具体的目标场景,基本现代所有的 UDP/IP 应用层网络协议,都具备丢包重传控制,当然有一些是不在乎丢包的。

所以,一般来说保证 UDP/IP 不丢包,是没有太大意义的,因为这只会出现以下两种情况:

1、UDP/IP 网络应用,可以丢包,它们会忽略这类问题,因为不重要。

2、UDP/IP 网络应用,自己带了,可靠CC(类似 KCP/TCP/QUIC 的控制协议)。

那么类似网络应用产品(有):

1、灵境奇谈 (封灵笔记)

2、CS:GO    (反恐精英:全球攻势/cs2)

3、Warframe(星际战甲)

回到正题,既然知晓了问题的所在,那么就来开始按照不同的应用场景来调优,每个不同的网络应用调优方法是不同的。

但,我们通常预期目标都是为了减少网络抖动、只要产生丢包,那么网络抖动就会非常严重,而且在现代网络之中,因为路由跃点之间的不同,客户端到服务器之间的网络路由是随时波动的,即便路由没有变动,也会因为路由本身的QOS管理策略,导致帧的先后顺序发生改变(即乱序问题)产生抖动问题,因为若客户端需要排序,那么在收到来自未来帧时,是先缓存在接收方队列之中,等待确认帧(包)的到达,在这个空窗期就会产生抖动问题。

所以对于游戏加速,为了质量最好,会有两个以下解决方案:

1、对于UDP/IP带控制协议的网络游戏

我们可以采用,当收到游戏UDP数据包之后立即发出到服务器,并且为每个数据包标记帧序号,接收方,可以根据在1 ~ 5个毫秒内跳过的帧号,来评估网络的丢包层度。

注意:是采用旁路观察的办法,即控制协议来决定,发送方应该发送多少个冗余包,即:当收到客户端A包之后,发出几个包到服务器,如果丢失了一个包、由于冗余多发,虽然占用了更大的带宽,但延迟、抖动这块是基本被抹平了。

比如:

我们可以通过测算出来的每个帧需要发送几次,可以评估为:10个包丢一个包,则冗余发送一个包,5个包丢一个包,则冗余发送两个包,虽然这可能浪费更多的网络带宽。

网络之中5个包丢一个包,放大到3倍,产生一个包都无法到达的可能性几乎是没有的,在保证RTT、抖动不变大的情况,这是最佳解决方案,即通过冗余传送来保证。

但接收方一般拿需要确保不会出现重复帧转发的问题,即可:接收方收到已经转发过的帧不能再次转发,但为了可靠性也可以再次转发过去,让目的服务器自己处理它,但前提是目的是服务器允许这样的行为,这个要靠人们自己去测算。

网络游戏加速一般都是定向分析,定向研究加速解决方案的。

另外一种是做一个带ARQ(自动请求重传)的控制协议,这种像TCP/IP流控协议的做法就没有那么好了。

我们可以如此这般设计并处理,但它仍旧会产生一个抖动问题。

1、帧带上序号跟确认号。

2、接收方收到帧后,如果是当前确认号就确认并且交付

     如果序号小于确认号,只要不是序号回绕问题,就丢弃帧。

     如果序号大于确认号,就预先缓存在接收方队列之中。

     当然如果缓存的数据包,已经占用了窗口大小的 50% 以上,就立即发出ACK+NAK包

     另外为了提高效率,当连续收到 “2 ~ 3” 个来自未来的包(跳过),那么可以立即发出ACK+NAK 包,但建议是放在跟下面 Delay 一毫秒后在处理。(可以理解为:快速重传机制)

     否则检查设定一个毫秒后ACK的计时器句柄,在一个毫秒之后检查,因为这一个毫秒过后可能网卡会达到无数个包,此时在判断那些包已经收到,那些包被跳过,在发出ACK+NAK数据包告诉服务器,可以一定减少昂贵的带宽资源浪费。

       

     接收方收到ACK+NAK包以后,更新发送方的窗口大小,并且删除自己的已经缓存的数据包(尽快释放内存资源占用)、并且NAK上面指示的没有收到包重新发送出去。

    注意:NAK为否定应答(即接收方发出没有收到的帧到发送方),对的网络游戏加速,比较适合按照帧来确认,帧填充的方式来传输,而不是流式传输。

   重传时间(测算):默认情况下单位为1秒,在第一个测量出来的RTT(往返时间)这个可以从链接握手时确定。

   即:客户端发送链接建立的帧、到服务器应答客户端应答帧的第一个RTT时间作为SRTT、RTT_VAL(RTT/2)初始值。

关于重传时间的时间可以采用下面的公式,TCP/IP(但需要魔改)

R = RTT

SRTT = 平滑RTT时间

RTTVAL = RTT因子

第一个RTT测量:

K = 4(常数)

SRTT = R

RTTVAR = R/2

RTO = SRTT + max(G,K*RTTVAR)

第二个RTT测量:(及之后)

注意:它需要通过 “NPU/SSE” 浮点数来运算

alpha=1/8

beta=1/4

RTTVAR = (1 - beta) * RTTVAR + beta * |SRTT - R|            

SRTT = (1 - alpha) * SRTT + alpha * R

RTO = SRTT + max (G, K*RTTVAR)

补充:

G为时间精度常数,在内核之中它被设定为200毫秒。

Linux TCP_RTO_MIN, TCP_RTO_MAX and the tcp_retries2 sysctl (pracucci.com)

#define TCP_RTO_MAX ((unsigned)(120*HZ))
#define TCP_RTO_MIN ((unsigned)(HZ/5))

下述为KCP控制协议算法的RTO重传时间计算公式:

      它与上面的公式区别不大,只是对系数微调的区别,即:KCP约为TCP/IP控制协议重传时间除以1.25~1.5倍左右。

static void ikcp_update_ack(ikcpcb *kcp, IINT32 rtt)
{
	IINT32 rto = 0;
	if (kcp->rx_srtt == 0) {
		kcp->rx_srtt = rtt;
		kcp->rx_rttval = rtt / 2;
	}	else {
		long delta = rtt - kcp->rx_srtt;
		if (delta < 0) delta = -delta;
		kcp->rx_rttval = (3 * kcp->rx_rttval + delta) / 4;
		kcp->rx_srtt = (7 * kcp->rx_srtt + rtt) / 8;
		if (kcp->rx_srtt < 1) kcp->rx_srtt = 1;
	}
	rto = kcp->rx_srtt + _imax_(kcp->interval, 4 * kcp->rx_rttval);
	kcp->rx_rto = _ibound_(kcp->rx_minrto, rto, IKCP_RTO_MAX);
}

     但同时,需要设置一个最小RTO时间的边界值(临界值),这个值根据实际生产需要,可以设置为40、100毫秒即可,但对于游戏加速这种场景设置为40 ~ 60毫秒,一般会比较合理,RTO不能太小,否则会浪费大量带宽的,我们应该通过快速重传的方式来处理,而不是依赖于设计的控制协议RTO自动重发来处理。

       

关于发送方,因为根据接收方传递过来的窗口大小来发送数据,为了提高效率:应该是对面接收方有足够接受能力收到足够大的字节数时,一次性把发送队列之中带传输的数据包输出过去,在根据接收方投递的ACK/NAK来实时更新窗口大小,以便评估是否需要继续发送数据到接收方。

但需要注意一点:接收方跟发送方之间,建议采用 “背负式确认” 的方式来处理,这可以减少没必要单独的 ACK 报文发出,节约两端的网络带宽资源,但这可能会带来一定对于网络控制协议栈编程的复杂度。

RTO 值得计算用KCP修改后的系数会比较好一些,当然人们仍旧可以大胆得重新调整系数,无外乎是牺牲更多带宽,还是更小网络带宽得问题,另外也可以选用 BBRplus(BBR+)得调效模式,尽量避免提高RTO重传时间,以避免网络吞吐效率的降低,但这会增加网络拥塞层度的问题。

补充:

简单说一说SWS问题(糊涂窗口综合症问题)

在控制协议之中,我们大家都是通过窗口来评估对方的接收能力,如果对方窗口堆满,我们就不能发送。

所以对方只要收取且交付数据就需要更新窗口大小,但不可能为了更新窗口大小,每次都去立即发出ACK报文。

我在上篇文中没有着重的探讨这个问题,而是说推迟确认(延迟1毫秒)都是为了解决,类似如这个SWS糊涂窗口问题。

但仍可以通过算法评估解决该问题的ACK发出时机。

可以窗口边缘滑动了:
1/4缓冲区 or 4个MSS大小

来评估是否立即发出ACK报文,迫使发送方更新接收方窗口大小,否则应在下个正常发出帧数据背负式确认。

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值