PHP Event Source продолжает выполняться

Я начал использовать push в HTML5, используя объект JavaScript EventSource. Я был полностью доволен рабочим решением на PHP:

$time = 0;
while(true) {
    if(connection_status() != CONNECTION_NORMAL) {
        mysql_close()
        break;
    }
    $result = mysql_query("SELECT `id` FROM `table` WHERE UNIX_TIMESTAMP(`lastUpdate`) > '".$time."'");
    while($row = mysql_fetch_array($result)) {
        echo "data:".$row["id"].PHP_EOL;
        echo PHP_EOL;
        ob_flush();
        flush();
    }
    $time = time();
    sleep(1);
}

Но вдруг мой WebApp не былбольше не достижим с ошибкой MySQL "слишком много подключений".

Оказалось, что соединение MySQL неt закрыть после закрытия источника события в JavaScript:

window.onload = function() {
    sse = new EventSource("push.php");
    sse.onmessage = function(event) {
        console.log(event.data.split(":")[1]);
    }
}
window.onbeforeunload = function() {
    sse.close();
}

Поэтому я предполагаю, что скрипт PHP не останавливается для выполнения. Есть ли способ вызвать функцию (например,die();) до того, как соединение с клиентом разрывается? Почему нетмой сценарий завершается после вызова.close(); на EventSource ?!

Спасибо за помощь! -

 Julian F. Weinert16 окт. 2012 г., 19:08
Вид. Каждый сеанс клиента получил этоs MySQL соединение. Соединение начинается до бесконечного цикла.реальный проблема в том, что зоветEventSource.close() не закрывает и не прерывает само соединение!
 topr16 окт. 2012 г., 18:38
Кажется, что каждый сеанс клиента запускает новый бесконечный цикл на стороне сервера со своим собственным соединением mysql, нене так ли? Я не вижу начала соединения на примере, который вы опубликовали, поэтому яЯ не уверен. Во всяком случае, этопочемуслишком много подключений" появляется ошибка Служба на стороне сервера, которая обслуживает данные, может использовать (совместно использовать) одно соединение с БД (и один бесконечный цикл). Я'я не публикую это как ответ, потому что у меня нету меня есть пример. Haven»Я использую PHP уже пару лет. Хотя я вижу на php.net mysql_query немного устарел. Вместо этого они советуют использовать MySQLi или PDO_MySQL.
 topr17 окт. 2012 г., 14:26
Как я понимаю, обслуживаемый контент через push.php одинаков для каждого клиента, не так ли?не так ли? Зачем тогда подключаться к базе данных и выполнять запросы для каждого сеанса клиента, а не делить одни и те же результаты SQL для всех сеансов клиента? Несмотря на этоБолее оптимальное решение поможет обойти вашу проблему.
 Julian F. Weinert18 окт. 2012 г., 12:18
Похоже, я должен попробовать это ... Мне нужен мой сценарий для передачи информации клиенту, когда другой клиент изменяет базу данных. Как я могу поделиться результатами для всех клиентов, не устанавливая соединение с БД для каждого клиента ?! Мне нужно немедленно нажать на информацию.
 topr18 окт. 2012 г., 14:06
Я не знаю точного ответа без дальнейших исследований. Я использовал PHP много лет назад. Но попробуйте искать такие вещи, какобласть применения ','Государственная служба а также 'Cron Job ' добавив ключевое слово PHP. Может быть, вы можете что-то склеить.

Ответы на вопрос(6)

$time = 0;
while(true) { 
    if(connection_status() != CONNECTION_NORMAL) {
        mysql_close()
        break;
    }
    $result = mysql_query("SELECT id FROM table WHERE UNIX_TIMESTAMP(lastUpdate) > '".$time."'");
    while($row = mysql_fetch_array($result)) {
        $rect[] = $row;
    }
    for($i-0;$i echo "data:".implode('',$disp)."\n\n"; $time = time(); sleep(1);
}
 madhu22 мар. 2014 г., 10:39
попробуй это сюрреально ты выигралвыполнение цикла ....................

Как отметил Элиас Ван Оотегем, ваш сценарий никогда не завершается, и, следовательно, у вас активна группа соединений MySQL. Более того, у вас есть куча ресурсов, используемых в виде циклов PHP, работающих без конца!

К сожалению, решение по сохранению не является "заголовки», В примере по этой ссылкессылка на Элиасасценарий php завершается, и клиентский javascript фактически должен заново открыть соединение. Вы можете проверить это, используя следующий код

source.addEventListener('open', function(e) {
  // Connection was opened.
    console.log("Opening new connection");
}, false);

Если вы последуете его примеру на github, в реализации автор фактически использует цикл, который завершается через X секунд.Смотрите цикл do и комментарии внизу скрипта.

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

Определяя предел цикла, IE X итерации или после X количество времени, чтобы инициировать конец цикла илиdie();, вы сделаете так, чтобы, если клиент отключился, было ограничение на то, как долго сценарий будет оставаться активным. Если клиент все еще остается там через X, он просто подключится заново.

Решение Вопроса

Во-первых: когда вы оборачиваете свой код в огромныйwhile(true) цикл, ваш сценарий никогда не закончится. Соединение с БД было бы закрыто, когда ваш скриптне хватило кода для выполнения, но так как тымы зашли в тупикне случится ... никогда.

Это'неEventSource вопрос, который просто делает то, что ондолжен делать. Это честно, верно, и, к сожалению, ваша вина.

Дело в том, что пользователь подключается к вашему сайту, аEventSource объект создан Соединение с сервером установлено, и запрос на возвращаемое значениеpush.php запрашивается Ваш сервер делает так, как запрошено, и запускает сценарий, что -again- это ничто иное, как тупик. Там нет ошибок, поэтому он может просто продолжать работать, пока php.ini позволяет ему работать..close() Метод отменяет поток вывода (или, скорее, должен), но ваш сценарий так занят, выполняя свой бесконечный цикл, или спит. Предполагать, что скрипт будет остановлен, потому что клиент отключается, все равно, чтолюбой клиент может вмешиваться в то, что делает сервер. С точки зрения безопасности это было бы наихудшим случаем. Теперь, чтобы ответить на ваш актуальный вопрос: что вызывает проблему, как ее исправить?

Ответ:HEADERS

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

Просто как примечание: пожалуйста, кюветmysql_* Как можно скореене рекомендуется (наконец), используйтеPDO или жеmysqli_* istead. Это'не так сложно, честно.

 Julian F. Weinert18 окт. 2012 г., 12:16
Я знаю ссылку. На какой абзац вы ссылаетесь? Мне нужен скрипт PHP, чтобы постоянно проверять мою базу данных. В моем PHP я записывал состояние соединения каждую секунду в текстовый файл. Когда я призываю.colse()статус НЕ меняется. К несчастью. Я могу't изменить заголовок в PHP, потому что скрипт должен работать непрерывно, пока клиент не отключится!while(connection_staus() == CONNECTION_NORMAL) {} тоже не работает ...
 Julian F. Weinert18 окт. 2012 г., 14:52
 Elias Van Ootegem18 окт. 2012 г., 13:57
@Julian: что такоеreadyState в обратном вызове ошибки? этоCLOSED? в этом случае: убедитесь, что вы нене иметьmysql_close или $ pdo = null; где-то в вашем PHP-коде, а такжепроверьте источник JS этого примераможет тамкакое-то вдохновение, чтобы получить оттуда
 Elias Van Ootegem17 окт. 2012 г., 00:11
@Julian: вызывая.close() действительно изменяет состояние соединения Вы можете установитьзаголовки запроса в JS (просто посмотрите на вызовы ajax:setRequestHeader), но я имел в виду PHPheader('some header');, Ты неЯ должен явно прекратить PHP-скрипт. Просто посмотрите на ссылку, которую я предоставил, она содержит больше деталей и дает достаточно четкие примеры того, как это работает
 Elias Van Ootegem18 окт. 2012 г., 14:37
@Julian: я только что кое-что понял: тыповторная очистка буферавнутри петли,EventSource ISN»t так же, как поток сокетов, вы должны либо вернуть весь вывод в один кусок или использовать веб-сокет для непрерывной передачи данных
 Julian F. Weinert16 окт. 2012 г., 19:20
Чтобы следовать вашим аргументам: вызов close (); Безразлично»t изменить состояние соединения, возвращаемоеconnection_status();? С каких это пор можно редактировать заголовки из JavaScript ?! Когда я прекращаю работу скрипта из PHP, новые данные никогда не будут переданы клиенту. При установке заголовка на "текст / событийно-поток» (как я) никогда бы не сказал mysql проверять наличие обновлений, верно?
 Julian F. Weinert18 окт. 2012 г., 14:07
ReadyState 2 (он жеCLOSED). Я нев моем коде не может быть mysql_close или что-то в этом роде. Я хотел реализовать это после цикла ... Я тоже знаю этот пример. Они ничем не отличаются от меня. Это'вид того же
 Julian F. Weinert18 окт. 2012 г., 13:41
Ну ... Это не работает. Я'я используютекст / событийно-поток» с тех пор, как я начал работать над толчком. Когда я удаляю цикл while, объект Event Source возвращаетon error Функция и закрывает соединение. Когда у меня нет цикла, скрипт завершает выполнение и завершается. Поток тогда закрыт. Заголовок швов, чтобы не 'не беспокойся. Вызов.close() все еще не меняет connection_status. Можно'не представляю почему ...
 Ulad Kasach22 янв. 2016 г., 05:27
@EliasVanOotegem, пример, на который вы ссылаетесь в своей ссылке, не поддерживается заголовками. Фактически, он фактически умирает, и клиент повторно открывает соединение через три секунды.
 Elias Van Ootegem18 окт. 2012 г., 12:20
@Julian: ну, естьПример PHP в ссылке, которую я разместил. Поскольку заголовки будут установлены вkeep-alive а такжеevent-stream заголовок соединение с вашей БД будет сохраняться до.close() метод вызывается ... Этос, правда. Ты неНе нужно никаких циклов, а не постоянных проверок. Его поведение сравнимо с node.js: отправка фрагментированных данных с сервера, у которого есть прослушиватели и который большую часть времени проводит в режиме ожидания ... Просто скопируйте и вставьте пример кода из ссылки (первый фрагмент под заголовком)Примеры серверов) и использовать это для проверки

1.

window.onbeforeunload = function() {
    sse.close();
}

это не требуется, EventSource будет закрыт во время выгрузки страницы.

даже если вы не можете найти способ обнаружить отключенный клиент на PHP, вы можете просто остановить выполнение через N секунд, EventSource автоматически восстановит соединение.

http://www.php.net/manual/ru/function.connection-aborted.php В комментариях на этой странице сказано, что вы должны использовать "промывать" в любом случае, перед connection_status вы должны сбросить соединение через N секунд, потому что вы не можете обнаружить "плохой" отсоединяется.

3. эхо "повторить: 1000"; // используем это, чтобы сообщить EventSource задержку переподключения в мс

 4esn0k21 окт. 2012 г., 05:21
а также? это нормально, чтобы получить эту ошибку, вы должны проверить readyState в обработчике ошибок, если это EventSource.CONNECTED - тогда ES попытается переподключиться
 Julian F. Weinert19 окт. 2012 г., 14:15
Спасибо, это своего рода обходной путь. Но это неЭто тоже кажется правильным, поскольку EventStream выдает ошибку, когда PHP Script останавливает выполнение.

У меня была точно такая же проблема, и насколько я понял, причина в том, что apache неНе завершайте php-скрипт, пока я не попытаюсь снова записать данные через соединение с закрытым сокетом.

Я не'В моей базе данных не было никаких изменений, поэтому не было выходных данных.

Чтобы это исправить, я просто отображаю комментарий источника события в цикле while:

echo ": heartbeat\n\n";
ob_flush();
flush();

Это приводит к завершению сценария, если соединение с сокетом закрыто.

 Marcel Gwerder23 мар. 2015 г., 18:36
Мне тоже нравится делать вещи идеально, я понимаю, что ты имеешь в виду. Возможность делать это с помощью php, как и все остальное в моем приложении, делает это намного проще. Если бы мне пришлось делать часть источника события с чем-то еще, яВозможно, я переключусь на WebSockets.
 Marcel Gwerder23 мар. 2015 г., 18:17
Зависит от того, как часто вы его отправляете. Ты нене нужно делать это на каждом цикле. Вы можете делать это каждые 15 минут или около того ... Важно то, что сценарий завершается, а не на самом деле, если он завершается немедленно.
 Julian F. Weinert23 мар. 2015 г., 17:05
Да, это будет работать Но это "массивная» накладные расходы в сравнении. Это не намного лучше, чем опрос постоянно ...
 Julian F. Weinert23 мар. 2015 г., 18:29
Согласитесь, вы абсолютно правы. Но я всегда стараюсь сделать все идеально;) Так что вы понимаете, почему это не так "вкус" так хорошо: D Но да, спасибо за ваше предложение, это определенно делает его выполнимым, даже если не идеальным. Я просто думаю, что PHPэто не то, что нужно сделать идеальным.

Вы можете попробовать добавить это в цикл:

if(connection_status() != CONNECTION_NORMAL)
{
    break;
}

но php должен остановиться, когда клиент отключился.

 Nathan27 дек. 2014 г., 07:11
Будет ли лучше (connection_aborted ()) проверить?
 Julian F. Weinert16 окт. 2012 г., 18:02
Я предполагал, что PHP тоже должен остановиться. Я попробовал ваше решение с оператором if, тогдаmysql_close(); затемbreak;, Это неТ помочь. Когда я иду к моему клиенту MySQL и печатаюSHOW PROCESSLIST мой пользователь WebApps все еще подключен. Каждый раз, когда я перезагружаю страницу, она подключается еще раз ... Может быть это'с JSEventSource.clos(); вопрос ???

Ваш ответ на вопрос