Node.JS: Как создать HTTP-чат-сервер? - PullRequest
9 голосов
/ 19 мая 2011

С Net Stream Object с TCP прекрасно работает (как это предисловие во вводном видео node.js ), но как мне это сделать в HTTP?

Есть ли способ получить доступ к сокетам / клиентам в http.createServer()? Или какой способ сделать это? Я пытался найти решение из официальных демонстраций чата узла souce code , но я не совсем понимаю.

Я понимаю, что на стороне клиента js, но что происходит после того, как я (как клиент) отправляю сообщение через JJ на стороне сервера? Как я могу отправить другим клиентам, которые тоже на сервере?

Обратите внимание, что я не хочу изучать логику процесса, поэтому я не хочу использовать socket.io или любые другие фреймворки, библиотеки, модули.

Большое спасибо за любую помощь!

Ответы [ 3 ]

10 голосов
/ 19 мая 2011

В идеале вы просто используете WebSockets, но альтернативой является опрос ajax long.

Вы можете использовать технику, известную как длинный опрос, чтобы сделать чат. Это означает, что вы делаете (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);

Лучшей технологией push будет События на стороне сервера . См. пример этого здесь . Это требует поддержки браузера (Chrome и Opera, я думаю).

2 голосов
/ 19 мая 2011

Один из способов заключается в том, что клиенты «подписываются» на канал, который выступает в роли распространителя сообщений.После подписки клиент получает копию каждого сообщения, отправляемого на канал.

Многие службы чата узла используют функцию pubisub в redis для обработки такого распределения сообщений от одного к любому числу клиентов.Если бы вы хотели «покататься», то хорошее понимание того, как Redis решает эту проблему, было бы отличным началом.

0 голосов
/ 19 мая 2011

Если вы хотите знать основные принципы длительного опроса, попробуйте взглянуть на эту статью .Я кратко описал некоторые части моего собственного длинного сервера опросов, как я их реализовал, и статья также содержит ссылки на другие ресурсы.Это должно дать вам, по крайней мере, более полную картину того, как долго работает опрос.

Если вы хотите изучить логику для того, чтобы немного поиграться с node.js, а не использовать существующие решения, то я быРекомендую пошагово перейти от самой простой и базовой реализации к более сложным вещам.Не пытайтесь построить все это с первого раза, потому что это один из самых надежных способов потерпеть неудачу.

...