Node.js和Comet

7

基本上,我正在尝试从头开始使用node.js设置基本的comet服务器和客户端。我尝试谷歌关于它应该如何工作的过程的事情,当我测试时似乎运行良好。然而,仍有一个问题困扰着我。首先,我想向您展示代码。

var http = require('http');
var sys = require('sys');
var fs = require('fs');
var qs = require('querystring');

var server = http.createServer();

var connections = [];

server.on('request', function(req, res) {

    console.log(req.url);

    if(req.url == '/index') {

        fs.readFile(__dirname + '/index.html', function(err, data){
            if(err) {
                res.writeHead(err, data);
                return res.end('Error loading index.html');
            }

            res.writeHead(200);
            res.end(data);
        });
    } else if(req.url == '/sendData') {
        if (req.method == 'POST') {
            var body = '';
            req.on('data', function (data) {
                body += data;
            });
            req.on('end', function () {

                var POST = qs.parse(body);
                console.log(POST);
                res.writeHead(200);
                res.end("");
                broadcastData(POST);
            });
        }

    } else {
        connections.push(res);
    }
});

function broadcastData(data) {
    for(var i = 0; i < connections.length; i++) {
        connections[i].writeHead(200);
        connections[i].end(JSON.stringify({'message': data}));
    }
}

process.openStdin().addListener('data', function(chunk) {
    for(var i = 0; i < connections.length; i++) {
        connections[i].writeHead(200);
        var message = chunk.toString();
        connections[i].end(JSON.stringify({'message': {'name': message}}));
    }
});

server.listen(4000);

客户端:

function doComet() {
    $.getJSON('/', function(events){
        doComet();
        console.log(events);
        $('#content').append(events.message.name);
    });
}

function sendData(data) {
    $.ajax({
        type: "POST",
        url: "/sendData",
        contentType: 'application/javascript; charset=UTF-8',
        data: { name: "John", location: "Boston" }
    }).done(function( msg ) {
        console.log(msg)
    });
}

所以有一个监听器将 stdin 上我写的数据发送出去,客户端上也有一个按钮,可以将数据发送到服务器,然后服务器会将其发送给所有客户端。
我的问题是如果在短时间内发生了很多事件怎么办?我的意思是一旦从服务器得到响应,就会发送另一个 ajax 请求,但是在客户端尚未连接时应该有一个短暂的时间间隔,如果在那段时间内发生了什么,客户端将无法获得最新的数据。
所以我的想法对吗?在这种情况下,我应该如何正确地同步数据,以确保每个人都能获得它。有人知道如何正确地做吗?
谢谢你的帮助!

为什么要自己实现comet?你应该使用其中一个处理它的许多库,例如http://socket.io/。 - generalhenry
3
我为什么要这么做?在没有任何知识的情况下使用这些东西之前,我对它们的运作方式很感兴趣。 - stomseven
我已经稍微清理了你的代码:http://runnable.com/UWhebgy1CIBlAACd,还在考虑洪水问题。 - generalhenry
1个回答

16

Comet是一个包括所有旧的基于HTTP的技巧的总称,我们希望摆脱这个短语。WebSockets是我们想要的东西;从浏览器到其他领域。因此,如果您有兴趣构建实时解决方案,那么您应该先调查WebSockets,然后处理回退,例如HTTP流和HTTP长轮询。有关更多信息,请参见实时Web技术传输机制

您提供的示例将被归类为HTTP长轮询。

如果在很短的时间内发生了很多事件怎么办?我的意思是,一旦从服务器获得响应,另一个ajax请求就会被发送,但是可能存在一个短时间段,在该时间段内客户端尚未连接,并且如果在该时间段内发生了某些情况,则客户端将没有最新数据

这是HTTP长轮询的限制之一,也是为什么HTTP流是更好的解决方案,而WebSockets更好 - 连接在发送数据时不会关闭。使用任何类型的轮询解决方案时,您可能需要确保接收和发送的消息在轮询请求期间不会被轮询客户端错过。

有几个解决方案:

  1. 使用会话来跟踪上次向特定客户端发送的最后一条消息。当他们重新连接时,检查最后发送的消息,已丢失的消息并进行发送。
  2. 作为客户端轮询的一部分,发送一个lastMessageId。当服务器接收到此消息时,可以检查是否为最后一条消息。如果不是,则可以响应任何未收到的消息。
实时Web技术中的一个复杂性在于处理所有可能的连接方案。因此,如果您将其作为学习经验进行,则绝对是有益且有趣的。但如果您要创建一个应用程序并投入生产,则建议使用现有的实时框架。请参阅实时Web技术指南

谢谢您的回复。是的,我正在使用Websockets,但它需要时间才能得到广泛支持。这就是为什么我正在尝试找出如何以更兼容浏览器的方式进行操作。我想到了您所写的相同解决方案,但在实施之前,我想知道是否有更好的方法来完成它。 - stomseven
WebSockets非常广泛地得到支持。请参见http://caniuse.com/#feat=websockets,根据我在Pusher工作的经验,我认为支持率超过70%。但是,我们确实需要基于HTTP的备用方案来实现近乎100%的支持。我的回答是否解答了您的问题? - leggetter
@leggetter 如果您使用WebSockets并需要使用基于HTTP的回退来满足例如仍具有WebSocket限制的多平台应用程序,那么“Comet”这个术语是否仍然适用?此外,是否有人正在开发一个跟进这一点的库? - Shane
一些解决方案即使使用WebSocket仍然将自己归类为“Comet服务器”。老实说,这很棘手。我会说Comet是将所有HTTP黑客攻击组合在一起的术语。因此,多平台解决方案可以支持Comet(HTTP黑客攻击)回退和WebSocket。有许多解决方案支持HTTP和WebSocket传输。事实上,由于WebSocket无法工作的边缘情况,我通常只建议支持两者的解决方案。 - leggetter

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