SPL Iterators

Базовые понятия
Итераторы (Iterators) — это классы которые реализуют интерфейс Iterator. Реализация данного интерфейса необходима при организации доступа к циклическим структурам (массивы, списки и т.д.).

В SPL (Standard PHP Library) существует большое количество готовых классов, реализующих интерфейс Iterator.

Далее перечислены классы, которые непосредственно реализуют интерфейс Iterator: Traversable, IteratorAgregate, OuterIterator, RecursiveIterator. Остальные классы-итераторы SPL наследуют свои интерфейсы уже от них.

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

Так как интерфейс Iterator входит в библиотеку стандартных классов PHP (Standard PHP Library), то его реализация выполнена в исходниках самого интерпретатора (имеются в виду коды программы на языке «С»). Если выразить этот интерфейс на языке PHP, то он будет выглядеть так:

interface Iterator{
  public function current(); // возвращает значение текущего элемента
  public function key(); // возвращает значения текущего ключа элемента (индекс массива например)
  public function next(); // смещает указатель на следующий элемент
  public function rewind(); // смещает указатель на первый элемент
  public function valid(); // определяет наличие элемента (выполняется после next или rewind)
}


Итераторы могут быть использованы во многих областях программирования. Например, при обработке набора значений полученных из Базы данных или обработке значений массива, или обработке набора файлов и т.д.

Вспомогательные функции при работе с итераторами.

iterator_to_array(Iterator $iteratorObject) — возвращает содержимое объекта-итератора в виде массива.

iterator_count(Iterator $iteratorObject)) — возвращает количество элементов в объекте-итераторе.

Пример использования:


$a = Array('a', 'b', 'c');
$iterator = new ArrayIterator($a);
echo iterator_count($iterator); // Результат - 3


iterator_apply(Iterator iteratorObject, function callback, [user_data) — данная функция позволяет с помощью callback-а обработать каждый элемент содержащийся в объекте-итераторе.

Пример использования:

function print_entry($iteratorObject) {
   var_dump($iterator->current());
   return true;
}

$a = Array('a', 'b', 'c');
$iterator = new ArrayIterator($a);
iterator_apply($iterator, 'print_entry', array($iterator));


Если функция callback возвращает значение отличное от true перебор элементов объекта-итератора прекращается.

Поиск и сортировка файлов средствами PHP (SPL)

В старых версиях PHP для работы с файлами и каталогами предусмотрены такие функции как open_dir, read_dir и т.д. Начиная с 5-ой версии PHP для работы с файловой структурой намного удобнее использовать классы SPL (Standard PHP Library). Для наглядности предлагаю разобрать небольшой пример.

Допустим, нам необходимо просканировать дерево каталогов и найти в них все файлы. Затем полученный список нужно отсортировать в алфавитном порядке. Вот как эту задачу можно решить используя SPL:


$dirTree = new RecursiveDirectoryIterator("./testDir");
$sortedFileList = new FileSorterIterator(new RecursiveItertatorIterator($dirTree));

foreach($sortedFileList as $file) {
    echo $file->getFilename() . '<br />';
}


class FileSorterIterator extends SplHeap
{
        
    public function __constructor(Iterator $iterator) {
         foreach ($iterator as $item) {
        	if ($item->isFile()) { 
                  // отсеиваем директории, 
                  // так как в условиях нашей задачи нужно получить только список файлов
              	  $this->insert($item);
        	}
        }

    }

    public function compare($b,$a)
    {
        return strcmp($a->getFilename(), $b->getFilename());
    }
    
}


Как видите, пример получился очень простым. Если в старых версиях PHP приходилось самостоятельно отслеживать указатель на открытую директорию и своевременно его закрывать, то теперь всю «грязную» работу берут на себя классы SPL.

Теперь давайте разберемся какие классы SPL используются в примере:

Класс RecursiveDirectoryIterator
RecursiveDirectoryIterator — это класс SPL который рекурсивно просматривает заданную директорию и составляет дерево всех файлов и директорий. При создании класса нужно указать директорию в которой должен осуществляться поиск.

Для того, чтобы работать с построенным деревом используются стандартные функции интерфейса Iterator, а так же несколько специфичных для данного класса методов.

При работе с данным классом нужно помнить, что функции на подобие foreach перебирают только элементы файловой структуры, находящиеся в корне построенного дерева. Для того, чтобы перебрать элементы расположенные ниже по структуре (имеются в виду вложенные директории) следует использовать специальный класс RecursiveIteratorIterator.

Класс RecursiveIteratorIterator
RecuriveIteratorIterator — это класс созданный для последовательно перебора элементов древовидных итераторов. В нашем примере данный класс используется для того, чтобы обработать файлы расположенные в поддиректориях корневой директории.

Класс FileSorterIterator
FileSorterIterator — это пользовательский класс созданный на базе класса SplHeap. Данный класс нужен для того, чтобы отсортировать файлы в алфавитном порядке. Для этого, используется функция compare, которая содержит условие сортировки, исходя из которого и определяется место элемента в общем массиве.

Исключительные ситуации
Теперь, хочется пару слов сказать о том, что делать если в результате работы указанных классов возникает какая-то ошибка. Например, мы указали для сканирования несуществующую директорию:


$dirTree = new RecursiveDirectoryIterator("./noneExistDirectory");


При возникновении ошибки в работе SPL классов генерируется соответствующее исключение, в случае если эти исключения не обрабатываются, они приводят к останову работы программы в целом. Поэтому лучше предусмотреть обработку наиболее вероятных исключительных ситуаций в программе.

Исключительные ситуации обрабатываются следующим образом:


try{
     $dirTree = new RecursiveDirectoryIterator("./testDasdfsdf");
}catch(Exception $e) {
     var_dump($e->getMessage());
}


В примере вся обработка сводится к выводу сообщения о полученном исключении на экран — RecursiveDirectoryIterator::__construct(./testDasdfsdf): failed to open dir: No such file or directory. В реальном приложении такая обработка, естественно, не подходит, поэтому вместо вывода сообщений на экран стоит придумать, что-то посерьезнее.

Что такое PHP SPL

SPL — это набор стандартных библиотек PHP (Standard PHP Library) появившихся начиная с 5-ой версии PHP.
Если рассматривать SPL с позиции разработчика, то легко выделить шесть основных классов и интерфейсов, функционал которых расширяется в большом множестве классов-потомков.

Класс ArrayAccess
ArrayAccess — это интерфейс который позволяет создать классы которые будут вести себя как массивы. В других языках эта возможность наиболее часто предоставляется с помощью интерфейсов-счетчиков (indexer).

Класс Exception;
Exception — это родительский класс SPL для большого количества классов-потомков (LogicExeption, DomainEception, RangeException и т.д.), которые «выбрасываются» при наступлении той или иной исключительной ситуации.

Класс Iterator
Iterator — это интерфейс SPL который предназначен для реализации объектов с циклической структурой. Реализация данного интерфейса в разрабатываемых классах позволяет стандартным функциям PHP (например foreach) работать с пользовательскими объектами.

Класс IteratorAgregate
IteratorAgregate — это интерфейс SPL который содержит только один метод — «getIterator». Этот интерфейс позволяет не реализовывать в классе интерфейс «Itertator», а использовать вместо этого внешний итератор.

Класс Serializable
Serializable — это интерфейс который позволяет сериализовать любой объект с помощью функций Serialize и Unserrialize

Класс Traversable
Traversable — это служебный класс SPL который используется в интерфейсах Iterator и IteratorAgregate. Реализовать данный интерфейс в PHP-программе нельзя т.к. он реализован на урове C-кода интерпретатора PHP.

Кроме этого есть несколько других возможностей таких как шаблон проектирования «observer», вспомогательные функции для идентификации объекта и для работы с итераторами. Так же есть функционал позволяющий автоматизировать процесс загрузки классов и интерфейсов.

The requested operation has failed

Ошибка «The requested operation has failed» — это не совсем ошибка PHP, но очень часто появляется именно при попытке настроить Apache 2.2.x для работы с PHP, подключаемого в качестве модуля. В таком случае причин появления ошибки может быть несколько.

Во-первых, ошибка может проявляться в случае если используемый модуль PHP не совместим с версией Apache. Чтобы исключить данный вариант, рекомендую попытаться поискать в интернете и скачать модуль PHP более новой версии.

Во-вторых, очень часть Apache отказывается работать если на компьютере установлен Skype, тогда в последнем необходимо найти и отключить опцию «использовать порты 80 и 443 в качестве входящих альтернативных»;

В-третьих, причиной ошибки может быть неверный синтаксис конфигурационного файла httpd.conf. В таком случае найти и устранить ошибку без соответствующей подготовки очень трудно. Поэтому начинающим рекомендую скачать и установить пакет «Денвер.

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

Call to undefined function curl init

Если Вы попали на эту страницу, значит у Вас есть проблема и имя этой проблемы: «Call to undefined function curl init». Так как ошибка среди Веб-программистов очень распространенная, то смею предположить следующее:

1.Вы начинающий веб-программист и с ошибкой «Call to undefined function curl init» сталкиваетесь впервые;
2.Как начинающий программист, Вы работаете в популярном пакете «Денвер»;
3.Опыта работы с CURL у Вас нет.

Если все сказанное — это про Вас, то вполне вероятно я смогу помочь Вашему горю.

Шаг первый. Проверяем установлен ли у нас CURL

В подавляющем большинстве случаев ошибка «Call to undefined function curl init» появляется по причине того, что у Вас просто напросто не установлен CURL. Что бы проверить так ли это, пишем небольшой скрипт:


<?php
phpinfo();
?>


Сохраняем его под именем «info.php» в корне вашего сайта и открываем в браузере страницу с адресом «имя_вашего_сайта/info.php». Далее открываем окошко поиска по странице и вбиваем слово «curl». Если в результате поиска Вы ничего не нашли, то поздравляю — CURL у Вас не установлен.

Шаг второй. Устанавливаем CURL

Итак, самый простой способ установить библиотеку CURL под Денвер — это скачать файл «php_curl.dll» и разместить его в Денвере по следующему пути «usr/local/php5/ext/php_curl.dll».

После чего зайти в файл php.ini, найти и раскоментировать строку «extension=php_curl.dll» и перезапустить «Денвер».

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

Шаг третий. Что делать если все сказанное выше не помогло

Бывает и такое, что после всех усилий проблема «Call to undefined function curl ini» не решается. В таком случае рекомендую сделать следующее:

Во-первых, проверить, что параметр «extension_dir» в php.ini указывает на директорию «usr/local/php5/ext/».
Во-вторых, попробовать скачать другой файл «php_curl.dll».

Если указанные действия не помогли, то пишите в комментарии о Вашей проблеме, и мы обязательно поможем вашему горю!

Передача переменных в PHP Array

Хотелось бы поделиться информацией о том, как можно передавать переменные в конструктор конструкции array(). Не могу сказать, что информация полезная, но может быть кому-то она покажется забавной.

На практике очень часто возникает задача инициализировать массив с помощью заранее созданных переменных. Для этого как правило используется следующая конструкция:


$someVar = 'Значение 1';

$arr = array(
     $someVar
);


Но кроме этого метода существует еще один, вполне законный метод сделать тоже самое:


$someVar = 'Значение 2';
$arr = array( 
       "$someVar"
);


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

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

Работа с массивами в PHP

Один из самых используемых инструментов в языке PHP — это массивы. Поэтому, важно не только знать что такое массив, но и уметь правильно пользоваться тем разнообразием функций, которые предлагает PHP при обработке массивов.

Прежде чем перейти к основной теме статьи хочется дать один простой, но очень важный совет всем начинающим веб-программистам. (Этот совет настолько важен, что я даже позволил себе нарушить порядок изложения материала).

Если Вы программируете на PHP и у Вас появилась необходимость обработать данные сохраненные в массиве. Прежде чем писать собственную функцию обработки, проверьте что Ваша задача точно не может быть решена стандартными функциями PHP.


Помните, для действительно важных и часто встречающихся задач при обработке массивов существуют готовые функции и конструкции языка, которые созданы с единственной целью — максимально ускорить работу скриптов.

Вероятность того, что Ваша задача уникальна и требует особого решения крайне мала. Даже если задача не решается с помощью одной функции, постарайтесь разбить ее на несколько более простых частей и использовать готовые функции PHP.

Теперь, после того, как мы уяснили важность использования стандартных функций PHP для обработки массивов давайте вернемся к теме статьи.

Что такое массив?

Так как эта статья рассчитана на новичков, то и начать стоит с определения того, чем же все-таки является массив. Вот мое вольное определение массива:

Массив — это переменная содержащая набор различных значений, доступных по уникальному индексу (индекс элемента массива).


Как в PHP создать массив

В PHP массив создается с помощью служебного слова array(). Существуют два варианта создания массива — это создание «пустого» массив и массива с предопределенными величинами:


$emptyArr = array(); // «пустой» массив
$someArr = array( 1, 2, 'Москва' ); // массив состоящий из элементов чисел «1», «2» и слова «Москва»;


В данном пример хотелось бы обратить внимание, на несколько вещей:

Во-первых, переменные, содержащиеся в массиве, могут быть разных типов. Так в массиве $someArr содержатся две целочисленные переменные и одна строковая.

Во-вторых, в приведенном определении массива, говорилось о том, что каждый элемент должен иметь уникальный индекс, а в примере этих индексов не видно.

Все дело в том, что в случае если при создании массива индексы не указаны явно, они будут созданы автоматически. Каждому элементу будет сопоставлен индекс вычисленный по следующей формуле:

«индекс» = «порядковый номер элемента» — 1


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

$someArr = array( 100 => 1, 200 => 2, 'city' => 'Москва' );


В данном примере числу «1» сопоставлен индекс «100», числу «2» индекс «200», а слову «Москва» сопоставлен строковый индекс «city».

Таким образом, мы приходим к третьему выводу о том, что в PHP индексами массива могут быть не только целые числа, но и строковые значения.

Как получить элемент массива в PHP?

Удобство массива заключается в том, что с ним можно работать как с обычной переменной — т.е. передавать в функцию, присваивать одному массиву другой и т.д. Но рано или поздно встает задача получить один конкретный элемент массива. Тогда нужно использовать следующий синтаксис:


$someArr = array(1, 2, 'Москва');

echo $someArr[2]; // Москва
echo $someArr[1]; // 2


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

Теперь, что делать если нам нужно получить все элементы массива? Для этого в PHP есть специальная конструкция foreach.

Конструкция FOREACH

Как было сказано ранее, при работе с массивами в PHP лучше использовать стандартные функции и конструкциии языка, а не придумывать велосипед. Поэтому давайте познакомимся поближе с наиболее часто используемой конструкцией — foreach:


$someArr = array( 1, 2, 'Москва');
foreach($someArr as $index => $value) {
echo 'Индекс элемента массива = '. $index .', значение = '.$value; // выводит на экран значения всех переменных массива.

}


Как видите, все просто, сначала мы указываем имя конструкции — «foreach», затем в параметрах конструкции указываем имя массива, который нужно «перебрать» — «$someArr», а затем с помощью служебного слова «as», указываем какое какое имя будет у переменной содержащей индекс элемента массива — «$index» и значение элемента массива — $value.

Ограничения на Cookie

Давно хотел разобраться с тем какие ограничения накладывают браузеры на хранение куков (cookie). Сегодня смог выкроить на это время и провести несколько простых тестов. Так как на полноту эксперимента я не претендую, то для исследования взял только три браузера — Opera 9, FireFox 3, InternetExplorer 8. Далее о том, какие результаты получены.


Для начала я прошелся по стандартным вещам — максимальный суммарный размер данных для всех куков на один домен и их общее количество.

В плане размера все браузеры показали примерно одинаковые результаты — 4096 симовлов (это включая знак равенства и имя самой куки). Что касается количества, то тут результаты разные:

  •  FireFox 3 — 50 куков на домен;
  •  Opera 9 — 30 куков на домен;
  •  InternetExplorer — 50 куков на домен. (напомню, что в IE6 можно было хранить не более 20 куков на домен)



Затем, мне стало интересно, а что будет если количество куков, полученных от сервера, превысит указанные ограничения. Логично предположить, что в таком случае браузер удалит самую старую куку и добавит одну из новых. Данное предположение оказалось истинным только для IE8 и Opera 9, а вот FireFox повел себя странным образом начав удалять куки в произвольном порядке.

Последний вопрос, который меня интересовал заключается в следующем: существует ли ограничение на общее количество хранимых куков. Фактически я хотел определить сколько различных сайтов можно посетить не боясь, что часть куков будет потеряна. Может быть кто-то помнит, в Netscape-их спецификациях было указано, что суммарное количество хранимых куков должно быть не менее 300.

Прежде чем я приведу результаты проверки, пара слов о том как я ее проводил. Для имитации большого числа различных доменов, я внес в файл хостов (hosts) порядка 30 тыс. доменов, следующего вида «dXXXXX.ru», где вместо XXXXX — указывается порядковый номер домена. Затем, с помощью небольшого скрипта на JS, загруженного в браузере, я последовательно обошел все домены и установил максимально разрешенное количество куков. После чего, другим скриптом проверил какие куки были сохранены.

В итоге у меня получились следующие ограничения (еще раз обращаю внимание, что приведенные ниже цифры отражают максимальное количество куков, которое может запомнить браузер!):

  • FireFox 3 — 3000 куков;
  • Opera 9 — 65535 куков;
  • InternetExplorer — неограниченное число куков (мне надоело проверять после того как были успешно установлено 150 тыс. куков).



Честно говоря, меня очень разочаровал показатель полученный в FireFox, ведь при установке 50 куков на один домен можно хранить информацию только от 60 сайтов, а это мало. С другой стороны, на практике даже скромного значения в 3000 куков оказывается вполне достаточно. Главное понимать для чего нужны куки и как их правильно использовать.

Полученные сведения, еще раз доказывают, что использовать куки нужно без фанатизма, так как у них существуют весьма значительные ограничения (особенно в FireFox).

Пара мыслей об анлизе и планировании проекта

Давно уже хочется что-нибудь написать о том, с чего и как начинают программный проект «взрослые» дяди. Но все как-то руки не доходили. И вот час «Х» настал.

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

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

А проектирование, в свою очередь, заключается в поиске концептуального решения, обеспечивающего выполнение требований, но не затрагивает конкретной реализации.

Обычно анализ делят на две части — это «Анализ требований» и «Объектный анализ». В первом случае перед разработчиком ставят цель осознать, что нужно будет сделать, а во втором выделить объекты участвующие в проекте.

Как правило на ранних этапах разработки определить все нюансы проекта невозможно. Это связано с тем, что после реализации части проекта у заказчика возникают дополнительные требования, которые необходимо учитывать. Поэтому при разработке коммерческого ПО, в том числе и разработке крупных сайтов, используются итеративные походы. Т.е. весь проект бьют на небольшие участки — итерации, и в рамках каждой итерации выполняют полный цикл разработки — начиная с анализа заканчивая реализацией.

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

Для сбора требований удобно создавать небольшие истории о том как пользователь взаимодействует с системой, эти истории называются прецедентами. При этом детально прорабатываются только несколько прецедентов, а остальные делаются более общими.

Как получить HTTP заголовки с помощью WireShark

Шаг нулевой. Вступительный

Для того, чтобы получить заголовки HTTP запросов и ответов нам понадобится две вещи. Первое — это снифер WireShark. Второе — браузер который наиболее всего соответсвует вашему вкусу. В моем случае выбор пал на FireFox.

Но прежде чем начнем, давайте усвоим несколько вещей:

RFC 2616 (равно как и все остальные RFC) — лучше всего использовать как справочник, а не как учебник по HTTP протоколу.


Большая часть информации, описанной в RFC 2616 никогда Вам не понадобится.


Лучший способ научиться писать программы использующие HTTP-протокол — это посмотреть какие заголовки (и в каких случаях) используют другие аналогичные программы.


Суть всего сказанного сводится к тому, что если ты хочешь начать работу с HTTP-протоколом, то не забивай себе голову ерундой, а просто посмотри как эту же работу делают FireFox, Opera или IE.

Шаг первый. Теоретический

Для того, чтобы браузер мог получать информацию с веб-сервера используется протокол который называется HTTP (Hypertext Transfer Protocol). Данный протокол создавался для решения широкого круга задач, поэтому содержит некоторую избыточность. Например, кроме наиболее часто используемых в вебе методов "GET" и "POST", есть такие методы как "PUT", "DELETE" и другие. Которые, повторюсь, никогда вам не понадобятся.

При обращении к серверу программа-клиент (браузер) направляет запрос, который по сути является обычным текстом и состоит из нескольких строк. Первая строка — это метод, который нужно применить к ресурсу.

Например:
GET http://www.phptips.ru/pages/about HTTP/1.1

Далее идут параметры указанного метода. Так как теоретически параметров может быть очень много, давайте посмотрим какие реально используются браузером.

Шаг второй. Практический

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

Первым делом запускаем снифер WireShark и выбираем устройство которое будем «нюхать». В большенстве случаев — это сетевая карта, через которую идет работа с Интернетом. В появившемся окне сразу начнет сыпаться куча сообщений. Это все запросы которые отправляет и получает ваш компьютер. В зависимости от того сколько запущено сетевых приложений их может быть как очень много, так и очень мало:

Чтобы ограничить этот список в строке «Filter:» вводит аббревиатуру «http» и нажимаем «enter». В итоге у нас остаются только HTTP запросы:


Сейчас снифер собирает все HTTP запросы, которые получает компьютер. Для того, чтобы понять какие запросы уходят на конкретный адрес. Переходим в FireFox и набираем строку «www.phptips.ru», после чего смело жмем на «Enter».

Переключившись обратно на WireShark мы видим кучу сообщений направленных и полученных по HTTP запросу.

Для того, чтобы понять что было отправлено и получено браузером щелкаем правой кнопкой мыши по любому из сообщений и выбираем пункт «Follow TCP Stream». В итоге WireShark анализирует весь трафик и выдает нам ответ в отдельном окне. Где красным помечен запрос, который был отправлен на сервер, а синим ответ, полученный с сервера:

Теперь, когда заголовки получены остается понять, что с ними делать.

Шаг третий. Завершающий

Для начала посмотрим, на запрос, который был направлен на сервер:

GET / HTTP/1.1

Host: www.phptips.ru

User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; ru; rv:1.9.1b4) Gecko/20090427 Fedora/3.5-0.20.beta4.fc11 Firefox/3.5b4

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language: ru,en-us;q=0.7,en;q=0.3

Accept-Encoding: gzip,deflate

Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7

Keep-Alive: 300

Connection: keep-alive


здесь наиболее важны первые две строки: GET и HOST именно по ним, сервер понимает какую страницу нужно отдать клиенту. В данном случае — это корневая страница сайта www.phptips.ru.

Все остальное уже менее важно, в том смысле, что запрос скорее всего был бы корректно обработан и без оставшихся строк. Здесь браузер указывает информацию о себе (User-agent), в каком виде браузер готов принять ответ (accept), на каком языке может быть выдан контент (accept-language), как закодировать ответ (Accept-Encoding), в какой кодировке должно быть содержимое страницы (Accept-Charset), что соединение может быть не разорвано после передачи страницы (keep-alive).

Чтобы узнать о данных параметрах более подробно можно воспользоваться RFC.

Теперь об ответе сервера на данный запрос. Первой строкой идет информация о том, что страница найдена (HTTP/1.1 200 OK), а дальше параметры ответа. В качестве задания для самопроверки, рекомендую самостоятельно узнать, что это за параметры.

Вроде с одним запросом более или менее разобрались, что же делать дальше? А дальше нужно попробовать выполнить разные запросы в браузере — сходить на разные сайты или страницы, заполнить поисковую форму или форму регистрации. После чего внимательно проанализировать какие заголовки используются браузером в том или ином случае. В итоге их окажется не так, много. И работать с этим набором будет легко.