Модераторы: skyboy, MoLeX, Aliance, ksnk

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Подгрузка нескольких потоков, Скачиваю сайты 
V
    Опции темы
Levsha
Дата 13.6.2007, 19:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Я осуществляю загрузку сразу нескольких страниц других сайтов стандартным методом "fopen-fgets-fclose".  Страниц примерно 15.
Как понимаю, при загрузке страницы чужого сервера, тратится время на:
  • запрос серверу
  • ожидание ответа сервера
  • подбор сервером нужных данных для страницы
  • выдача сервером результата
Но загрузка страниц происходит последовательно, следовательно я трачу лишнее время на второй и третий пункт, т.е. пока чужой сервер думает, я мог бы загружать другие файлы. 
Следовательно даже не зависимо от ширины или скорости канала моего сервера, скорость загрузки сраниц будет доооолгой.

Вопрос, возможно ли организовать загрузку сразу нескольких страниц одновременно?

Примерно, я планирую что бы это выглядело так: 
Код

$url = array("orange.com", "banana.com", "apple.com");
$text = MyDownload ($url);

где $text соответсвенно будет массивом


--------------------
PM   Вверх
sTa1kEr
Дата 13.6.2007, 22:21 (ссылка) |    (голосов:4) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Для создания нескольких потоков существует 2 способа:
1. Для каждого нового потока запускать отдельный интерпретатор PHP. Это наиболее простой, но и наиболее корявый способ. Так же каждый новый псевдопоток будет съедать около 15мб памяти.
Методика этого способа следующая: создаем отдельный скрипт вся работа которого заключается в том, что бы загрузить нужный сайт, URL сайта будет передаватся первым параметром. Затем просто запускаем этот скрипт для каждого URL-а.
Для того что бы не ожидать окончание работы каждого такого скрипта, можно запустить его в фоновом режиме (для этого в конце команды нужно добавить &):
Код

exec("/usr/binphp loadpage.php $url &");

Но такой способ не будет работать в Windows. Другой способ не ждать окончания работы скрипта - это использовать proc-open
Код

$desc = array(
   0 => array("pipe", "r"),
   1 => array("pipe", "w"),
   2 => array("file", "/tmp/log", "a")
);

$env = array("URL" => $url);
$p = proc_open('/usr/bin/php loadpage.php', $desc, $pipes, dirname(__FILE__), $env);
// Пока страничка загружается, работаем дальше...

Вот и вся наука.
2. Более правильный способ. Заключается он в использовании Stream Functions совместно с stream_set_blocking() и stream_select(). Включение режима "non-blocking" позволяет не ждать когда поток будет доступен для чтения, а stream_select() позваляет из массива потоков выбирать тот поток(и), который доступен для чтения/записи данных в данный момент. Написал пример работы с потоками:
Код

$timeout = "30";
$urls = array(
   "ya.ru",
   "php.net",
   "zend.com",
   "mail.ru",
   "microsoft.com",
   "google.com",
   "forum.vingrad.ru"
   );

$streams = array();

foreach($urls as $url)
{
   $stream = stream_socket_client(
      "tcp://$url:80",
      $errno, $errstr, $timeout,
      STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT); // Асинхронное соединение, что бы не ждать коннекта...
   stream_set_blocking($stream, 0); // Для всех потоков ставим режим non-blocking, что бы не ждать когда данные будут доступны для чтения/записи
   $streams[$url] = $stream;
}

$toRead = $toWrite = $streams; // Два массива потоков, для чтения и для записи. Для чтения можно сразуже задавать, т.к. все равно они не будут доступны пока не будет послан запрос

do
{
   $rStreams = $toRead;
   $wStreams = $toWrite;
   $num = stream_select($rStreams, $wStreams, $e = null, 0); // Выбираем какой-нибудь поток. Последний параметр 0 - не ждать таймаута 

   if ($num > 0) // Если $num == 0, то можно добавить в общий массив новых потоков, что бы не stream_select не простаивал, но я не стал этого делать
   {
      if (count($wStreams) > 0)
      {
         foreach($wStreams as $write)
         {
            $url = array_search($write, $streams);
            echo "Sending request for $url\n";
            fwrite($write, "GET http://$url/ HTTP/1.1\r\nAccept: */*\r\nnAccept-Language: en-us\r\nPragma: no-cache\r\nUser-Agent: Monzilla/4.0 (compatible; MSIE 6.0)\r\nHost: $url\r\nConnection: Close\r\n\r\n");
            unset($toWrite[array_search($write, $toWrite)]); // Запрос послан, больше не надо выбирать поток для записи
         }
      }

      if (count($rStreams) > 0)
      {
         foreach($rStreams as $read)
         {
            $url = array_search($read, $streams);
            echo "Getting data for $url\n";
            $f = fopen($url, "w");
            while (!feof($read))
            {
               fputs($f, fgets($read, 128));
            }
            fclose($f);
            unset($toRead[array_search($read, $toRead)]); // Ответ получен, поток не нужен больше
         }
      }
   }
} while(count($toRead) > 0); // Читать нечего больше

PM MAIL   Вверх
Vbif
Дата 14.6.2007, 19:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 59
Регистрация: 25.2.2006
Где: Реутов

Репутация: нет
Всего: нет



Жаль что такое чудо будет работать лишь на php5
PM MAIL WWW ICQ   Вверх
Levsha
Дата 15.6.2007, 03:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



sTa1kEr, благодарю smile , разобрался, под себя переделал.
Выглядит это так:
Код

<?
function MyDownload ($urls) {
    $timeout = "30";
    $streams = array();
    $result = array();
    foreach($urls as $url)
    {
       $stream = stream_socket_client(
          "tcp://$url:80",
          $errno, $errstr, $timeout,
          STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT); // Асинхронное соединение, что бы не ждать коннекта...
          stream_set_blocking($stream, 0); // Для всех потоков ставим режим non-blocking, что бы не ждать когда данные будут доступны для чтения/записи
         $streams[$url] = $stream;
    }
    $toRead = $toWrite = $streams; // Два массива потоков, для чтения и для записи. Для чтения можно сразуже задавать, т.к. все равно они не будут доступны пока не будет послан запрос
    do
    {
       $rStreams = $toRead;
       $wStreams = $toWrite;
       $num = stream_select($rStreams, $wStreams, $e = null, 0); // Выбираем какой-нибудь поток. Последний параметр 0 - не ждать таймаута 
    
       if ($num > 0) // Если $num == 0, то можно добавить в общий массив новых потоков, что бы не stream_select не простаивал, но я не стал этого делать
       {
          if (count($wStreams) > 0)
          {
             foreach($wStreams as $write)
             {
                $url = array_search($write, $streams);
                //echo "Sending request for $url\n<br>";
                fwrite($write, "GET http://$url/ HTTP/1.1\r\nAccept: */*\r\nnAccept-Language: en-us\r\nPragma: no-cache\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0)\r\nHost: $url\r\nConnection: Close\r\n\r\n");
                unset($toWrite[array_search($write, $toWrite)]); // Запрос послан, больше не надо выбирать поток для записи
             }
          }
          if (count($rStreams) > 0)
          {
             foreach($rStreams as $read)
             {
                $url = array_search($read, $streams);
                //echo "Getting data for $url\n<br>";
                $result[$url] = "";
                while (!feof($read))
                {
                   $result[$url] = $result[$url].fgets($read, 128);   
                }
               unset($toRead[array_search($read, $toRead)]); // Ответ получен, поток не нужен больше
             }
          }
       }
    } while(count($toRead) > 0); // Читать нечего больше
    return $result;
}

$urls = array(
   "ya.ru",
   "php.net",
   "zend.com",
   "mail.ru",
   "microsoft.com",
   "google.com",
   "forum.vingrad.ru"
   );

$sait = MyDownload ($urls);

echo $sait ["ya.ru"];
?>


Но есть проблема, при выдаче результата, скрипт также выдает серверные заголовки типа:
Код

HTTP/1.1 200 OK
Connection: close
Content-Type: text/html; charset=windows-1251
Accept-Ranges: bytes
ETag: "-604246012"
Last-Modified: Mon, 04 Jun 2007 13:36:05 GMT
Content-Length: 2110
Date: Fri, 15 Jun 2007 00:08:06 GMT
Server: httpd

Как их убрать? Где именно они добавляются?

Добавлено через 12 минут и 5 секунд
И еще: как скачать ссылку типа http://sait.ru/script/fail.php?name=web&z=0&c=110 ?


--------------------
PM   Вверх
Levsha
Дата 15.6.2007, 08:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Цитата

И еще: как скачать ссылку типа http://sait.ru/script/fail.php?name=web&z=0&c=110 ?

Снимаю вопрос: ссылка должна выглядеть вот так tcp://sait.ru:80/script/fail.php?name=web&z=0&c=110


Я Провел тест на время генерации страницы, вместо предидущих 19.38749сек я получил 8.105515сек smile , экономия десяти секунд smile !!!! sTa1kEr, благодарю за науку!

Осталась только проблема серверных заголовков. Конечно переменную можно просто обработать, и убрать все что идет до первого тега, но имхо это неправильно.


--------------------
PM   Вверх
vasac
Дата 15.6.2007, 10:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1060
Регистрация: 4.5.2006

Репутация: нет
Всего: 36



PM WWW   Вверх
sTa1kEr
Дата 15.6.2007, 12:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Цитата(Vbif @  14.6.2007,  19:04 Найти цитируемый пост)
Жаль что такое чудо будет работать лишь на php5

На 4ом не будет работать только функция stream_socket_client и соответственно асинхронное соединение. Вместо нее можно использовать обычный fsockopen. Все остальное будет работать и на 4ом PHP.
Цитата(Levsha @  15.6.2007,  08:47 Найти цитируемый пост)
Снимаю вопрос: ссылка должна выглядеть вот так tcp://sait.ru:80/script/fail.php?name=web&z=0&c=110

Вообще-то не совсем так... Коннектится нужно к tcp://sait.ru:80, а в запрос посылать уже полный урл. 
Цитата(Levsha @  15.6.2007,  08:47 Найти цитируемый пост)
Осталась только проблема серверных заголовков. Конечно переменную можно просто обработать, и убрать все что идет до первого тега, но имхо это неправильно. 

Я бы разделил хидеры от контента через explode (вместо строчек 40-44):
Код

$buffer = "";
while (!feof($read))
{
   $buffer .= fgets($read, 1024); 
}
$tmp = explode("\r\n\r\n", $buffer);
/* $header[$url] = */ array_shift($tmp);
$result[$url] = implode("\r\n\r\n", $tmp);


Цитата(vasac @  15.6.2007,  10:22 Найти цитируемый пост)
Мультикурл 

Да, есть такое. Надо будет протестировать. Жаль только, что еще сыроват и плохо задокументирован.
PM MAIL   Вверх
teroni
Дата 15.6.2007, 13:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 381
Регистрация: 15.5.2007
Где: Днепропетровск

Репутация: 1
Всего: 22



Цитата(sTa1kEr @  15.6.2007,  12:04 Найти цитируемый пост)
Да, есть такое. Надо будет протестировать. Жаль только, что еще сыроват и плохо задокументирован

А где-нибудь нормальную документацию не видели?
PM MAIL   Вверх
Levsha
Дата 15.6.2007, 13:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Некоторые сайты говорят в ответ:
Цитата

Your browser sent a request that this server could not understand.


Запрос идет такой
Цитата

GET http://$url HTTP/1.1\r\nAccept: */*\r\nAccept-Language: en-us\r\nPragma: no-cache\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0)\r\nHost: $url\r\nConnection: Close\r\n\r\n

Может что-то неправильно?

Цитата(sTa1kEr @  15.6.2007,  12:04 Найти цитируемый пост)
Я бы разделил хидеры от контента через explode (вместо строчек 40-44):

Спасибо за еще одну гениальную идею  smile 



--------------------
PM   Вверх
sTa1kEr
Дата 15.6.2007, 14:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Цитата(teroni @  15.6.2007,  13:11 Найти цитируемый пост)
А где-нибудь нормальную документацию не видели? 

Нет, не видел, да и наврядтли она будет, пока на амереканских зеркалах php.net нету нормально документации.

Levsha, Да... я когда писал этот пример не учел что хост может выдать ошибку или его вовсе не существует.  Нужно добавить проверку.
Код

       if ($errno > 0)
       {
          echo "Error connectiong to $url. $errstr($errno)";
          continue;
       }

Сразу после stream_socket_client().

Добавлено через 11 минут и 28 секунд
Так же на всякий случай еще можно проверять 3ий параметр stream_select(). Доработанный код:
Код

function MyDownload ($urls, $timeout = 30) {
    $streams = array();
    $result = array();
    foreach($urls as $url)
    {
       $stream = @stream_socket_client(// Если не удается законнектится то выводится Warning, а он нам тут совершенно не нужен
          "tcp://$url:80",
          $errno, $errstr, $timeout,
          STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT); // Асинхронное соединение, что бы не ждать коннекта...
       if ($errno > 0)
       {
          //echo "Error connectiong to $url. $errstr($errno)<br>\n";
          // либо еще что-нибудь делаем. Пишем в логи итп...
          continue;
       }
       stream_set_blocking($stream, 0); // Для всех потоков ставим режим non-blocking, что бы не ждать когда данные будут доступны для чтения/записи
       $streams[$url] = $stream;
    }
    $toException = $toRead = $toWrite = $streams; // Два массива потоков, для чтения и для записи. Для чтения можно сразуже задавать, т.к. все равно они не будут доступны пока не будет послан запрос
    do
    {
       $rStreams = $toRead;
       $wStreams = $toWrite;
       $eStreams = $toException;
       $num = stream_select($rStreams, $wStreams, $eStreams, 0); // Выбираем какой-нибудь поток. Последний параметр 0 - не ждать таймаута 
    
       if ($num > 0) // Если $num == 0, то можно добавить в общий массив новых потоков, что бы не stream_select не простаивал, но я не стал этого делать
       {
          if (count($wStreams) > 0)
          {
             foreach($wStreams as $write)
             {
                $url = array_search($write, $streams);
                //echo "Sending request for $url<br>\n";
                fwrite($write, "GET http://$url/ HTTP/1.1\r\nAccept: */*\r\nnAccept-Language: en-us\r\nPragma: no-cache\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0)\r\nHost: $url\r\nConnection: Close\r\n\r\n");
                unset($toWrite[array_search($write, $toWrite)]); // Запрос послан, больше не надо выбирать поток для записи
             }
          }
          if (count($rStreams) > 0)
          {
             foreach($rStreams as $read)
             {
                $url = array_search($read, $streams);
                //echo "Getting data for $url\n<br>";
                $buffer = "";
                while (!feof($read))
                {
                   $buffer .= fgets($read, 1024); 
                }
                $tmp = explode("\r\n\r\n", $buffer);
                /* $header[$url] = */array_shift($tmp);
                $result[$url] = implode("\r\n\r\n", $tmp);
                unset($toRead[array_search($read, $toRead)]); // Ответ получен, поток не нужен больше
             }
          }
          if (count($eStreams) > 0)
          {
             foreach($eStreams as $exception)
             {
                $url = array_search($exception, $streams);
                // echo "Fail getting data for $url.<br>\n";
                // Здесь так же кричим, что сервер вернул не то что ожидали и выкидываем этот поток из стека
             }
             unset($toRead[array_search($exception, $toRead)]);
             unset($toWrite[array_search($exception, $toWrite)]);
             unset($toException[array_search($exception, $toException)]);
          }
       }
    } while(count($toRead) > 0); // Читать нечего больше
    return $result;
}
$urls = array(
   "localhost",
   "localhost2"
   );
$sites = MyDownload ($urls);
echo count($sites);


PM MAIL   Вверх
Levsha
Дата 15.6.2007, 14:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



sTa1kEr, но сайт то существует, более того, запрос перепроверял через браузер.
Все должно быть...


--------------------
PM   Вверх
vasac
Дата 15.6.2007, 14:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1060
Регистрация: 4.5.2006

Репутация: нет
Всего: 36



Цитата

GET http://$url HTTP/1.1

Здесь должен указывать путь к документу на сайте, а не URL
PM WWW   Вверх
sTa1kEr
Дата 15.6.2007, 14:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Levsha, вы в $urls пишете ссылки вида tcp://sait.ru:80/script/fail.php?name=web&z=0&c=110 ?
PM MAIL   Вверх
Levsha
Дата 15.6.2007, 14:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Все, нашел, мой был косяк

Добавлено через 1 минуту и 39 секунд
Цитата(sTa1kEr @  15.6.2007,  14:30 Найти цитируемый пост)
Levsha, вы в $urls пишете ссылки вида tcp://sait.ru:80/script/fail.php?name=web&z=0&c=110 ?

Да. Проглядел Host: $url


--------------------
PM   Вверх
sTa1kEr
Дата 15.6.2007, 15:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Код для *полных* URL-ов. Версия: 0.0.3 Pre Alpha
Код

if (!defined("MD_DEBUG"))
   define("MD_DEBUG", false);

function MyDownload ($urls, $timeout = 30) {
    $streams = array();
    $result = array();
    foreach($urls as $url)
    {
       $host = parse_url($url, PHP_URL_HOST);
       if ($host === null)
       {
          if (MD_DEBUG) echo "Host in '$url' is not correct<br>\n";
          continue;
       }
       $port = parse_url($url, PHP_URL_PORT);
       $stream = @stream_socket_client(// Если не удается законнектится то выводится Warning, а он нам тут совершенно не нужен
          "tcp://$host:".($port === null ? "80" : $port),
          $errno, $errstr, $timeout,
          STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT); // Асинхронное соединение, что бы не ждать коннекта...
       if ($errno > 0)
       {
          if (MD_DEBUG) echo "Error connectiong to $url. $errstr($errno)<br>\n";
          // либо еще что-нибудь делаем. Пишем в логи итп...
          continue;
       }
       stream_set_blocking($stream, 0); // Для всех потоков ставим режим non-blocking, что бы не ждать когда данные будут доступны для чтения/записи
       $streams[$url] = $stream;
    }
    $toException = $toRead = $toWrite = $streams; // Два массива потоков, для чтения и для записи. Для чтения можно сразуже задавать, т.к. все равно они не будут доступны пока не будет послан запрос
    do
    {
       $rStreams = $toRead;
       $wStreams = $toWrite;
       $eStreams = $toException;
       $num = @stream_select($rStreams, $wStreams, $eStreams, 0); // Выбираем какой-нибудь поток. Последний параметр 0 - не ждать таймаута 
    
       if ($num > 0) // Если $num == 0, то можно добавить в общий массив новых потоков, что бы не stream_select не простаивал, но я не стал этого делать
       {
          if (count($wStreams) > 0)
          {
             foreach($wStreams as $write)
             {
                $url = array_search($write, $streams);
                $host = parse_url($url, PHP_URL_HOST);
                $request = "GET $url HTTP/1.1\r\nAccept: */*\r\nnAccept-Language: en-us\r\nPragma: no-cache\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0)\r\nHost: $host\r\nConnection: Close\r\n\r\n";
                if (MD_DEBUG) echo "Sending request for $url<br>\n$request";
                fwrite($write, $request);
                unset($toWrite[array_search($write, $toWrite)]); // Запрос послан, больше не надо выбирать поток для записи
             }
          }
          if (count($rStreams) > 0)
          {
             foreach($rStreams as $read)
             {
                $url = array_search($read, $streams);
                if (MD_DEBUG) echo "Getting data for $url<br>\n";
                $buffer = "";
                while (!feof($read))
                {
                   $buffer .= fgets($read, 1024); 
                }
                $tmp = explode("\r\n\r\n", $buffer);
                /* $header[$url] = */array_shift($tmp);
                $result[$url] = implode("\r\n\r\n", $tmp);
                unset($toRead[array_search($read, $toRead)]); // Ответ получен, поток не нужен больше
             }
          }
          if (count($eStreams) > 0)
          {
             foreach($eStreams as $exception)
             {
                $url = array_search($exception, $streams);
                if (MD_DEBUG) echo "Fail getting data for $url.<br>\n";
                // Здесь так же кричим, что сервер вернул не то что ожидали и выкидываем этот поток из стека
             }
             unset($toRead[array_search($exception, $toRead)]);
             unset($toWrite[array_search($exception, $toWrite)]);
             unset($toException[array_search($exception, $toException)]);
          }
       }
    } while(count($toRead) > 0); // Читать нечего больше
    return $result;
}

// !!! Только полные URL-ы !!!
$urls = array(
   "http://www.yandex.ru/yandsearch?stype=www&nl=0&text=test",
   "http://mail.ru:80/"
   );
$sites = MyDownload ($urls);
var_dump($sites);

PM MAIL   Вверх
Levsha
Дата 16.6.2007, 04:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



sTa1kEr, я уже правда по своему исправил, но все равно спасибо


--------------------
PM   Вверх
Levsha
Дата 19.6.2007, 16:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Столкнулся с такой проблемой, закачивая страницы вышеописанным методом в текст документов иногда вставляются "левые" наборы символов типа: "15f", "25e4", "14bb". Почему это происходит? Может ли это быть некая защита сайтов?

И еще проблема. Как я понимаю, тот же вышеописанный метод использует кеширование? Как его включать и выключать?


--------------------
PM   Вверх
sTa1kEr
Дата 19.6.2007, 16:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Цитата(Levsha @  19.6.2007,  16:03 Найти цитируемый пост)
Столкнулся с такой проблемой, закачивая страницы вышеописанным методом в текст документов иногда вставляются "левые" наборы символов типа: "15f", "25e4", "14bb". Почему это происходит? Может ли это быть некая защита сайтов?

Надо разбираться на конкретном примере.
Цитата(Levsha @  19.6.2007,  16:03 Найти цитируемый пост)
И еще проблема. Как я понимаю, тот же вышеописанный метод использует кеширование? Как его включать и выключать?

Нет, кэширование не используется. Где вы это увидели?
PM MAIL   Вверх
Levsha
Дата 19.6.2007, 17:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Цитата(sTa1kEr @  20.6.2007,  00:49 Найти цитируемый пост)
Нет, кэширование не используется. Где вы это увидели?
Да просто браузер выдал одно, а сервер скачал другое...

Добавлено через 12 минут и 11 секунд
Цитата(sTa1kEr @  20.6.2007,  00:49 Найти цитируемый пост)
Надо разбираться на конкретном примере.
Ну например если скачивать сайт с запросом: http://www.service-whois.ru/?domain=mail.ru получаю баги (на скриншоте)

sTa1kEr, проверьте пожалуйста, может это только у меня глючит.

Что примечательно, для http://www.service-whois.ru/?domain=yandex.ru такого нет.

Присоединённый файл ( Кол-во скачиваний: 18 )
Присоединённый файл  1.gif 15,04 Kb


--------------------
PM   Вверх
sTa1kEr
Дата 19.6.2007, 20:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Levsha, попробую вечером разобраться.
Цитата(Levsha @  19.6.2007,  17:57 Найти цитируемый пост)
sTa1kEr, проверьте пожалуйста, может это только у меня глючит.

Нет, у меня тоже самое, только символы другие.
PM MAIL   Вверх
teroni
Дата 20.6.2007, 11:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 381
Регистрация: 15.5.2007
Где: Днепропетровск

Репутация: 1
Всего: 22



Да, сталкивался с такой же проблемой...
Из-за чего возникает - так и не понял, для решения - тупо обрезал все, до первого < и после последнего >. Мне кажется, что это каким-то образом зависит от хостинга, на котором расположена скачиваемая страница, т.к. на некоторых такая проблема не возникает.

Это сообщение отредактировал(а) teroni - 20.6.2007, 11:14
PM MAIL   Вверх
sTa1kEr
Дата 20.6.2007, 17:04 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Разобрался в чем дело. Достаточно было повнимательнее почитать спецификацию HTTP 1.1 smile 3.6.1 Chunked Transfer Coding
Смысл этого хидера в крации: Для лучшего контроля передачи данных в HTTP 1.1 существует возможность передавать контент по частям с указанием размера каждой части. Сначала передается размер следующего блока (число в HEX и следующий за ним разделитель строки CRLF), затем сам блок и так далее пока размер блока не будет равен нулю (0 в самом конце). Я вижу три способа решения этой проблемы:
1. Опять же самое простое. Вместо HTTP 1.1 использовать HTTP 1.0.
2. Сначала получаем хидеры. Смотрим используется ли Chunked Coding (заголовок Transfer-Encoding: chunked). Если используется то полученный контент декодируем при помощи http://ru2.php.net/manual/ru/function.http...nked-decode.php. Но для этого придется установить соответствующее PECL расширение.
3. Имхо, самое правильное. Если предоставляется возможность дополнительного контроля целостности данных, то почему бы этим не воспользоваться? 
Код

function get_chanked($stream)
{
   $content = "";
   do
   {
      $len = trim(fgets($stream, 10));
      if (MD_DEBUG) echo "Find lable 0x$len<br>\n";
      if ($len === false || !preg_match("|[0-9a-f]+|i", $len))
      {
         if (MD_DEBUG) echo "Failure getting content<br>\n";
         return "";
      }
      else
      {
         $len = hexdec($len);
         if (MD_DEBUG) echo "Reading $len byte<br>\n";
      }
      if ($len > 0)
      {
         $readed = 0;
         while($readed < $len + 2)
         {
            $buffer = fgets($stream);
            $readed += strlen($buffer);
            $content .= $buffer;
         }
      }
   } while($len > 0);
   return $content;
}

Соответственно в функции MyDownload при чтении будет:
Код

          if (count($rStreams) > 0)
          {
             foreach($rStreams as $read)
             {
                $url = array_search($read, $streams);
                if (MD_DEBUG) echo "Getting data for $url<br>\n";
                $isChunk = false;
                $result[$url] = "";
                while(($header = fgets($read)) != "\r\n")
                {
                   if (preg_match("|Transfer-Encoding:\s+chunked|i", $header))
                   {
                      $isChunk = true;
                   }
                }
                if ($isChunk)
                {
                   $result[$url] = get_chanked($read);
                }
                else
                {
                   while (!feof($read))
                   {
                      $result[$url] .= fread($read, 1024); 
                   }
                }
                unset($toRead[array_search($read, $toRead)]); // Ответ получен, поток не нужен больше
             }
          }


Это сообщение отредактировал(а) sTa1kEr - 20.6.2007, 17:58
PM MAIL   Вверх
Levsha
Дата 21.6.2007, 07:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Вот уж действительно раздел для профи...
Пытаюсь подстроить в свое...
Отпишусь...


--------------------
PM   Вверх
Levsha
Дата 21.6.2007, 08:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Есть, срабатывает шикарно, ошибок нет. Щас еще чутка доделаю-приделаю и выложу свою версию smile 
sTa1kEr, мегаспасибо


--------------------
PM   Вверх
Levsha
Дата 21.6.2007, 09:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



В общем если нужно - моя версия:
Код

if (!defined("MD_DEBUG")) define("MD_DEBUG", false);
function get_chanked($stream) {
   $content = "";
   do
   {
      $len = trim(fgets($stream, 10));
      if (MD_DEBUG) echo "Find lable 0x$len<br>\n";
      if ($len === false || !preg_match("|[0-9a-f]+|i", $len))
      {
         if (MD_DEBUG) echo "Failure getting content<br>\n";
         return "";
      }
      else
      {
         $len = hexdec($len);
         if (MD_DEBUG) echo "Reading $len byte<br>\n";
      }
      if ($len > 0)
      {
         $readed = 0;
         while($readed < $len + 2)
         {
            $buffer = fgets($stream);
            $readed += strlen($buffer);
            $content .= $buffer;
         }
      }
    } while($len > 0);
    return $content;
    }

function MyDownload ($urls, $timeout = 30) {
    $streams = array();
    $result = array();
    foreach($urls as $url)
    {
       $host = parse_url($url, PHP_URL_HOST);
       if ($host === null)
       {
          if (MD_DEBUG) echo "Host in '$url' is not correct<br>\n";
          continue;
       }
       $port = parse_url($url, PHP_URL_PORT);
       $stream = @stream_socket_client(// Если не удается законнектится то выводится Warning, а он нам тут совершенно не нужен
          "tcp://$host:".($port === null ? "80" : $port),
          $errno, $errstr, $timeout,
          STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT); // Асинхронное соединение, что бы не ждать коннекта...
       if ($errno > 0)
       {
          if (MD_DEBUG) echo "Error connectiong to $url. $errstr($errno)<br>\n";
          // либо еще что-нибудь делаем. Пишем в логи итп...
          continue;
       }
       stream_set_blocking($stream, 0); // Для всех потоков ставим режим non-blocking, что бы не ждать когда данные будут доступны для чтения/записи
       $streams[$url] = $stream;
    }
    $toException = $toRead = $toWrite = $streams; // Два массива потоков, для чтения и для записи. Для чтения можно сразуже задавать, т.к. все равно они не будут доступны пока не будет послан запрос
    do
    {
       $rStreams = $toRead;
       $wStreams = $toWrite;
       $eStreams = $toException;
       $num = @stream_select($rStreams, $wStreams, $eStreams, 0); // Выбираем какой-нибудь поток. Последний параметр 0 - не ждать таймаута 
    
       if ($num > 0) // Если $num == 0, то можно добавить в общий массив новых потоков, что бы не stream_select не простаивал, но я не стал этого делать
       {
          if (count($wStreams) > 0)
          {
             foreach($wStreams as $write)
             {
                $url = array_search($write, $streams);
                $host = parse_url($url, PHP_URL_HOST);
                $request = "GET $url HTTP/1.1\r\nAccept: */*\r\nnAccept-Language: en-us\r\nPragma: no-cache\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0)\r\nHost: $host\r\nConnection: Close\r\n\r\n";
                if (MD_DEBUG) echo "Sending request for $url<br>\n$request";
                fwrite($write, $request);
                unset($toWrite[array_search($write, $toWrite)]); // Запрос послан, больше не надо выбирать поток для записи
             }
          }
          if (count($rStreams) > 0)
          {
             foreach($rStreams as $read)
             {
                $url = array_search($read, $streams);
                $key = array_keys ($urls, $url); $key = $key[0];
                if (MD_DEBUG) echo "Getting data for $url<br>\n";
                $isChunk = false;
                $charset = "";
                $result[$key][0] = "";
                while(($header = fgets($read)) != "\r\n") {
                    if (!(strpos($header, "Content-Type")===false)) if (!(strpos($header, "charset=")===false)) $charset = substr($header, strpos($header, "charset=")+8);
                    else $charset = "default";
                    if (preg_match("|Transfer-Encoding:\s+chunked|i", $header)) $isChunk = true;
                 }
                if ($isChunk) $result[$key][0] = get_chanked($read);
                else while (!feof($read)) $result[$key][0] .= fread($read, 1024);
                $result[$key][1] = $charset;
                unset($toRead[array_search($read, $toRead)]); // Ответ получен, поток не нужен больше
             }
          }
          if (count($eStreams) > 0)
          {
             foreach($eStreams as $exception)
             {
                $url = array_search($exception, $streams);
                if (MD_DEBUG) echo "Fail getting data for $url.<br>\n";
                // Здесь так же кричим, что сервер вернул не то что ожидали и выкидываем этот поток из стека
             }
             unset($toRead[array_search($exception, $toRead)]);
             unset($toWrite[array_search($exception, $toWrite)]);
             unset($toException[array_search($exception, $toException)]);
          }
       }
    } while(count($toRead) > 0); // Читать нечего больше
    return $result;
}

$urls = array(
"yandex"=>"http://www.yandex.ru/yandsearch?text=Превед",
"whois"=>"http://www.service-whois.ru/?domain=mail.ru"
    );
$sites = MyDownload ($urls);
$yandex1 = $sites["yandex"][0];
$yandex2 = $sites["yandex"][1];

Основное отличие в том, что дается функции двумерный массив, а возвращается массив содержащий тело документа[0] и кодировку[1]. В принципе туда легко можно добавить любую другую информацию...


--------------------
PM   Вверх
Levsha
Дата 24.6.2007, 14:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



А вот и новая проблема, если один из скачиваемых сайтов не отвечает долгое время, т.е. вообще нет ответа от сервера, ни ошибки, ничего другого, то останавливается все, соответственно сайт встает. Возможно ли установить лимит по времени на ответ сервера, чтобы по истечении возвращалась бы пустая строка или что-то вроде... Ну в общем лишь бы сайт не вставал.


--------------------
PM   Вверх
Levsha
Дата 25.6.2007, 10:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



У меня ощущение что $timeout не работает.. Я так понимаю, $timeout=30 подразумевает секунды? А страница прогружается за пять секунд, не выдав никакого результута...

Есть соображения у кого?


--------------------
PM   Вверх
sTa1kEr
Дата 25.6.2007, 15:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Странно... Если хоста не существует, то поток не будет создан. А если будет ошибка, то он попадет в массив $eStreams и будет благополучно выброшен. Можете привести пример хоста из-за которого он зацикливается?
Цитата(Levsha @  25.6.2007,  10:22 Найти цитируемый пост)
У меня ощущение что $timeout не работает.. Я так понимаю, $timeout=30 подразумевает секунды? А страница прогружается за пять секунд, не выдав никакого результута...

$timeout - это таймаут только для соединения с сервером. Т.ч. вполне возможно, что он законнектиться с сервером за 5 секунд и тут же сервер вернет ошибку.
PM MAIL   Вверх
Levsha
Дата 25.6.2007, 15:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Хост существует, просто он долго думает что ответить... Ну это в прошлом...

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

А локально выдается
Код

Fatal error: Maximum execution time of 30 seconds exceeded in y:\home\...\func.php on line 301


А 301я строка - это первая строка цикла:
Код

while(($header = fgets($read)) != "\r\n") {
   if (!(strpos($header, "Content-Type")===false)) if (!(strpos($header, "charset=")===false)) $charset = substr($header, strpos($header, "charset=")+8);
   else $charset = "default";
   if (preg_match("|Transfer-Encoding:\s+chunked|i", $header)) $isChunk = true;
}


Добавлено @ 15:30
Можно ли сделать, чтобы он вообще если не успел ниче за 30 сек, то пусть вообще пустые строки вернет.

Это сообщение отредактировал(а) Levsha - 25.6.2007, 15:30


--------------------
PM   Вверх
sTa1kEr
Дата 25.6.2007, 16:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Цитата(Levsha @  25.6.2007,  15:27 Найти цитируемый пост)
А 301я строка - это первая строка цикла:

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

set_time_limit(90); 

И добавьте проверку
Код

while(($header = fgets($read)) !== false && $header != "\r\n")

Цитата(Levsha @  25.6.2007,  15:27 Найти цитируемый пост)
Можно ли сделать, чтобы он вообще если не успел ниче за 30 сек, то пусть вообще пустые строки вернет.

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

$endWork = mktime() + 30;
// ...
do
{
// ...
} while(count($toRead) > 0 && mktime() < $endWork);


Это сообщение отредактировал(а) sTa1kEr - 25.6.2007, 16:16
PM MAIL   Вверх
Levsha
Дата 25.6.2007, 16:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Цитата(sTa1kEr @  26.6.2007,  00:15 Найти цитируемый пост)
В начале функции в переменную запишите метку времени и добавьте в цикл условие. Можно добавить в цикл для чтения данных такую же проверку.
Совсем забыл о простейших методах...


--------------------
PM   Вверх
Levsha
Дата 25.6.2007, 17:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



sTa1kEr, спасибо, заработало... Я думаю set_time_limit(90); помог.

Добавлено через 3 минуты и 36 секунд
Кстати созданный благодаря этому продукт... http://web-alt.ru/stat


--------------------
PM   Вверх
aktuba
Дата 25.6.2007, 18:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Смышленный
***


Профиль
Группа: Завсегдатай
Сообщений: 1915
Регистрация: 24.4.2006
Где: Планета Земля

Репутация: нет
Всего: 38



Levsha, что-то у тебя не так работает. Попробуй введи nnm.ru и посмотри, сколько выведет проиндексированных страниц в Яндексе. Всего 2, в то время, как почти по любому запросу nnm.ru попадает в результаты поиска.


--------------------
user posted image
PM MAIL WWW Skype   Вверх
sTa1kEr
Дата 25.6.2007, 18:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Для большинства сайтов выдает пустую страницу.

Добавлено через 5 минут и 22 секунды
Levsha, кстати, забавно, если ввести URL сайта web-alt.ru/stat/?url=ya.ru, то он отрабатывает нормально smile. Страшно подумать, что будет если вместо ya.ru подставить ссылку на анализ самой страницы (т.е. примерно так 'web-alt.ru/stat/?url=web-alt.ru/stat/?url=web-alt.ru/stat/?url=' итд). Имхо, надо исключать свой домен.
PM MAIL   Вверх
Levsha
Дата 25.6.2007, 18:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



aktuba, ну так ты по ссылке ходил? Там действительно две страницы... Это нестрашно, пару дней назад я застал ситуацию, когда яндекс показывал что для моего сайта вообще нет проиндексированных страниц, хотя всегда показывал 49. У Яндекса такое бывает, и на выдачу это не влияет, просто какой-то пересчет данных...

aktuba, спасибо, что воспользовался серсисом. Буду рад слышать рекомендации и советы. Только тему желательно обсуждать здесь.


Добавлено @ 18:27
Цитата(sTa1kEr @  26.6.2007,  02:14 Найти цитируемый пост)
Страшно подумать, что будет если вместо ya.ru подставить ссылку на анализ самой страницы (т.е. примерно так 'web-alt.ru/stat/?url=web-alt.ru/stat/?url=web-alt.ru/stat/?url=' итд). Имхо, надо исключать свой домен.

Да нет, я пробовал, ничего страшного не случается. Домен отделяется от остальной части, и по нему идет анализ, то что после "?" практически не учавствует в анализе

Добавлено @ 18:30
Цитата(sTa1kEr @  26.6.2007,  02:14 Найти цитируемый пост)
Для большинства сайтов выдает пустую страницу.
Большие проблемы с кодировками, непрерывно работаю над проектом уже 12 часов - сказывается

Это сообщение отредактировал(а) Levsha - 25.6.2007, 18:30


--------------------
PM   Вверх
aktuba
Дата 25.6.2007, 18:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Смышленный
***


Профиль
Группа: Завсегдатай
Сообщений: 1915
Регистрация: 24.4.2006
Где: Планета Земля

Репутация: нет
Всего: 38



Цитата

aktuba, ну так ты по ссылке ходил? Там действительно две страницы... 


Я вообще-то там модер =))) Две страницы говоришь? Это на сайте, с более 1 000 000 зарегистрированных пользователей, более 20 000 личных дневников, в каждом из которых от 1 до 100 и более страниц по 15 новостей, а каждая новость - отдельная страница??? Чего-то ты загнул...




--------------------
user posted image
PM MAIL WWW Skype   Вверх
Levsha
Дата 25.6.2007, 19:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



aktuba, по ссылке под цифрой 2 ты сходил??? Эх, все надо делать самому...
Вот эта ссылка. Как видишь, там действительно две страницы. Я всего лишь транслирую их результат. Повторяю, либо это временный глюк Яндекса, либо пиши платону

Добавлено через 2 минуты и 2 секунды
sTa1kEr, абсолютно все работает нормально, пока я не использую функцию MyDownload
Она постоянно в чем-нибудь глючит... Абидна


--------------------
PM   Вверх
sTa1kEr
Дата 25.6.2007, 19:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Цитата(Levsha @  25.6.2007,  19:09 Найти цитируемый пост)
sTa1kEr, абсолютно все работает нормально, пока я не использую функцию MyDownload
Она постоянно в чем-нибудь глючит... Абидна 

Кто сказал, что все сразу должно идеально работать, к тому же если учесть, что изначально она писалась как пример? С какими именно URL-ами она не работает и что не работает? Т.к. локально у меня проблем не обнаружилось.
PM MAIL   Вверх
Levsha
Дата 25.6.2007, 20:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



sTa1kEr, так в том то и проблема,что не могу отловить на котором url происходит ошибка. У меня есть смутное сомнение, что на хостинге хреновый канал, и сайт просто не успевает ничего скачивать...


--------------------
PM   Вверх
sTa1kEr
Дата 26.6.2007, 13:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Написал простой класс работы с потоками (примерно тоже, что здесь выкладывали, только слегка модернизировал). Что бы не засорять форум исходниками выложил его в гугле http://multi-downoader.googlecode.com/svn/trunk/Downloader/ Там же лежит тестовый скрипт и лог выполнения этого скрипта у меня. Все 104 страницы скачались без проблем, правда как показал тест, производительность не высокая, как ожидалось. 44 секунды...
Levsha, попробуйте запустите тест, если будет ошибка, то в логах ее будет видно. Только не забудьте set_time_limit побольше поставить.

Это сообщение отредактировал(а) sTa1kEr - 26.6.2007, 13:41
PM MAIL   Вверх
Levsha
Дата 27.6.2007, 20:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



sTa1kEr, спасибо, протестирую


--------------------
PM   Вверх
nerezus
  Дата 28.6.2007, 05:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Вселенский отказник
****


Профиль
Группа: Участник
Сообщений: 3330
Регистрация: 15.6.2005

Репутация: нет
Всего: 43



А почему именно пхп применяется для такой задачи? Не проще ли заюзать другой ЯП с поддержкой потоков(нитей)?


--------------------
Сообщество художников Artsociety.ru
PM MAIL WWW   Вверх
Levsha
Дата 28.6.2007, 07:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Цитата(nerezus @  28.6.2007,  13:40 Найти цитируемый пост)
А почему именно пхп применяется для такой задачи?
Потому что я умею программировать на PHP smile 


Цитата(nerezus @  28.6.2007,  13:40 Найти цитируемый пост)
Не проще ли заюзать другой ЯП с поддержкой потоков(нитей)?
Какой ЯП по твоему лучше подойдет?


--------------------
PM   Вверх
sTa1kEr
Дата 28.6.2007, 09:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Цитата(nerezus @  28.6.2007,  05:40 Найти цитируемый пост)
А почему именно пхп применяется для такой задачи? Не проще ли заюзать другой ЯП с поддержкой потоков(нитей)? 

Интересна реализация именно на пхп, т.к. на .NET, к примеру, это просто и очевидно, но подходит только для Windows платформ. На других прикладных языках будет слишком тяжело работать именно c Web (то , что на PHP одна встроенная функция, на C++ уже может потребовать своего объемного класс), а интегрировать PHP скрипт с какой-либо внешней программой- не менее проблематично, как и создавать мультипоточность в скриптовом языке.
И еще просто спортивный интерес, реализовывать на PHP то, для чего он в принципе не предназначенsmile

Цитата(Levsha @  28.6.2007,  07:53 Найти цитируемый пост)
Какой ЯП по твоему лучше подойдет? 

nerezus, мне то же интересно, на каком языке вы предлагаете это реализовывать?

Это сообщение отредактировал(а) sTa1kEr - 28.6.2007, 10:36
PM MAIL   Вверх
sTa1kEr
Дата 28.6.2007, 11:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Еще одно замечание по работе со stream functions. Как-то я совсем упустил из виду эту важную деталь... При отключенной блокировке потока, он не ждет данные, а только забирает то, что уже пришло на данный момент, поэтому просто использовать циклы нельзя, т.к. при очередной итерации данных еще может не быть и fread() вернет false...  Поэтому нужно перед чтением либо включать блокировку
Код

stream_set_blocking($stream, 1); // включаем блокировку
while (($buffer = fread($stream, 1024)) !== false) // спокойно читаем
{
   $content .= $buffer;
}
stream_set_blocking($stream, 0); // отключаем обратно

Либо проверять на доступность, через тот же stream_select каждый раз
Код

$eof = false;
while (stream_select($r = array($stream), $w = null, $e = null, 0) > 0)

   // есть данные для чтения
   $content .= fread($r[0], 1024);
   $eof = feof($r[0]);
}
if ($eof)
{
   // прочитали все данные, удаляем поток
}
else
{
   // еще не все прочитали, пока можно делать что-то другое, а к чтению данных этого потока вернутся позже
}


PM MAIL   Вверх
vasac
Дата 28.6.2007, 12:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1060
Регистрация: 4.5.2006

Репутация: нет
Всего: 36



Блокировку включать нельзя. Какой тогда смысл в ее отключении?
Нужно просто не проверять fRead на false, а смотреть fEof
PM WWW   Вверх
sTa1kEr
Дата 28.6.2007, 13:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Цитата(vasac @  28.6.2007,  12:05 Найти цитируемый пост)
Блокировку включать нельзя. Какой тогда смысл в ее отключении?

Смысл в асинхронных соединении, отправке запроса и получения ответа. Но вы правы, что читать данные будет эффективнее именно во втором случае.
Цитата(vasac @  28.6.2007,  12:05 Найти цитируемый пост)
Нужно просто не проверять fRead на false, а смотреть fEof 

Просто проверять на eof не достаточно, нужно так же проверять и на false иначе цикл будет идти в пустую.




Это сообщение отредактировал(а) sTa1kEr - 28.6.2007, 13:19
PM MAIL   Вверх
vasac
Дата 28.6.2007, 14:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1060
Регистрация: 4.5.2006

Репутация: нет
Всего: 36



Ну и пусть идет впустую. Думаете шестеренке в процессоре износятся?
PM WWW   Вверх
sTa1kEr
Дата 28.6.2007, 18:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Цитата(vasac @  28.6.2007,  14:46 Найти цитируемый пост)
Ну и пусть идет впустую. Думаете шестеренке в процессоре износятся? 

Так это будет то же самое, как если включить блокировку.
PM MAIL   Вверх
nerezus
Дата 28.6.2007, 18:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Вселенский отказник
****


Профиль
Группа: Участник
Сообщений: 3330
Регистрация: 15.6.2005

Репутация: нет
Всего: 43



sTa1kEr, а чем плохи питон? или даже джава(крупная артиллерия)?


--------------------
Сообщество художников Artsociety.ru
PM MAIL WWW   Вверх
sTa1kEr
Дата 28.6.2007, 19:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Цитата(nerezus @  28.6.2007,  18:53 Найти цитируемый пост)
sTa1kEr, а чем плохи питон? или даже джава(крупная артиллерия)? 

Питон... я его почти не знаю, мне с первого знакомства не понравился его синтаксис и я не стал с ним разбиратся (хотя, может быть, зря...).
Джава да, вполне подошла бы, но все же на ней намного сложнее разрабатывать веб приложения, нежели на PHP. Да и для нее требуется JRE... Наверное, тогда уж лучше всего бы подошел Mono  (кроссплатформенный .NET, артиллерия будет не слабее Джавы!), но он еще сыроват и для него нету хорошего IDE...

Кстати, есть пару интересных абзацев в статье Рынок разработки переполнен недоучками – PHP и хорош и плох своей простотой. Из-за этой простоты и начинаешь требовать от PHP почти не возможного, потому-что иначе - не интересно smile
PM MAIL   Вверх
Levsha
Дата 7.7.2007, 03:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



sTa1kEr, я прогнал ваши скрипты(на гугле которые). Действительно работает лучше первого скрипта. Пытаюсь подогнать под себя.


--------------------
PM   Вверх
Levsha
Дата 8.7.2007, 03:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Отлично, скрипты работают гораздо точнее. Но вот проблема - не качается webalta.
Например
Код

$urls = array("http://www.webalta.ru/search?q=web-alt.ru","http://www.webalta.ru/search?q=www.web-alt.ru");
$down = new Downloader();
$down->AddLogEngine("downloader.log");
try
{
   $data = $down->DownloadToArray($urls);
   var_dump($data);
}
catch (Exception $ex)
{
   $down->ToLog($ex);
}


Добавлено через 1 минуту и 10 секунд
Я опасаюсь что на webalte могли просто забанить мой IP. Проверьте пожалста у себя.


--------------------
PM   Вверх
sTa1kEr
Дата 10.7.2007, 21:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



Levsha, работает, но почему-то сервер выдает 500ую ошибку. Причем в браузере тоже сначала выдавал, теперь в браузере нормально. Надо с запросом поколдавать.
PM MAIL   Вверх
Levsha
Дата 26.7.2007, 00:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



Я с портами пробовал, все равно глючит... Да вебальта вся какая-то кривая...


--------------------
PM   Вверх
Anarki
Дата 30.7.2007, 16:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 326
Регистрация: 14.3.2005

Репутация: 1
Всего: 11



Цитата(sTa1kEr @  15.6.2007,  15:04 Найти цитируемый пост)
На 4ом не будет работать только функция stream_socket_client и соответственно асинхронное соединение. Вместо нее можно использовать обычный fsockopen. Все остальное будет работать и на 4ом PHP.

Единственное, что fsockopen может оказаться большим тормозом в такой системе, ибо он ресолвит имена и создает подключение и прервать никак нельзя. Поэтому для быстройдействия нужно будет отказаться от fsockopen и streams в сторону socket функций


--------------------
PM WWW   Вверх
teroni
Дата 6.10.2007, 12:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 381
Регистрация: 15.5.2007
Где: Днепропетровск

Репутация: 1
Всего: 22



sTa1kEr, можно вопросик по скрипту с потоками... Почему он так сервер грузит? У меня вот просто рефрешем страницы с этим скриптом (качается 6 потоков инфы каждый раз) Апач убивается за полчаса smile Причем не пойму, из-за чего... :(
PM MAIL   Вверх
sTa1kEr
Дата 6.10.2007, 13:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

Репутация: 11
Всего: 146



teroni, хм... не наблюдал такого. А что говорит top во время скрипта? Какой процесс грузит сервер и сколько съедает памяти? Как часто рефреш происходит?
PM MAIL   Вверх
Levsha
Дата 6.10.2007, 13:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 294
Регистрация: 30.9.2005

Репутация: нет
Всего: 4



teroni, использую скрипт 150-250 раз в день по 20 потоков уже месяца два. Никаких проблем.


--------------------
PM   Вверх
Ответ в темуСоздание новой темы Создание опроса

Внимание: данный раздел предназначен для решения сложных, нестандартных задач.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Для профи | Следующая тема »


 




[ Время генерации скрипта: 0.2156 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.