2015-04-05 5 views
0

Я пытаюсь создать узел-сервер, который будет уведомлять клиентов с большим количеством запросов, когда файл обновляется на сервере. Тем не менее, я не могу придумать код, чтобы сервер распознал изменение в файле и обновил любой клиент опроса, который было выполнено.обработка многопользовательского большого опроса с помощью узла

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

Итак, я думаю, что сервер получает запрос и сразу же сохраняет временную метку целевого файла. Затем каждые 10 секунд сервер проверяет сохраненную метку времени на отметку времени файла в текущее время. Если есть разница, файл был обновлен, и сервер отправляет ответ клиенту, который указывает, что файл был изменен. Если сервер не видит изменения в файле после, скажем, 60 секунд, он отправляет ответ клиенту, чтобы указать, что клиент должен инициировать новый запрос.

Имеет ли смысл стратегия выше? Как эффективно обрабатывать материал временной метки? И как вы обрабатываете несколько клиентов одновременно? И как предотвращается переполнение сервера несколькими запросами одного и того же клиента?

ответ

1

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

Один из способов позаботиться об этом будет для клиента в первом запросе текущий статус файла:

GET /file/timestamp 
    -> Server returns the timestamp 

GET /file/update?after=[timestamp] 
    -> Server checks whether the file has changed after the timestamp. 
     If it has, the server sends the response immediately. 
     Otherwise insert the client into a queue. 
     You don't need to save the timestamp in the queue. 
     If the server notices a change it notifies the clients. 

Теперь из-за нескольких клиентов сервер не должен делать опрос в обработчике запроса клиента. Вместо этого есть отдельный объект, который обрабатывает опрос.

В зависимости от того, есть ли у вас один или несколько файлов, которые необходимо просмотреть, для этого вам может понадобиться простая или сложная реализация. Короче, хотя вы, вероятно, захотите обернуть fs.watchFile в EventEmitter, чтобы изменения в файле выдавали change -events.

Наивный реализация будет:

var watcher = new EventEmitter(); 

// Get the initial status 
fs.lstat('test.file', function(err, stat) { 
    if(err) return console.error(err); 
    watcher.stat = stat; 
}); 

// Start watching the file and emit an event whenever the file changes. 
fs.watchFile('test.file', function(curr, prev) { 
    console.log('File changed'); 
    watcher.stat = curr; 
    watcher.emit('change', curr); 
}); 

С этим вместо обработчик запроса будет выглядеть как-то вдоль линий:

var server = http.createServer(function(req, res) { 

    res.writeHead(200, { 'Content-Type': 'text/html' }); 

    var timeout; 
    var onChange = function(stat) { 
     // Prevent timeout from triggering 
     clearTimeout(timeout); 

     console.log('File changed at ' + stat.mtime); 
     res.end(
      'Changed at ' + stat.mtime + '. ' + 
      '<a href="?after=' + stat.mtime.getTime() + '">Poll again</a>'); 
    }; 

    var after = url.parse(req.url).query || ''; 
    after = after.split('='); 
    console.dir(after); 
    if(after.length < 2 || after[1] < watcher.stat.mtime.getTime()) { 
     console.log('Initial request or file changed before request'); 
     return onChange(watcher.stat); 
    } 

    console.log('Polling request.'); 

    watcher.once('change', onChange); 
    timeout = setTimeout(function() { 
     console.log('File not changed. Giving up.'); 
     watcher.removeListener('change', onChange); 
     res.end(
      'Unchanged! <a href="?after=' + after[1] + '">Poll again</a>'); 
    }, 10000); 
}); 

И, наконец, «предотвратить сервер от переполнения по нескольким запросам от одного и того же клиента? " - Нет. Нет, если вы хотите гарантировать это и по-прежнему разрешать анонимные запросы. Вы можете попробовать исключение на основе cookie, но если ваша служба разрешает анонимные запросы, пользователи могут просто прекратить отправку файлов cookie, в этот момент становится очень сложно идентифицировать запросы из того же браузера.

+0

Подход eventEmitter действительно работает хорошо! На клиенте я начал использовать sessionStorage для записи временной метки, возвращенной с сервера (может быть, это не лучший способ?). Когда сервер отправляет новую временную метку в JSON, клиент хранит ее в sessionStorage, а затем оборачивается и делает запрос с этим значением в качестве аргумента «после». Я пробовал его, по крайней мере, с двумя клиентами до сих пор, и, похоже, он отлично работает! Следующим шагом будет просмотр нескольких файлов; очень интересно узнать, как вы можете подходить к этой проблеме? – mlehmeher

+0

Я все равно останусь одним наблюдателем. Просто укажите путь к файлу в событии как параметр. И если есть ограниченное количество разных файлов, которые вы знаете заранее, я бы поставил в очередь эти fs.watchFiles при запуске сервера. Однако, если у вас много разных файлов, клиенты могут смотреть в случайном порядке, я бы обернул все это аккуратным классом, который отслеживает «открытых» наблюдателей и отключает файлы, когда их никто не интересует. –

+0

Итак, этот проект получился довольно приятным благодаря вашему первоначальному вводу. Теперь мой сервер обрабатывает многопользовательские клиенты, которые могут просматривать несколько файлов. Клиент запрашивает файл для просмотра. Очередь поддерживается, которая отслеживает назначенные сервером идентификаторы GUID для каждого запроса клиента. Все это завершено в класс отличный класс по вашему предложению. Все события в классе наблюдателя используют EventEmitter, поэтому нет никакого уродливого разворота обратного вызова. Спасибо за помощь! – mlehmeher

Смежные вопросы