Мультипоточность в CURL (странности result 7)

Ответить
Аватара пользователя
metrik
Сообщения: 4
Зарегистрирован: 05.03.2015
Все бы ничего, но выявил нехорошую ошибку. было бы интересно узнать, делаю ли я что-то не так или это чисто баг cURL.
Что мы имеем мультипоточные запросы курла через PROXY - сервер.
Например PROXY - сервер: 123.456.789.012:3128
Страница запроса: mydomain.com:80

Код: Выделить всё

// инициализируем отдельное соединение (поток)
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_PROXY, $proxy);
    curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
curl_setopt($ch, CURLOPT_PORT, 80);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
            
curl_multi_add_handle($cmh, $ch);
  
// количество активных потоков
$active = null;
// запускаем выполнение потоков
do {
    $mrc = curl_multi_exec($cmh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);

// выполняем, пока есть активные потоки
while ($active && ($mrc == CURLM_OK)) {
    // если какой-либо поток готов к действиям
    if (curl_multi_select($cmh) != -1) {
        // ждем, пока что-нибудь изменится
        do {
            $mrc = curl_multi_exec($cmh, $active);
            usleep(10000);
            // получаем информацию о потоке
            $info = curl_multi_info_read($cmh);

            // если поток завершился
            if ($info['msg'] == CURLMSG_DONE) {
                if ($info['result']) {
                    // ОШИБКА
                }
                // удаляем поток из мультикурла
                curl_multi_remove_handle($cmh, $ch);
                // закрываем отдельное соединение (поток)
                curl_close($ch);
            }
        } while ($mrc == CURLM_CALL_MULTI_PERFORM);
    }
}
// закрываем мультикурл
curl_multi_close($cmh); 
! -код немного утрировал

В принципе все работает нормально, но ясное дело, что прокси из паблик-листов полудохлые.
И бывают случае когда подключение к прокси успешно, а запрашиваемая страница не возвращается.
В таком случае возвращается ошибка ($info['result'] равная 7), т.е. "Failed to connect mydomain.com:3128".
Смущает, что в таком случае показывается порт запрашиваемой страницы от PROXY - сервера. Почему? Может неправильно все-таки формирую поток в cURL ? Если проделать все тоже самое но без мультипоточности, то курл в такой ситуации возвращает правильный порт "Failed to connect mydomain.com:80".

Аватара пользователя
Distructor
Администратор
Сообщения: 1607
Зарегистрирован: 28.12.2009
Скорее всего баг. Не зря видимо добавили curl-multi-strerror в PHP 5.5

если цель узнать какие адреса не обработались и с какой ошибкой, то можно пойти по следующему пути:

Код: Выделить всё

$url = 'http://dynupdate.no-ip.com/ip.php';
$proxy = 'XXX.XXX.XXX.XXX:1080';

set_time_limit(65);

$aURLs = array($url, $url, $url); // array of URLs
$mh = curl_multi_init(); // init the curl Multi

$aCurlHandles = array(); // create an array for the individual curl handles

foreach ($aURLs as $id => $url) { //add the handles for each url
    
    $ch = curl_init(); // init curl, and then setup your options
    
    curl_setopt($ch, CURLOPT_PROXY, $proxy);
    curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
      
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); // returns the result - very important
    curl_setopt($ch, CURLOPT_HEADER, 0); // no headers in the output
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);

    $aCurlHandles[(int)$ch] = array('url' => $url, 'ch' => $ch, 'error' => '-');
    curl_multi_add_handle($mh, $ch);
}
    
$active = null;
//execute the handles
do {
    $mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);

$errors = array();
while ($active && $mrc == CURLM_OK) {
    if (curl_multi_select($mh) != -1) {
        do {
            $mrc = curl_multi_exec($mh, $active);
            $info = curl_multi_info_read($mh);
            if (false !== $info && $info['msg'] == CURLMSG_DONE) {
                $aCurlHandles[(int)$info['handle']]['error'] = $info['result'];
            }
        } while ($mrc == CURLM_CALL_MULTI_PERFORM);
    }
}
// еще раз
$info = curl_multi_info_read($mh);
if (false !== $info && $info['msg'] == CURLMSG_DONE) {
    $aCurlHandles[(int)$info['handle']]['error'] = $info['result'];
}
    
// iterate through the handles and get your content
foreach ($aCurlHandles as $data) {

    echo '<br>'.'url: '.$data['url'].'<br>';
    
    $ch = $data['ch'];
    if ($data['error'] != 0) {
        echo ' - Ошибка curl #'.$data['error'].': ' . curl_error($ch).'<br>';
    } else {
        echo ' - Успешно';
    }

    $html = curl_multi_getcontent($ch); // get the content
            
    curl_multi_remove_handle($mh, $ch); // remove the handle (assuming  you are done with it);
}

curl_multi_close($mh); // close the curl multi handler        
в результате получим результат вида

Код: Выделить всё

url: http://dynupdate.no-ip.com/ip.php
- Ошибка curl #7: Failed connect to dynupdate.no-ip.com:1080; No error

url: http://dynupdate.no-ip.com/ip.php
- Успешно

url: http://dynupdate.no-ip.com/ip.php
- Ошибка curl #7: Failed connect to dynupdate.no-ip.com:1080; No error 

Ответить