udp可靠传输那些事之游戏篇

    关于使用udp可靠传输在替代tcp传输方面,我之前已经写过文章,http://blog.csdn.net/danscort2000/article/details/8432778,说明了udp可靠传输相对tcp的优点和缺点,这里不再重复说明,但是,有一个特殊的应用范围是非常适合使用udp传输代替tcp传输的,这就是对网络传输的实时性为第一考虑的实时网络游戏应用.

   网上有不少文章都谈到了使用udp可靠传输替代tcp,应用在网络游戏中的原因,也看了几个udp在游戏中应用的实现,感觉存在不少的误解,有些udp的特性并没有发挥出来,例如乱序可靠传输,只能算是能用,指导思维有问题, 很多都没有解释清楚,需要详细解释一下,计划重写一个udp可靠传输实时性实现代码来对比测试一下.

       我们来看以下TCP协议栈的具体实现, tcp是通过滑动窗口进行流量控制的, 而tcp层的数据是通过ip层进行分片传输,然后tcp层重新组合,而当其中任意一个ip包发生丢包的时候,让我们来看看会发生什么事情?通常是根据当前的延迟数字[根据之前ip包的传输延迟来综合计算的一个数字], 第一次丢包的计算方法是 2*延迟+延迟常量,并且不小于定义的最小延迟数字, 这个延迟数字我们在应用层是无法强制修改的,因为是协议栈的实现,到了延迟时间后重新发送一个ip包, 每当发生丢包,tcp会"友好"的认为,是网络发生了拥堵,带宽不够导致的,然后就会缩小窗口[缓冲],降低传输速率, 如果所有的实现,包括udp可靠传输,大家都采用这种"友好"的流水不争先思想,这没什么问题.通常可以把网络带宽浪费降低到最低 [因为tcp/ip协议栈实现时候的网络,1Mbps已经很奢侈了,因此优先考虑的就是避免带宽浪费], 有些udp可靠传输会说自己的实现可以抢带宽, 尼玛这不是抢带宽,这是耍流氓,大家开车都在按规则排队等待通行,你Y的来加塞,不是别人抢不过你,而是人家都是文明人.  tcp的算法里,它采用了慢启动,这在文件传输等非实时应用里,没什么问题,而且带宽的浪费,也就是错误发送重复包的概率,要低于1/1000,这没什么问题,但是在对实时要求性很高的网络游戏里,你可能期望如果50ms没有收到ack,就立即重新发送,带宽的浪费让位给实时需求,但是tcp的最低重发[不同实现数字不同]通常都至少是180ms,让你干瞪眼. 还有什么问题呢? tcp是个有次序的流传输, 假设ip层发了10个包,编号1到10,可要命是的偏偏1号包丢了,然后后续所有的2到10号包只好等在缓冲里,去等待1号包的重发,数据卡壳,然后tcp还认为当前的重发是带宽不够引发的,就缩小了窗口,好了,引发一连串的反应. 

   无线网络下的tcp表现,

   在无线网络下,偶发性丢包是个大概率事件,这对tcp来说是要命的,针对偶发性丢包,正确的做法是尽快重新传输丢的包,但是tcp的算法确判断反了,它认为是网络发生了拥堵,应该减慢发送速度,然后就比较悲剧了,这也是为什么我们常说,再牛的无线网络也赶不上一条垃圾有线网络来的稳定的原因.

  初步总结,tcp目前的实现,对连续的网络拥堵引发的丢包有非常好的适应性,带宽浪费极低;但是当遇到偶发性丢包的时候,目前的实现判断失误了,因此在对网络实时性要求高的场合,效率是不够的.

同时使用tcp和udp可靠传输的互相干扰

  如果一个游戏同时采用tcp和udp传输,确实会发生互相干扰, 这主要是tcp的拥塞控制机制引发的, 因为tcp和udp最终都是通过ip层进行传输,而tcp或者udp可靠传输的实现,对延迟的控制和判断是彼此独立的,当双方都同时进行大数据量传输的时候,ip层会出现类似 tcp包 udp包 udp包 udp包 tcp包这样的发送队列,按通常的算法, udp可靠传输和tcp都会检测到延迟加大, 因此都会判断是网络拥堵彼此都放慢发送速度,耍流氓的算法除外,

upd和tcp最终都是被封成ip包进行传输的,我们来看一下,什么情况下,会出ip丢包情况

[1] 发送方网络拥堵导致,多个应用同时启用大数据量网络传输,例如你在进行游戏的时候,同时有bt类下载进行,以及其他如手机访问网络,这种场景在家庭网络下经常发生的,在某个时间点下ip层包发送数量超过了路由器[网关]的处理队列极限, 这个时候路由器会根据算法或者随机丢包[普通rom实现]或者根据优化丢弃某些特定包[一般是udp包].

[2] 物理错误导致,物理链路传输过程中,因为crc校验错导致包丢失,这个概率非常小,所以实际上ipv6干脆取消了传输过程中ip crc校验,但是也存在这个可能,就当中奖了.

[3]传输过程丢包, ip包在经过isp线路到达目标ip前,因为路由路径错误导致丢包,或者在经过某些节点的时候因为拥堵而被随机丢包,这个概率一般在1/1000以下.

[4] 接收方网络拥堵导致, 好多应用在某个时间片爆发发送大量数据,特别是发送大量udp小包,超过了对方路由器[网关]的处理速度或者队列极限,同样会产生随机丢包

[5]  无线网络传输过程丢失, 无线网络方便,但是不稳定,传输过程中,路由器与无线终端之间,哪怕只是跑过一只狗,都可能引发传输错误导致丢包, 平常家用无线丢包的概率千分之几到百分之几,连接握手速度越高,丢包概率越高.

[6] 其他 , 应该基本是中大奖的概率了

那么,当丢包发生后,我们如何判断是发生了什么情况,协议里又应该如何操作呢?

丢包的原因123456,ip层是无法知道了,因为没有反馈,不同的上层实现有不同的指导思想和处理意见

tcp的指导思想很简单, 如果发现某个包在指定延迟时间后,依然没有ACK确认,那么就认为是丢包了,重发一个,并降低发送速度,这种处理方法的好处是 发生了丢包,一律认为是发生了网络拥堵,这样可以最大限度的降低重复发包导致的带宽浪费,也就是以避免带宽浪费为主要指导思想,一个100M的连接,一个tcp应用在小概率丢包情况下可能只能利用到98%的带宽,但是它因为重复发报而导致的带宽浪费可能千分之一都不到,如果同时有两个以上tcp应用,那么基本就可以接近100%了,浪费率[错误重发]极低.

常规的udp可靠传输,除了1到6可能引发的丢包,还需要增加 7 由于udp可靠传输是在应用层实现的, ACK确认也需要在应用层实现,那么当系统内核处理很忙碌的时候,例如大量的磁盘i/o并发操作等,或者游戏进程占用了大量的时间片,cpu资源不足,那么就会导致应用层无法及时读取SOCKET缓冲里的数据包,也无法及时给对方发送ACK,而对方并不知道是因为接收方系统忙碌导致了接收延迟,于是在规定的延迟时间到了还没有ACK确认,就会重复发包并认为丢包,并进行调整缓冲或者加大延迟. 通常目的的udp可靠传输实现,只是为了利用udp可塑性好的特点,实现包流二重传输部分替代tcp, 因此一般也是以最大限度的降低重复发包导致带宽浪费为指导思想,也许有些udp可靠传输会说我的实现可以抢带宽,尼玛你这不是抢带宽,而纯粹在耍流氓,大家都按规矩排队,你在抢红灯不按规矩出牌,当然有一个领域例外,这就是要求网络数据实时传输优先的网络游戏类应用.

现在,我们来看看实时网络传输优先的游戏类应用的特殊性,为什么要选择udp可靠传输:

[1]网络游戏类应用会对硬件cpu等有基本的需求,这样除了可以保证游戏内容本身的流畅度,同时也保证了应用层的udp可靠传输可以有足够的cpu时间片.

[2]网络游戏类应用一般对带宽的要求在 1.2Mbps到 4.8Mbps, 相对于目前的平均10+Mbps以上的带宽,为了保证足够的网络实时性,在进行游戏的时候,可以要求不要同时进行其他类似bt的下载操作,可以要求用户不要同时执行其他大流量网络应用,这样可以在udp可靠传输中,放弃tcp类的一律认为是网络拥堵的指导思维,而改用认为是偶发丢包的指导思想,也就是可以耍流氓,用浪费一点带宽来保证实时性,而不是节省带宽. 单纯使用tcp进行游戏数据传输,因为tcp拥堵算法的慢启动缺陷,不太适合此类应用,例如tcp在偶发丢包的情况下你可能只能做到180ms内的延迟,但是换用udp可靠传输,可以优化到60ms.

[3]网络游戏类,有大量数据不需要保证可靠性与有序性的数据,只能通过udp来进行传输,同时,要udp可靠传输也是唯一可以实现有序与无序可靠数据传输的方法,除此你找不到其他合适的方法.

[4] Tcp实现中,对于数据报的重发默认下限时间片数据太高,是不太适合实时性游戏网络类应用的,也就是很难保证数据的实时连续传输,而udp是可以实现乱序可靠传输与有序可靠传输的,不会因为一个前序包的丢失引发连锁反应.

[5] 游戏类应用,因为服务器端和客户端是唯一配套的,不需要考虑第三方兼容性,因此udp可靠传输完全可以实现专门的优化,并确定缓冲区大小而不需要动态适应,可以作到深度优化,这是tcp做不到的,虽然udp可靠传输是应用层的实现.

udp可靠传输在游戏类应用的优化,与通用udp可靠传输或者文件传输类udp可靠传输的优化方向是相反的,游戏类应用优化是以耍流氓的方法来实现优化,即使存在一定概率的错误重发[浪费带宽]也在所不惜,把丢包统统当作是偶发性错误,而通用udp可靠传输或者文件传输类udp可靠传输,则类似tcp算法,将丢包当作是网络拥堵引发,并采用一定的算法来加大发送延迟或者缩小发送速率,以降低带宽浪费为目的.

如何取舍与优化,勇敢去尝试,这里没有特定的最优算法,网络一直在发展,只有天知道.

相关文章
相关标签/搜索