Curl и http/2 multiplex, или как я хотел пустить несколько запросов в 1 соединение

babahalki

Постоялец
Регистрация
6 Май 2016
Сообщения
247
Реакции
107
Привет.
Делаю либу для работы с удаленными файлами, а поскольку я сижу через очень долгий канал, каждое соединение добавляет по 150-200мс в итоге тестируя свою первую функцию filesize_remote() меня неприятно удивила задержка в 300мс, сначала 150мс первое соединение, а потом на еще 1 редирект 150мс. А я всего лишь увидел размер файла. Решил попробовать использовать http/2, сам протокол мне запустить удалось, но вот заставить curl использовать 1 соединение никак не получается.

Код:
<?php
    function callbackheader($ch, $hdr) { 

        //делим строку по двоеточию на 2 эл. максимум
        $v = explode(':', $hdr, 2);
        if(count($v) < 2){
            //если двоеточия не было, тогда оставим старый ключ и значение
            $key = 0;
               $val = explode(' ', trim($v[0]));
        }else{
            $key = strtolower($v[0]);
            $val = trim($v[1]);
        }
        $header[$key] = $val;
         print_r($header);
        return strlen($hdr); 
    } 

    function callbackdata($ch, $data) { 
        print $data;
        return strlen($data); 
    } 

        $src = 'https://www.xiaomi2buy.ru/files/products/12101.10x10.jpg';
        $ch = curl_init();
        $opt = array(
            CURLOPT_URL => $src, // устанавливаем URL
            CURLOPT_PIPEWAIT => 1, //1 to wait for pipelining/multiplexing
            CURLOPT_FOLLOWLOCATION => 1, //redirect to location header
            CURLOPT_MAXREDIRS => 10, //max redirects
            CURLOPT_HTTP_VERSION => 3, // пробуем использовать http/2
            CURLOPT_SSL_VERIFYHOST => 0, //отключаем проверку соответсвия имени на сертификате хосту
            CURLOPT_RETURNTRANSFER => 1, //вернуть результат через curl_exec($ch), а не на экран.
            CURLOPT_HEADERFUNCTION => 'callbackheader',
            CURLOPT_WRITEFUNCTION => 'callbackdata',
        );
        curl_setopt_array($ch, $opt);
       
        print '<PRE>';
        curl_exec($ch);
Даже в таком примере происходит 2 соединения, судя по показаниям netstat -atc на сервере.

А браузер нормально работает через 1 соединение, даже если вручную в адресной строке вводить разные адреса 1 хоста.

Кому удавался трюк?
 
Проверь версию курла и php
Starting in 7.43.0, libcurl fully supports HTTP/2 multiplexing

CURLOPT_PIPEWAIT TRUE для ожидания конвеера/мультиплексирования. Добавлено в cURL 7.43.0. Доступно с PHP 7.0.7

Но это мало чем поможет, потому как HTTP2 нужен для выполнения параллельных запросов к одному домену
У тебя происходит редирект твоего запроса с www. на domain и это 2 разных домена.

curl даже гораздо более ранних версий по умолчанию переиспользует соединение, и единственное, что для этого надо, это не создавать заново сеанс через curl_init();
Вот таким вот образом:
PHP:
        $src = 'https://www.xiaomi2buy.ru/files/products/12101.10x10.jpg';
        $ch = curl_init();
        $opt = array(
	        CURLOPT_URL => $src, // устанавливаем URL
	        CURLOPT_FOLLOWLOCATION => 0, //redirect to location header
	        CURLOPT_SSL_VERIFYHOST => 0, //отключаем проверку соответсвия имени на сертификате хосту
	        CURLOPT_RETURNTRANSFER => 1, //вернуть результат через curl_exec($ch), а не на экран.

        );
        curl_setopt_array($ch, $opt);
        curl_exec($ch);

		$src = 'https://www.xiaomi2buy.ru/';

		curl_setopt($ch, CURLOPT_URL, $src);
		curl_exec($ch);
курл получает 2 странички через одно соединение.

В твоём случае, проще будет убрать www
PHP:
$src = 'https://xiaomi2buy.ru/files/products/12101.10x10.jpg';
 
Проверь версию курла и php


Но это мало чем поможет, потому как HTTP2 нужен для выполнения параллельных запросов к одному домену
У тебя происходит редирект твоего запроса с www. на domain и это 2 разных домена.

curl даже гораздо более ранних версий по умолчанию переиспользует соединение, и единственное, что для этого надо, это не создавать заново сеанс через curl_init();

Спасибо.

Версии у меня вот:
curl 7.54.1
php 7.1.7

У меня пример специально упрощен, в реальности там все сложнее закручено. Это просто тренировка на кошках.

Действительно, если хост на 100% совпадает, то вроде как в 1 соединение все пускается. Выходит при редиректе, поскольку хост становится другим мне никак не избежать 2 соединений.
 
Назад
Сверху