2011-05-18 67 views
9

随着网络流对象与TCP工程伟大(作为node.js introduction video presetend),但我应该怎么做到这一点在HTTP?Node.JS:如何创建HTTP聊天服务器?

有没有办法访问http.createServer()内的套接字/客户端?或者有什么办法做到这一点?我试图找出从官方node chat demossouce code解决方案,但我不明白。

我明白客户端js,但是我(作为客户端)通过AJAX发送消息到服务器端js后发生了什么?我怎样才能发送给服务器上的其他客户呢?

请注意,我不想学习过程的逻辑,所以我不想使用socket.io或任何其他框架,库,模块。

非常感谢您的帮助!

回答

2

这样做的一种方式涉及客户端“订阅”一个充当消息分发者的渠道。一旦订阅,客户端就会收到发送给该频道的每条消息的副本。

许多节点聊天服务都依赖于redis的pubsub功能来处理从一个到多个客户端的这种消息分布。如果你想“推出自己的产品”,了解Redis如何解决这个问题将是一个很好的开始。

+1

但问题是如何将消息发送到客户端?感谢redis,这看起来很有趣,但是并不涉及'node.js' :),但作为一个PHP程序员,这看起来很有趣 – Adam 2011-05-18 23:34:42

+0

简而言之,一旦客户端订阅了服务,就会创建一个队列来包含其他客户发送的任何消息。当一个客户端发送一条消息时,它将被添加到每个其他订阅者的队列中。然后,客户端请求任何已添加到其自己队列中的待处理消息。 – 2011-05-18 23:40:06

+2

Websockets(HTML5的一个特性)允许客户端打开双向套接字到服务器可以用来将消息“推送”到客户端的Web服务器。在没有此功能的情况下,客户端会通过AJAX调查服务器是否有任何未决消息。服务器不会推消息,因为(没有websockets)它没有本地设施这样做。这就是为什么socket.io非常有用。如果客户端支持websocket,则使用它们。如果不是,它会尝试一些其他方法回到长轮询。 – 2011-05-18 23:42:53

10

理想情况下,您只需使用WebSockets,但替代选择是ajax长轮询。

您可以使用称为长轮询的技术来进行聊天。这意味着你向服务器发出一个(ajax)请求,并且服务器保持这个请求,直到它有一些数据要发送。

因此,客户端定期轮询服务器,如果服务器没有新的消息,它只是保持您的请求。如果它有一条消息,它会将其发送回客户端,客户端将再次轮询服务器。

[伪代码]

// Client.js

var Socket = function(ip, port, name) { 
    this.ip = ip; 
    this.port = port; 
    this.name = name; 
    this._cbs = []; 
    this._poll(); 
}; 

// Call the server periodically for data. 
Socket.prototype._poll = function() { 
    var that = this; 
    // if the server does not return then call it again 
    var timer = setTimeout(function() { 
     this._poll(); 
    }, 5000); 
    $.ajax({ 
     type: "GET", 
     timeout: 5000, 
     data: { 
      name: this.name 
     }, 
     url: this.ip + ":" + this.port, 
     success: function(data) { 
      // server returned, kill the timer. 
      clearTimeout(timer); 
      // send the message to the callback. 
      for (var i = 0; i < that._cbs.length; i++) { 
       that._cbs[i](data); 
      } 
      // call the server again 
      that._poll(); 
     } 
    }); 
}; 

// Add a callback for a message event 
Socket.prototype.on = function(event, cb) { 
    if (event === "message") { 
     this._cbs.push(cb); 
    } 
}; 

// Send a message to the server 
Socket.prototype.send = function(message) { 
    $.ajax({ 
     data: { 
       message: message, 
       name: this.name 
     }, 
     type: "GET", 
     url: this.ip + ":" + this.port 
    }); 
}; 

var socket = new Socket('192.168.1.1', '8081', "Raynos"); 
socket.on("message", function(data) { 
    console.log(data); 
}); 
socket.send("Hello world!"); 

// server.js

var url = require("url"); 
var events = require("events"); 
// store messages for clients 
var clients = {}; 

var emitter = new events.EventEmitter(); 

http.createServer(function(req, res) { 
    // get query string data 
    var data = url.parse(req.url, true).query; 
    // if client is not initialized then initialize it. 
    if (data.name && !clients[data.name]) { 
     clients[data.name] = []; 
    } 
    // if you posted a message then add it to all arrays 
    if (data.message) { 
     for (var k in clients) { 
       clients[k].push(data.name + " : " + data.message); 
     } 
     // tell long pollers to flush new data. 
     emitter.emit("new-data"); 
    } else if (clients[data.name].length > 0) { 
     // else empty the clients array down the stream 
     for (var i = 0; i < clients[data.name].length; i++) { 
       res.write(clients[data.name].shift()); 
     }; 
     res.end(); 
    // long polling magic. 
    } else { 
     var cb = function() { 
       for (var i = 0; i < clients[data.name].length; i++) { 
        res.write(clients[data.name].shift()); 
       }; 
       res.end(); 
       // kill that timer for the response timing out. 
       clearTimeout(timer); 
     } 
     // when we get data flush it to client 
     emitter.once("new-data", cb); 
     var timer = setTimeout(function() { 
       // too long has passed so remove listener and end response. 
       emitter.removeListener(cb); 
       res.end(); 
     }, 4500); 
    } 
}).listen(8081); 

更好的推送技术将Server-side events。请参阅example of it here。这确实需要浏览器支持,尽管(我认为是Chrome和Opera)。

+1

第一个WoW,非常感谢!这是一个可行的方法,但长时间轮询对于大量客户端来说具有性能问题,所以彗星服务器将是一个很好的解决方案,但我不知道如何使用node.js实现它,查看http ://www.ape-project.org/ajax-push.html它类似于我想要的但它不是节点:) – Adam 2011-05-19 00:03:41

+1

@CIRK如果你想要类似于APE的东西,然后安装socket.io。如果您想从头开始编写,请阅读socket.io源文件。对于记录我不知道如何实现服务器推在节点:( – Raynos 2011-05-19 00:04:31

+0

我不想APE也不socket.io:P,我想知道他们是如何工作的,看着socket.io的来源对我来说是邪恶的: O,因为我不知道它的逻辑:S – Adam 2011-05-19 00:06:05

0

如果你想知道长轮询的基本原则,然后尝试看看this article。我总结了我自己的长轮询服务器的某些部分,我如何实现它们,文章还包含指向其他资源的链接。它至少应该给你更多关于投票工作时间的更多信息。

如果你想要学习逻辑以便为Node.js编写一些编程乐趣,而不是使用现有的解决方案,那么我会推荐从最简单和基本的实现一步步到更复杂的东西。不要试图从第一枪开始构建整个事情,因为它是如何失败的最可靠方法之一。