Параллельное выполнение запросов через сокеты?

Discussion in 'PHP' started by Darkweider, 19 Sep 2007.

  1. Darkweider

    Darkweider Elder - Старейшина

    Joined:
    8 Feb 2007
    Messages:
    142
    Likes Received:
    13
    Reputations:
    0
    Вообщем столкнулся с такой проблемой, хочу быстрый парсер страниц написать. Как парсить страницы понял и разобрался... Проблема в том что через file_get_contents() все тормозно получается, слышал что можно параллельно информацию получать через сокеты, т.е. выполнять сразу несколько запросов в нескольким сайтам... Даже пример нашел, но не могу понять как переделать его=\ под парсер... Пожалуйста помогите разобраться уже который день думаю как переделать... Как работают незаблокориванные соксы не могу понять че-то... Пример, очень распространенный...
    PHP:
    <?
    // путь, где расположены скрипты
    $path = "http://domain.com/path/";

    // число потоков
    $max_threads = 20;


    // инициализация

    $sockets = array();
    $done = false;

    // будем работать, к примеру с набором
    // ключевых слов

    $keywords = fopen("keywords.txt", 'r');

    // приступаем к многопоточной работе

    while (!$done)
    {
    // если обнаружен файл,
    // то прекращаем выполнение скрипта

    if (file_exists('stop-file'))
    die;

    // если число запущенных потоков меньше
    // разрешенного максимума
    // то запускаем потоки еще

    if ($max_threads > count($sockets))
    {

    if (!
    feof($keywords))
    {
    $buffer = array();

    // читаем ключевое слово
    // в реальности в этот массив можно
    // положить очень много всего
    // а не только одно ключевое слово…

    $buffer[] = trim(fgets($keywords));

    // задаем данные для запуска сокета
    // request.php - это тот файл,
    // которые делает “дело”

    $query_url = $path . 'request.php';
    $url_info = parse_url($query_url);

    $url_info[port] = ($url_info[port]) ? $url_info[port] : 80;
    $url_info[path] = ($url_info[path]) ? $url_info[path] : “/”;
    $url_info[query] = ($url_info[query]) ? “?” . $url_info[query] : “”;

    // пакуем данные для передачи
    // в генерирующий скрипт
    // использование serialize очень удобно,
    // так как позволяет
    // залить в request.php мегабайты данных

    $request = serialize($buffer);

    // формируем запрос для передачи по сокету

    $query = “POST ” . $url_info[path] . ” HTTP/1.1\r\n”;
    $query = $query . “Content-Type: text/xml\r\n”;
    $query = $query . “Host: ” . $url_info[host] . “\r\n”;
    $query = $query . “Content-length: ” . (strlen($request)) . “\r\n\r\n”;
    $query = $query . $request;

    // создаем сокет, переводим его
    // в неблокирующий режим и запускаем
    // обработчик запросов

    $errno = 0;
    $error = “”;

    $socket = fsockopen($url_info[host], $url_info[port], $errno, $error, 30);
    stream_set_blocking($socket, 0);
    stream_set_timeout($socket, 3600);
    fputs($socket, $query);

    // запоминаем запущенный сокет

    $sockets[md5(time())] = $socket;
    }
    }

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

    reset($sockets);
    while (
    $socket = current($sockets))
    {
    if (
    feof($socket))
    {
    // убиваем сокет, который отработал

    unset($sockets[key($sockets)]);
    }
    else
    {
    // читаем данные из сокета

    $temp = fgets($socket, 1000);
    }

    // обрабатываем следующий сокет

    next($sockets);
    }

    // делаем небольщую задержку,
    // иначе загруженность сервера
    // приближается к 100 процентам

    sleep(1);

    // если нет активных сокетов, то можно выходить

    if (count($sockets) == 0)
    $done = true;
    }

    fclose($keywords);

    die;
    ?>
     
  2. ant0ha

    ant0ha Elder - Старейшина

    Joined:
    22 May 2007
    Messages:
    130
    Likes Received:
    50
    Reputations:
    13
  3. Darkweider

    Darkweider Elder - Старейшина

    Joined:
    8 Feb 2007
    Messages:
    142
    Likes Received:
    13
    Reputations:
    0
    Вот еще нашел пример помогите кто-нибудь подробно разобраться неплохая может статья выйдет.... мало где нашел подробное описание.... Я конешно понимаю надо смотреть каменты и т.п. ,но все таки когда теретически понимаешь как это организуется, только тогда появлятся возможность написать что-то свое...
    PHP:
    < ?php
    $hosts 
    = array("host1.sample.com", "host2.sample.com");
    $timeout = 15;
    $status = array();
    $sockets = array();
    /* Инициируем соединения ко всем хостам одновременно */
    foreach ($hosts as $id => $host) {
        
    $s = stream_socket_client("$host:80", $errno, $errstr, $timeout, 
            
    STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT);
        if (
    $s) {
            
    $sockets[$id] = $s;
            
    $status[$id] = "in progress";
        } else {
            
    $status[$id] = "failed, $errno $errstr";
        }
    }
    /* Теперь ожидаем результат */
    while (count($sockets)) {
        
    $read = $write = $sockets;
        
    /* Вот она - магическая функция - пояснения ниже */
        
    $n = stream_select($read, $write, $e = null, $timeout);
        if (
    $n > 0) {
            
    /* доступные для чтения сокеты готовы отдать нам данные 
               или попытка провалилась 
            */
            
    foreach ($read as $r) {
                
    $id = array_search($r, $sockets);
                
    $data = fread($r, 8192);
                if (
    strlen($data) == 0) {
                    if (
    $status[$id] == "in progress") {
                        
    $status[$id] = "failed to connect";
                    }
                    
    fclose($r);
                    unset(
    $sockets[$id]);
                } else {
                    
    $status[$id] .= $data;
                }
            }
            
    /* доступные для записи сокеты могут принимать 
                HTTP-запросы 
            */
            
    foreach ($write as $w) {
                
    $id = array_search($w, $sockets);
                
    fwrite($w, "HEAD / HTTP/1.0rnHost: "
                    
    . $hosts[$id] .  "rnrn");
                
    $status[$id] = "waiting for response";
            }
        } else {
            
    /* ожидаем таймаут; подразумевается, что все сокеты, 
                ассоциированные с массивом $sockets не сработали 
            */
            
    foreach ($sockets as $id => $s) {
                
    $status[$id] = "timed out " . $status[$id];
            }
            break;
        }
    }
    foreach (
    $hosts as $id => $host) {
        echo 
    "Host: $hostn";
        echo 
    "Status: " . $status[$id] . "nn";
    }
    ?> 
    Помогите расписать по блокам...Вписываю какие-нибудь сайты,запускаю и все виснет...
     
    #3 Darkweider, 19 Sep 2007
    Last edited: 19 Sep 2007