Keep looking Donot settle
分类: 嵌入式
2015-06-16 10:23:07
记得以前做游戏时,就出现了一个问题,我们鼠标从背包物品上移动时,应该会出现物品的tips信息。在我们的游戏中,从背包的左边格子移动到右边格子时,tips信息总是出现的太慢。这是一个问题。另外一种现象是点击任务NPC后,出现弹框,点击接受任务时从会转一会圈(前端设置了必须后端有消息返回才停止转圈)。而这两个问题其他网页游戏好像都没有,所以我们很奇怪,因为我负责任务模块。
所以我对第两个问题还是很关注,一直以为的后端太卡了。至于在哪里则找不到。后来我们组长对这个过程进行抓包分析后知道是服务器返回消息太慢导致。后来我们就设置了tcp_nodelay,效果很明显,很多响应都快了。其他同事都感觉太神奇了。我也觉得是。哈哈
现在记录一下今天看到这两个定义的理解
nagle算法:为了减少小包的发送次数,进行延迟发包。只有在两个情况下会触发发送:1.前面一个包的ack已经到达 2. 200ms超时到了
tcp_nodelay:禁止nagle算法,有需要发送的就立即发送
tcp_cork:它是一种加强的nagle算法,过程和nagle算法类似,都是累计数据然后发送。但它没有 nagle中1的限制,所以,在设置cork后,即使所有ack都已经收到,但我还是不想发送数据,我还想继续等待应用层更多的数据,所以它的效果比nagle更好。
url
http://blog.csdn.net/dog250/article/details/5941637
这三个选项十分有意思,并且困扰了很多人。特别是cork选项,它到底和nodelay有什么区别,到底怎样影响了Nagle算法。在tcp的实现中(特指linux内核的协议栈实现),cork和nodelay非常让人看不出区别,这一块的实现非常复杂,看内核实现之前最好先明白它们大概在说什么,否则很容易迷失的。
所谓的cork就是塞子的意思,形象地理解就是用cork将连接塞住,使得数据先不发出去,等到拔去塞子后再发出去,而nodelay事实上是为了禁用Nagle算法,Nagle算法为了增加了网络的吞吐量而牺牲了响应时间体验,这在有些应用中是不合适的,比如交互式应用(终端登录或者远程X应用 etc.),因此有必要提供一个选项将它禁用掉,Nagle算法在RFC1122中有提及,它的实现实际上很简单,利用了tcp本身的一些特性,在算法描述中,关键的一点是“什么时候真实的发送数据”,这个问题的解答也是很简单,原则上只要发出的包都被对端ack了就可以发送了,这实际上也是一种权衡,Nagle算法最初的目的在于解决大量小包存在于网络从而造成网络拥塞的问题(一个小包可能只有几个字节,比如ls,cat等等,然而为每个小包封装几个协议头,其大小就不可忽视了,大量此类小包存在于网络势必会使得网络带宽的利用率大大下降),如果包被ack了,说明包已经离开了网络进入了对端主机,这样就可以发送数据了,此时无需再等,有多少数据发送多少(当然要考虑窗口大小和MTU),如果很极端地等待更多的数据,那么响应度会更低,换句话简单的说Nagle算法只允许一个未被ack的包存在于网络,它并不管包的大小,因此它事实上就是一个扩展的停-等协议,只不过它是基于包停-等的,而不是基于字节停-等的。
可以看出,Nagle算法完全由tcp协议的ack机制决定,这会带来一些问题,比如如果对端ack回复很快的话,Nagle事实上不会拼接太多的数据包,虽然避免了网络拥塞,网络总体的利用率依然很低,Nagle真的做到了“只做好一件事”的原则,然而有没有另外一种算法,可以提高整体网络利用率呢?也就是说尽量以不能再多的数据发送,这里之所以说是尽量还是权衡导致的,某时可以发送数据的时候将会发送数据,即使当前数据再小也不再等待后续的可能拼接成更大包的数据的到来。
实际上,这样的需求可以用TCP_CORK来实现,但是实现得可能并不像你想象的那么完美,cork并不会将连接完全塞住。内核其实并不知道应用层到底什么时候会发送第二批数据用于和第一批数据拼接以达到MTU的大小,因此内核会给出一个时间限制,在该时间内没有拼接成一个大包(努力接近MTU)的话,内核就会无条件发送,这里给出的只是一个大致的思想,真实的情况还要受到窗口大小以及拥塞情况的影响,因此tcp“何时发送数据”这个问题非常复杂。
Nagle算法和CORK算法非常类似,但是它们的着眼点不一样,Nagle算法主要避免网络因为太多的小包(协议头的比例非常之大)而拥塞,而CORK算法则是为了提高网络的利用率,使得总体上协议头占用的比例尽可能的小。如此看来这二者在避免发送小包上是一致的,在用户控制的层面上,Nagle算法完全不受用户socket的控制,你只能简单的设置TCP_NODELAY而禁用它,CORK算法同样也是通过设置或者清除TCP_cork使能或者禁用之,然而Nagle算法关心的是网络拥塞问题,只要所有的ack回来则发包,而CORK算法却可以关心内容,在前后数据包发送间隔很短的前提下(很重要,否则内核会帮你将分散的包发出),即使你是分散发送多个小数据包,你也可以通过使能CORK算法将这些内容拼接在一个包内,如果此时用Nagle算法的话,则可能做不到这一点。