是用UDP还是TCP?

你好,

写网游的时候,迟早会面临用UDP还是TCP的问题。

一般来说,你会听到有人说“除非你在写动作游戏,否则你可以用TCP”或者“你可以在MMO游戏里用TCP,因为魔兽世界用TCP!”

不幸的是,这些观点都没有反映出这个问题的复杂性。

背景

首先说明一下,我主要是用TCP进行网络编程的。几年来,我一直在为一款流行的在线纸牌游戏编写服务器。在高峰期,我们的每台服务器都可以承受4,000到65,438+00,000个连接(同一台物理机上运行多个服务器进程)而不会出现任何问题。在我看来,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只使用一个套接字进行通信,不像TCP需要为每个客户端建立一个套接字连接。这些都是UDP非常好的地方。

但是,在大多数情况下,你需要的只是一些连接的概念,一些基本的包排序函数,以及所谓的连接可靠性。不幸的是,这些功能没有一个可以简单地通过UDP提供给你,但是你可以通过使用TCP免费获得它们。

这也是为什么人们经常推荐TCP的原因。使用TCP时,可以忽略这些问题,直到需要500个以上的同步连接。

所以,是的,UDP不能提供所有的解决方案,但是正如你所看到的,这就是UDP派上用场的地方。从某种意义上说,TCP到UDP就好比Hibernate和手写SQL的区别。

TCP失败的地方。

经常有人给你使用TCP的建议,比如“TCP和UDP一样快”或者“Game 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)”这样的接口中完成的,换句话说,瞄准操作是独立的。这样就可以直接执行一些类似发动攻击、释放技能的特效,而不需要收到服务器的确认。比如展示冻结技能的效果,可以在服务器返回数据之前,在客户端做出。

客户端不需要等待服务器的确认就直接开始计算,这是一种典型的隐藏延迟技术。

几年前,我为一个叫“五牌爵士”的纸牌游戏写了一个客户端。它使用http协议,比直接TCP连接有更严重的延迟。

我们