2017-01-07 12 views
1

Я транслирую HTML 5 видео с помощью Express с помощью fs.createReadStream(path).pipe(res);, что в конечном итоге вызывает ошибку Error: EMFILE: too many open files, если я обновляю страницу слишком много раз (в тысячах). Я предполагаю, что мне нужно выполнить какую-то очистку и закрыть файл, чтобы предотвратить это, но я не уверен, что нужно сделать.Закрыть поток по окончании

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

Соответствующая часть функции тока:

fs.stat(path, function(err, stats) { 
    var size = stats.size; 
    var range = req.headers.range; 

    if (range) { 
    var parts = range.replace(/bytes=/, '').split('-'); 
    var start = parseInt(parts[0]); 
    var end = parts[1] ? parseInt(parts[1]) : size - 1; 
    var chunksize = (end - start) + 1; 

    res.writeHead(206, { 
     'Content-Range': 'bytes ' + start + '-' + end + '/' + size, 
     'Accept-Ranges': 'bytes', 
     'Content-Length': chunksize, 
     'Content-Type': 'video/mp4' 
    }); 

    fs.createReadStream(path, {start: start, end: end}).pipe(res); 
    } else { 
    res.writeHead(200, { 
     'Content-Length': size, 
     'Accept-Ranges': 'bytes', 
     'Content-Type': 'video/mp4' 
    }); 

    fs.createReadStream(path).pipe(res); 
    } 
}); 
+0

, что ОС вы работаете на? Mac? Linux? etc ... –

+0

@PhilPoore Windows, неуверенный, если это происходит в другой ОС. – user2248702

ответ

0

На Linux/Unix EMFILE вопросов решаются ulimit. Я не уверен в окнах. Google Windows ulimit EMFILE получает этого Stack Overflow

https://stackoverflow.com/a/729204/683017

Сво говоря 2048 дескрипторов файлов на процесс является ограничением на Windows. Это соответствует тому, что Ваше высказывание

«в тысячах»

Если 2048 является фирма предел, и я не уверен, что это, (вы должны Google вокруг узнайте больше о своей конкретной ОС).

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

+0

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

+0

В unix, и предположим, что он похож на окна. Файловые дескрипторы очищаются ОС по своему усмотрению. Дескрипторы файлов имеют минимальный тайм-аут, чтобы снова и снова открывать один и тот же файл ... говорят, что каждый из них остается открытым не менее 30-60 секунд. Поэтому, если вы используете 2048 через минуту, вы исчерпаете и получите сообщение об ошибке. Эта ошибка возникает при бенчмаркинге, но необычна для повседневного использования. Если это так, предполагает, что что-то требует переустановки для преодоления предела 2048 года. –

+0

Я внимательно рассмотрел открытые файлы, и кажется, что я могу открыть один и тот же файл сотни раз, многократно перекачивая его (что произойдет через несколько минут поиска по видео HTML 5). – user2248702

0

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

Чтобы исправить это, вы должны слушать близкого события ответа и уничтожить поток:

res.on('close', function() { 
    stream.destroy(); 
}); 

Иногда близкий обработчик никогда не вызывается, даже когда он помещается на первой строке в запросе функция. Довольно Hacky способ я нашел, чтобы исправить это, чтобы проверить, если сокет разрушается до создания потока:

if (req.socket.destroyed) { 
    return; 
} 

Неподвижная функция потока:

fs.stat(path, function(err, stats) { 
    if (req.socket.destroyed) { 
    return; 
    } 

    var stream; 
    var size = stats.size; 
    var range = req.headers.range; 

    if (range) { 
    var parts = range.replace(/bytes=/, '').split('-'); 
    var start = parseInt(parts[0]); 
    var end = parts[1] ? parseInt(parts[1]) : size - 1; 
    var chunksize = (end - start) + 1; 

    res.writeHead(206, { 
     'Content-Range': 'bytes ' + start + '-' + end + '/' + size, 
     'Accept-Ranges': 'bytes', 
     'Content-Length': chunksize, 
     'Content-Type': 'video/mp4' 
    }); 

    stream = fs.createReadStream(path, {start: start, end: end}); 
    } else { 
    res.writeHead(200, { 
     'Content-Length': size, 
     'Accept-Ranges': 'bytes', 
     'Content-Type': 'video/mp4' 
    }); 

    stream = fs.createReadStream(path); 
    } 

    stream.pipe(res); 

    res.on('close', function() { 
    stream.destroy(); 
    }); 
});