title
Description
Body
Решил написать очередной велосипед те расширение для php но хотел бы узнать мало ли может он уже существует.
В общем задача такова нужно получить данные с нескольких url по http но при этом что бы получение данных происходило одновременно со всех url а не по очередности.
так как PHP процедурный и блокирует сокеты.
Рою в React но что то пока что глухо в основном везде работа с сервером
Неактивен
В общем разобрался я с react. Довольно таки не плохая библиотека. Жаль что я раньше не узнал что php может работать с неблокирующими сокетами. Да и вообще удивительно что он может работать с ними на низком уровне.
Замутил такую функцию.
|
|
Результаты довольно таки не плохие
Неактивен
Gemorroj написал:
а чем нативный curl_multi_* не подошел?
спасибо.
Неактивен
Gemorroj curl_multi по результатам моих тестов во много раз медленнее чем напрямую работать с сокетами
|
|
Неактивен
Вот только столкнулся со следующей проблемой. Понятия не имею как работать с tls соединениями. Можно было бы использовать stream_socket_client но тут проблема с блокировкой сокета. Почему то не хочет сниматься блокировка с сокетов. Пробовал так
|
|
Неактивен
Короче я тут крутил крутил. И обратил внимание что используя ssl/tls протокол подключение значительно затягивается во времени раза в сто. Возможно что stream_socket_client используя ssl игнорирует параметр STREAM_CLIENT_ASYNC_CONNECT блокирует сокет пока не составит подпись только после делает его неблокирующим и возвращает управление.
Что то я нигде не найду примеры для эмуляции tls соединения на обычном сокете. А ввесь протокол перечитывать реально впадло.
Паша ты случаем не знаком с этим протоколом, как мне подготовить сокет для работы по ssl?
Желательно бы решить задачу с ssl так как api.vk.com работает через ssl а вот если отказаться от него то появляются новые проблемы нужно каждый запрос к вк подписывать. Это в принципе не проблема но все же хотел разобраться с защищенным соединением
Добавлено спустя 9 минут 16 секунд:
В общем если не разберусь буду юзать сурл для ssl
Неактивен
Gemorroj написал:
TLENS, нет, я не работал с сокетами на таком уровне. Я бы не заморачивался и использовал CURL
Ну да я все таки решил взяться за курл и не морочить себе мозги. А на будущее найму человека что бы переписал функцию под сокеты)
Неактивен
В общем запилил себе такой класс. Удобно работать.
|
|
Воспроизводится что то вроде этого.
|
|
Неактивен
Gemorroj написал:
а почему use не пользуешься, а пишешь неймспейсы постоянно?
Ну данный вызов класса находится в глобальной области. По этому и не юзал пространство. Да и вообще привычка не юзать прастранства. Видимо опасаюсь несовместимости.
Gemorroj написал:
код закрыт в целом?
Вообще то не планировал целый проект в публику выносить по соображениям безопасности. Но пока месть он то и не готов, только только формируется архитектура сайта. Потом может и сверкну гитхабом но только в приватном доступе.
Неактивен
TLENS написал:
В общем запилил себе такой класс. Удобно работать.
Код:
1
span style="color: #0000BB"><?phpnamespace Loader;require_once __DIR__ . '/_Link.php';require_once __DIR__ . '/_IP.php';/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. *//** * Description of Multi * * @author Dmitriy Bondarenko <TLENS at tlens.ru> */class Multi { //put your code here private $_timeout; private $_length = 0; /** @var array */ private $_links = array(); private $_callback = array(); private $_ch = array(); private $_chm; public function __construct($timeout = 10) { $this->_chm = curl_multi_init(); $this->_timeout = $timeout; $this->_length = 0; } public function addLink(\Loader\Link $link, $callback = null) { $this->_links[$this->_length] = $link; $this->_callback[$this->_length] = $callback; $this->_ch[$this->_length] = curl_init((string)$link); curl_setopt($this->_ch[$this->_length], CURLOPT_HEADER, false); curl_setopt($this->_ch[$this->_length], CURLOPT_RETURNTRANSFER, true); curl_setopt($this->_ch[$this->_length], CURLOPT_TIMEOUT, $this->_timeout); if (\Loader\IP::V6 == $link->getIp()->type()) curl_setopt($this->_ch[$this->_length], CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); if ((string)$link->getIp()) curl_setopt($this->_ch[$this->_length], CURLOPT_INTERFACE, (string)$link->getIp()); switch ($link->scheme()) { case 'https': curl_setopt($this->_ch[$this->_length], CURLOPT_PORT, $link->port() ? $link->port() : '443'); curl_setopt($this->_ch[$this->_length], CURLOPT_SSL_VERIFYPEER, 0); curl_setopt($this->_ch[$this->_length], CURLOPT_SSL_VERIFYHOST, 0); break; case 'http': curl_setopt($this->_ch[$this->_length], CURLOPT_PORT, $link->port() ? $link->port() : '80'); break; default : break; } curl_multi_add_handle($this->_chm, $this->_ch[$this->_length]); $this->_length++; } public function run () { $rh = null; do { curl_multi_exec($this->_chm, $rh); curl_multi_select($this->_chm); } while ($rh > 0); $results = array(); for ($i = 0; $i < $this->_length; $i++) { $results[$i] = $this->_links[$i]->parser( curl_multi_getcontent($this->_ch[$i]), curl_getinfo($this->_ch[$i]), curl_error($this->_ch[$i])); if (gettype($this->_callback[$i]) == 'object') $this->_callback[$i]($results[$i]); } return $results; } }?>
Внес некоторые критические обновления в класс. На другой машине метод run() ни разу не выполнился быстрее чем за 1 сек. в логах как правило ~1.001. Пришлось подправить пару строк начиная с 99ой
|
|
Неактивен
Кстати только что допилил интересный класс для работы.
Теперь загружать данные можно просто как через file_get_contents но переданная ссылка добавляется в стек и начинает асинхронно загружаться вместе со всем стеком только тогда когда какие то данные понадобятся.
Используется он так:
|
|
ну и собственно сам класс)
|
|
Неактивен
а класс Link где?
мне кажется архитектура была бы более правильной если бы использование выглядело как-то так:
|
|
Неактивен
Ну собственно архитектура так и выглядит в классе CurlMulti.
А здесь используется агрегирование т.е. RemotData создан для упрощенного использования класса CurlMulti
|
|
|
|
И да слово "правильная" архитектура относительное.
Как тебе вообще такая архитектура?
|
|
Можно еще имплементировать от итераторов почему бы и нет. Но мне как то не по приколу этим страдать. Но рахитектура получается довольно таки гибкой и интересной.
Неактивен
Какая то каша получилась у меня. В ходе работы оказалось что он не совсем то и универсальный. В общем переписал все. Закрыл конструктор сделал класс синглтоном. И теперь курлмульти принимает не url а курловские дескрипторы (Разумеется добавил метод addUrl для дефолтной загрузки) так же отказался от Link и Ip. Еще добавил полезную штуку что бы функция добавления дескриптора возвращала ссылку на ячейку стека куда запишется результат каллбека типо:
$result =& CurlMulti::getInstance()->addUrl('http://example.com', $callback, $callbackError);
В ходе работы с ним заточу данный класс и может на гитхаб закину если будет время.
Неактивен
Да это проблема в архитектуре стек нужно переделать Просто у меня метод exec после исполнение всех callback функций закрывает все дескрипторы и очищает стеки. И если из каллбека я добавлю в стек какой то дескриптор. То мой мусорщик подумает что он уже загружен и тут же закроет и удалит его. Вместо переделывание класса из-за лени сделал костыль и обошелся без добавления ссылок на загрузку из каллбека. (Пишу что то вроде поискового паука те собираю данные с разных ресурсов)
Неактивен