Node.JS: How to create a HTTP Chat Server?

你说的曾经没有我的故事 提交于 2019-12-20 10:43:58

问题


With the Net Stream Object with TCP works great (as presetend in the node.js introduction video), but how should I do this in HTTP?

Is there a way to access sockets/clients within an http.createServer() ? Or what's the method to do it? I tried to figure out the solution from the official node chat demos souce code, but I don' really understand.

I understand the client side js, but what's happening after I(as a client) send a message trough AJAX, to the server side js? How can I send to the other clients who's on the server too?

Please note that I wan't to learn the logic of the process, so I don't want to use socket.io or any other frameworks, libraries, modules.

Thanks very much for any help!


回答1:


Ideally you just use WebSockets but the alternative is ajax long polling.

You can use a technique known as long polling to do the chat. This means you make an (ajax) request to the server and the server keeps hold of this request until it has some data left to send.

So the clients ends up periodically polling the server, if the server has no new messsages, it just keeps hold of your request. If it has a message it sends it back to the client and the client will poll the server again.

[[Pseudo Code]]

// 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);

A better push technology would be Server-side events. See an example of it here. This does require browser support though (Chrome and opera I think).




回答2:


One way of doing it involves clients "subscribing" to a channel that acts as a distributor for messages. Once subscribed, a client then receives a copy of each message sent to the channel.

Many node chat services rely on redis' pubsub feature to handle this distribution of messages from one to any number of clients. If you wanted to "roll your own", understanding how redis solves this problem would be a great start.




回答3:


If you want to know the basic principles of long polling then try to look at this article. I summarized there certain parts of my own long poll server, how I implemented them and the article also contains links to other resources. It should give you at least the bigger picture of how long polling works.

If you want to learn the logic in order to have some coding fun with node.js, and not to use existing solutions, then I would recommend to go step by step from the most simple and basic implementation to more complex stuff. Don't try to build the entire thing from the first shot because it's one of the most surest way how to fail.



来源:https://stackoverflow.com/questions/6052181/node-js-how-to-create-a-http-chat-server

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!