游戏服务器协议,游戏服务器到底该选哪种⽹络协议?(1)在编写⽹络游戏的时候,到底使⽤UDP还是TCP的问题迟早都要⾯对。
⼀般来说你会听到⼈们这样说:“除⾮你正在写⼀个动作类游戏,否则你就⽤TCP吧” 或者是 “你能够在MMO游戏中⽤TCP,因为魔兽世界就⽤的TCP!”
遗憾的是,这些观点都没有反映这个问题的复杂性。
背景雪诗
中药大全
⾸先,说明⼀下,我之前主要是⽤TCP进⾏⽹络编程。我曾为⼀个流⾏的在线纸牌游戏编写服务器了好⼏年,在⾼峰期我们的每台服务器能够承受4000到10000个连接(同⼀台物理机器上有多个服务器进程在跑)都没有问题。在我来看,TCP是⼀种安全⽽且常见的选择。
尽管如此,我们最新的项⽬却是使⽤UDP协议,⽽且我们的项⽬⽆法通过任何⽅式在TCP下⼯作。事实上,项⽬⼀开始使⽤的TCP,但是后来发现我们使⽤TCP⽆法达到我们需求的连接数量时,我们只能换成UDP了。
在使⽤中TCP表现怎么样呢
从原理上,TCP的优势有:
简单直接的长连接
可靠的信息传输
数据包的⼤⼩没有限制
郭敬明 陈学冬任何⼀个和TCP打过交道的⼈都知道,要实现⼀个稳定的TCP⽹络连接,需要处理各种隐藏的坑,⽐如断线检测、慢速客户端响应阻塞数据包,对开放连接的各种dos攻击,阻塞和⾮阻塞IO模型等等。
除了上⾯列出的这些问题外,⼀个好的TCP模块确实不好编码实现。
但是,TCP最糟糕的特性是它对阻塞的控制。⼀般来说,TCP假定丢包是由于⽹络带宽不够造成的,所以发⽣这种情况的时候,TCP就会减少发包速度。
在3G或WiFi下,⼀个数据包丢失了,你希望的是⽴马重发这个数据包,然⽽TCP的阻塞机制却完全是采⽤相反的⽅式来处理!
⽽且没有任何办法能够绕过这个机制,因为这是TCP协议构建的基础。这就是为什么在3G或者WiFi环境下,ping值能够上升到1000多毫秒的原因。
张钧甯赵又廷为什么不⽤UDP
UDP相对TCP来说既简单⼜困难。
举个例⼦来说,UDP是基于数据包构建,这意味着在某些⽅⾯需要你完全颠覆在TCP下的观念。UDP只使⽤⼀个socket进⾏通信,不像TCP需要为每⼀个客户端建⽴⼀个socket连接。这些都是UDP⾮常不错的地⽅。
但是,⼤多数情况下你需要的仅仅是⼀些连接的概念罢了,⼀些基本的包序功能,以及所谓的连接可靠性。可惜的是,这些功能UDP都没有办法简单的提供给你,⽽你使⽤TCP却都可以免费得到。
这也是⼈们为什么经常推荐TCP的原因。在⽤TCP的时候你可以不考虑这些问题,直到你需要同步连接的数量级达到500以上的时候。
所以,是的,UDP没有提供所有的解决⽅法,但是就像你看到的那样,这也正是UDP好⽤的地⽅。在某种意义上来说,TCP对UDP就好⽐是Hibernate和⼿写SQL的区别。
使⽤TCP失败的地⽅
⼈们经常给你建议,让你去使⽤TCP,⽐如“TCP跟UDP⼀样快”或者“游戏X⽤TCP如此成功,所以TCP当然是⾸选”,然⽽,他们完全没有理解为什么在那个特定的游戏中TCP是有效的,为什么UDP不按照顺序发送数据包呢?
那么为什么魔兽世界采⽤TCP呢?⾸先我们需要解释这个问题。这个问题其实是“为什么魔兽世界有的时候1000毫秒以上的延迟还能够运⾏?”这是TCP的性质决定的,在发⽣丢包的时候,会产⽣巨⼤的延迟,因为TCP⾸先会去检测哪些包发⽣了丢失,然后重发所有丢失的包,直到他们都被接收到。
可靠的UDP也是有延迟的,但是由于它是在UDP的基础之上建⽴的通信协议,所以可以通过多种⽅式来减少延迟,不像TCP,所有的东西都要依赖于TCP协议本⾝⽽⽆法被更改。
就这⼀点来讲,⼀些⼈要开始提到Nagle算法了,实际上它是你在实现任意⼀个对延迟敏感的TCP模型时⾸先需要禁⽌使⽤的。
那么魔兽世界以及其他的⼀些游戏是怎么处理延迟问题的呢?
张曼玉年轻图片⽅法也很简单,他们能够隐藏掉延迟带来的影响。
茄子炖土豆在魔兽世界中,玩家和玩家是⽆法碰撞的:因为这类碰撞是⽆法通过⼀些预测来处理的,但是玩家和环境之间的碰撞却是可以通过预测来处理的,所以这⾥使⽤TCP是没有问题的。
我们来看⼀下魔兽世界的战⽃就会发现,玩家的攻击指令发送给服务器的操作是放在⽐如“attack_entity(entity_id)”或
者”cast_spell(entity_id, spell_id)“的接⼝中来做的,换句话说,瞄准操作是独⽴于进⾏的。如此⼀来,⼀些类似发起攻击动作和释放技能特效就能够在没有收到服务器确认的情况下就直接执⾏,⽐如展现冰冻技能的效果就可以在服务器没有返回数据前在客户端就做出来。
客户端直接开始进⾏计算⽽不等待服务端确认是⼀种典型的隐藏延迟的技术。
⼏年前,我为⼀个叫“Five Card Jazz”的纸牌游戏编写过客户端。它使⽤的是http协议,它⽐直接的TCP协议连接的延迟更加严重。
我们⽤简单的纸牌绘制和抽牌的动画来掩盖延迟的问题,所以延迟的问题只在⾮常糟糕的连接下才会被看出来。这种⽅法也⾮常的典型:发送请求的同时开始播放牌桌的动画,⼀直播放翻动最后⼀张牌直到接收到了服务端传回来的数据为⽌。魔兽世界的战⽃特效就是使⽤类似的原理。
这也意味着,我们到底是使⽤TCP还是UDP取决于我们能否隐藏延迟。