Node.js UDP 实现实时多人游戏

14
我正在使用node.js构建一个实时多人浏览器游戏。目前,我让客户端通过socket.io将用户输入发送到游戏逻辑服务器,并将游戏世界的快照发送回客户端进行渲染。
以下是代码的简化版本。是否可能使用UDP从基于浏览器的客户端发送数据到服务器,反之亦然?我知道Node.js有一个UDP模块,但我不确定如何以这种方式实现。
任何帮助都将不胜感激。谢谢。
服务器:
var server = http.createServer(handler).listen(8888);
var iosocket = io.listen(server);

// request/response handler
function handler(req, res){

    ...
}

iosocket.sockets.on('connection', function(socket){
    console.log("[x] Socket listener started");

    socket.on('msg', function(data){
        console.log( " [-] incoming message);
    });
});

...

iosocket.sockets.emit("message", msg);

客户端:

<!DOCTYPE html>
<html>
    <head>
        <title>Test</title>
        <script type="text/javascript" src="/socket.io/socket.io.js"></script>
        <script type="text/javascript">
            socket.on('connect', function(){
             console.log("connected to server");
            });

            socket.on('message', function(message){
            console.log('received message');
            });

        </script>
    </head>

    <body>
        <canvas id='canvas' width="400" height="400">Canvas</canvas>
    </body>

</html>

你做不到。浏览器只支持HTTP。其中一些还支持WebSockets(其他可以使用Flash XMLSocket模拟WebSockets)。就是这样。顺便问一下:为什么要使用UDP?使用TCP(即WebSockets)更可靠。 - freakish
@freakish 我之前看了各种有关 UDP vs TCP 的文章,所以追求的是速度而不是可靠性...我猜他们没有谈到基于浏览器的游戏,对吧? - RobotEyes
嗯,这取决于你要开发什么类型的游戏。如果你想要在浏览器中制作另一款Quake游戏,那么也许你应该放弃这个想法。:) 另一方面,如果你不需要每秒制作大量的快照,则TCP协议就足够了。最后请注意,有些非常出色的游戏仍然使用TCP协议,例如:《魔兽世界》。 - freakish
@freakish 《魔兽世界》实际上很难被认为是一个实时游戏。如果你正在设计一个带有抛射物或移动碰撞箱的游戏,那么几乎肯定需要使用某种形式的UDP,同时混合使用TCP处理那些不太时间敏感的事情。如果你要制作一款攻击基于面向方向、按下按键并等待一秒钟的游戏(像《魔兽世界》),那么TCP可能就足够了。 - Spencer
3个回答

24

通常,浏览器不支持UDP连接。但有一些浏览器支持UDP,例如Google Chrome拥有一个套接字API:

http://developer.chrome.com/trunk/apps/socket.html

[2012/10/29 更新:套接字不再是实验性的 - PhilH]

你也可以尝试使用本地客户端接口中的套接字API(我不确定,这只是猜测)。

如果你想在浏览器上进行任何实时操作,Websockets可能是最好的选择,但它们仅支持TCP。

关于您对UDP和TCP速度的评论,UDP始终会更快。 TCP提供排序和传递保证(这意味着可能需要重试,并一直保留其他数据包,直到丢失的数据包最终到达其目的地),而UDP仅承诺发送一次,然后不关心其后果。 UDP仅会发送其数据包一次,您需要确定是否有数据包丢失。当/如果您收到大量的UDP数据包时,如果顺序很重要,您需要将其编码到数据负载中以便能够找出。

总的来说,UDP对于那些少数数据包丢失无关紧要而且仅有最新数据包真正重要的情况非常适用。游戏通常会使用TCP流,其中排序和保证传递很重要(即重要的东西),以及UDP流用于对象移动等(仅最新位置真正重要,如果一个更新丢失了,只要每个包都包含完整位置[而不是增量,所有包都很重要])。

对于您自己的游戏,我建议您首先在TCP上实现它,然后当您有更多经验时,可以尝试将时间关键的内容(其中顺序和丢失数据包的重要性较小)移入单独的UDP流中。许多项目失败的原因是人们首先使用UDP,然后试图在其上添加排序和传递保证,从而实际上是在尝试重新实现TCP。这就是为什么采用另一种方式更有意义的原因。


3
一般来说是个好回答,但需要注意的是TCP并不是建立在UDP之上:它们都是建立在IP数据报之上。UDP除了端口号以外,几乎没有添加任何其他内容。这个区别很重要,因为TCP端口和UDP端口处于不同的编号空间。例如,TCP的80端口与UDP的80端口完全不同且没有关联。 - Seth Noble
@SethNoble和Marius。如果我以每秒20次的速率从服务器向客户端发送游戏世界快照,TCP会在客户端端口引起问题吗?像实体插值、客户端预测和延迟补偿这样的技术是否适用于TCP,就像它们适用于UDP一样?谢谢。 - RobotEyes
Yoshima,这取决于许多因素,例如发送方和接收方之间的带宽和延迟。除非您在局域网上,否则需要将视图更新帧速率与“网络帧速率”分离。高级技术将尝试检测和适应任何条件(减少更新以适应带宽和延迟)。 - Marius Kjeldahl
除了Marius所说的,还要记住,如果由于数据包重传或流量控制而导致TCP延迟,所有延迟的消息都会堆积起来并一次性传递。因此,您可能需要一种机制来“赶上”并丢弃过时的信息。这甚至适用于UDP,但在TCP中更为明显。 - Seth Noble
除非是回合制RPG,否则不要使用TCP进行网络游戏。即使是这样,也要重新考虑。 http://gafferongames.com/networking-for-game-programmers/udp-vs-tcp/ - Spencer

1
实时应用通常是指至少每秒接收30次数据更新,并且抖动不超过10%的应用程序。TCP / IP是可靠的,但无法在不偶尔引起抖动的情况下以该速率发送周期性更新。这是因为TCP正在握手和确认以确保可靠传输,这妨碍了快速定期平滑更新的发送。UDP是一种更简单的协议,其中套接字数据是“发射并忘记”。这本身就是一个问题,但是这个问题比TCP / IP的差劲抖动更容易克服。根据我的经验,UDP是前进的唯一途径,也是实时应用程序在VoIP中使用的RTP等协议内部使用它的原因。
Web Sockets也是虚假的希望,因为那是基于TCP的协议。我使用自定义UDP套接字,其中发送方和接收方维护序列号,可以告诉您数据包是否丢失,重复或顺序错误,这些都是WAN网络上的问题。找到使用UDP的方法并检测入站数据包以测量性能。

-6
var server = require('http').createServer();

require('dgram-browserify').listen(server);

server.listen(8080);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接