Простой скрипт длинного опроса PHP, слишком просто? - PullRequest
8 голосов
/ 02 сентября 2010

Я работаю над простым приложением чата, вероятно, от 10 до 20 пользователей на комнату.

Скрипт, который запрашивает в базе данных новые сообщения, выглядит слишком простым для всех запросов, которые он получит.

Ниже приведен блок кода, который зацикливается на новые сообщения, остальная часть сценария просто получает переменные, конструкцию запроса и объект ответа json:

$sleepTime = 1; //Seconds
$data = "";
$timeout = 0;

//Query database for data
while(!$data and $timeout < 10){
    $data = getQuery($sql);
    if(!$data){
        //No new messages on the chat
        flush();
        //Wait for new Messages
        sleep($sleepTime);          
        $timeout += 1;
    }else{
        break;
    }
}

Блок выше запроситбаза данных для новых сообщений каждую секунду в течение 10 секунд, если после 10 секунд нет новых сообщений, она уведомит об этом браузер.Браузер ждет 5 секунд и затем отправляет другой запрос для получения новых сообщений.

Однако, если скрипт находит новые сообщения, браузер немедленно запросит больше новых сообщений, как только он получит ответ с новыми сообщениями отсервер.

Этот процесс продолжается и продолжается ...

Так, как я могу оптимизировать этот процесс дальше?Это так хорошо, как это получается?Работает нормально на моем локальном сервере, но я боюсь, что только несколько пользователей могут перегрузить живой сервер (общий хост) со всеми запросами и циклами.

Вот живая демонстрация, которую вы можете проверить с помощью firebug http://pixbush.com/chat/chat.php

Ответы [ 4 ]

3 голосов
/ 27 октября 2010

По вашему описанию, похоже, что у вас есть 5-секундная пауза молчания, которая побеждает выгоду от длинных опросов. Сделайте так, чтобы браузер сразу же запустил другой запрос, когда звонок (длинный или короткий) возвращается с сервера. В качестве резервной копии при каждом вызове сервера браузер должен запускать тайм-аут немного дольше, чем тайм-аут на стороне сервера, но отменять его при возврате запроса. Если запрос к серверу завершится неудачно и истечет время ожидания браузера, запустите новый запрос.

2 голосов
/ 02 сентября 2010

Этот кричит для AJAX.

Смотрите мой пост сегодня на , как отправлять ответы JavaScript на PHP . Нет никаких причин, по которым ваш скрипт вообще должен был бы зацикливаться.


РЕДАКТИРОВАТЬ: Мое плохо об AJAX. Когда я писал чат-бот IRC PHP-Egg , я столкнулся с этой проблемой * 100. Способ, которым я решил ее (еще в PHP 4 дня), был pcntl_fork () PHP и просто возвращать каждый раз, когда было сообщение. Преимущество состоит в том, что он не блокирует процессор на 100%, в отличие от sleep (), и НАМНОГО быстрее, чем 10 секунд или любого произвольного ограничения, установленного вами.


Я снова пересматриваю свой ответ (извините!):

Использовать какой-то асинхронный процесс, который выводит текст в файл.

Тогда вы бы сделали

if (filemtime ('chat.log')> time () - 5) { echo json_encode (file_get_contents ('chat.log')); }

Преимущества: ограниченное использование SQL; не нужно зацикливаться.

1 голос
/ 23 ноября 2010

Я делал веб-чат и нашел то же самое решение для хранения обновлений в режиме реального времени. Итак, мне интересно, выяснили ли вы это: это хороший способ продолжать зацикливаться на стороне сервера, используя функцию sleep (), или, может быть, лучше вместо этого использовать больше запросов ajax. Является ли функция sleep () действительно хорошей идеей, и она не остановит сервер при опросе нескольких пользователей?

Я вижу, что meebo использует длинный опрос (время между запросами также зависит от фокуса окна, я полагаю), когда приложение SO chat. кажется, просто использует ajax-запросы. Так что это заставляет меня задуматься.

0 голосов
/ 02 сентября 2010

Вы можете попробовать использовать файлы, помеченные в соответствии с разговорным идентификатором вместо БД, и просто проверить, был ли файл «затронут». Также используйте usleep и set_time_limit (для сервера Windows), чтобы установить интервал в миллисекундах и увеличить время ожидания. На самом деле спит, задерживает загрузку процессора, но все равно срабатывает мгновенно, если файл был изменен.

Вот часть моего скрипта чата. =)

define('SUCCESS', '__SUCCESS__');
define('FAILED', '__FAILED__');

$tmpLib = $TMPFOLDER;
$msgPath = $MSGFILE;

$timeout = $POLLSPEEDSEC;

$acct = new Account($tmpLib, $_GET['key']);

if (false === $acct) {
    return false;
}

$msg = new Message($msgPath, $acct);

$lastMod = !empty($_GET['ts']) ? $_GET['ts']: 0;
$lastMod = substr($lastMod, 0, 10);
$lastMod = (int)$lastMod;

$result = array();

$start = gettimeofday();
$prevMsg = $acct->getTemp('cache');

do{
    usleep(10000);

    if ($acct->getFileTime() >= $lastMod) {
        $result['account'] = $acct->getAllOnline();
    }

    if($msg->getFileTime() >= $lastMod) {
        $result['message'] = $msg->fetch();
    }

    if (!empty($result)) {
        $theMsg = json_encode($result);
        if ($theMsg != $prevMsg) {
            $acct->setTemp('cache', $theMsg);
            echo $theMsg;
            flush();
            exit;
        }
        $result = array();
        $lastMod = time();
    }

    $end = gettimeofday();
} while($timeout > ($end['sec'] - $start['sec']));

echo FAILED;
...