Соединения. Постоянные соединения. Цель
Прежде чем установить постоянную связь, следует реализовать отдельное TCP соединение с тем, чтобы получить URL. Это увеличивает нагрузку HTTP серверов и вызывает перегрузку каналов. Использование изображений и другой связанной с этим информации часто требует от клиента множественных запросов, направленных определенным серверам за достаточно короткое время. Анализ этих проблем содержится в [7.30],[7.27], а результаты макетирования представлены в [7.26].
Постоянное HTTP соединение имеет много преимуществ.
При открытии и закрытии TCP соединений можно сэкономить время CPU и память, занимаемую управляющими блоками протокола TCP.
HTTP запросы и отклики могут при установлении связи буферизоваться (pipelining), образуя очередь. Буферизация позволяет клиенту выполнять множественные запросы, не ожидая каждый раз отклика и используя одно соединение TCP более эффективно и с меньшими потерями времени.
Перегрузка сети уменьшается за счет сокращения числа пакетов, сопряженных с открытием и закрытием TCP соединений, предоставляя достаточно времени для детектирования состояния перегрузки.
HTTP может функционировать более эффективно, так как сообщения об ошибках могут доставляться без потери TCP связи. Клиенты, использующие будущие версии HTTP, могут испытывать новые возможности, взаимодействуя со старым сервером, но после неудачи могут попробовать старую семантику. HTTP реализациям следует пользоваться постоянными соединениями.
Общие процедуры
Заметным различием между HTTP/1.1 и более ранними версиями HTTP является постоянное соединение, которое в HTTP/1.1 является вариантом, реализуемым по умолчанию. Поэтому, если не указано обратное, клиент может предполагать, что сервер будет поддерживать постоянное соединение.
Постоянное соединение обеспечивает механизм, с помощью которого клиент и сервер могут сигнализировать о закрытии TCP-соединения. Эта система сигнализации использует поле заголовка Connection. Как только поступил сигнал о закрытии канала, клиент не должен посылать какие-либо запросы по этому каналу.
Согласование
HTTP/1.1 сервер может предполагать, что HTTP/1.1 клиент намерен поддерживать постоянное соединение, если только в поле заголовка Connection не записана лексема close. Если сервер принял решение закрыть связь немедленно после посылки отклика, ему рекомендуется послать заголовок Connection, включающий лексему связи close.
Клиент HTTP/1.1 может ожидать, что соединение останется открытым, но примет решение, оставлять ли его открытым, на основе того, содержит ли отклик сервера заголовок Connection с лексемой close.
Если клиент или сервер посылает лексему close в заголовке Connection, этот запрос становится последним для данного соединения.
Клиентам и серверам не следует предполагать, что соединение будет оставаться постоянным для версий HTTP, меньших 1.1, если только не получено соответствующее уведомление.
Буферизация
Клиенты, которые поддерживают постоянное соединение, могут буферизовать свои запросы (то есть, посылать несколько запросов не дожидаясь отклика для каждого из них). Серверы должны посылать свои отклики на эти запросы в том же порядке, в каком они их получили.
Клиенты, которые предполагают постоянство соединения и буферизацию, немедленно после установления соединения должны быть готовы совершить повторную попытку установить связь, если первая буферизованная попытка не удалась. Если клиент совершает повторную попытку установления связи, он не должен выполнять буферизацию запросов, пока не получит подтверждения об установления постоянного соединения. Клиенты должны также быть готовы послать повторно свои запросы, если сервер закрывает соединение прежде, чем пришлет соответствующие отклики.
Проксисерверы
Особенно важно то, чтобы проксисерверы корректно использовали свойства поля заголовка Connection.
Проксисервер должен сигнализировать о постоянном соединении отдельно своему клиенту и исходному серверу (origin server) или другому прокси, с которым связан. Каждое постоянное соединение устанавливается только для одной транспортной связи.
Проксисервер не должен устанавливать постоянное соединение с HTTP/1.0 клиентом.
Практические соображения
Серверы обычно имеют некоторое значение таймаута, за пределами которого они уже не поддерживают более неактивное соединение. Проксисерверы могут сделать эту величины больше, так как весьма вероятно, что клиент создаст больше соединений через один и тот же сервер. Использование постоянных соединений не устанавливает никаких требований на величину этого таймаута для клиента или сервера.
Когда клиент или сервер хочет прервать связь по таймауту, ему следует послать корректное оповещение о закрытии соединения. Клиенты и серверы должны постоянно следить, не выдала ли противоположная сторона сигнал на закрытие канала, и соответственно реагировать на него. Если клиент или сервер не зафиксирует сигнал противоположной стороны, то будут бессмысленно тратиться ресурсы сети.
Клиент, сервер или прокси могут закрыть транспортный канал в любое время. Например, клиент может послать новый запрос во время, когда сервер решит закрыть пассивное соединение. С точки зрения сервера, состояние, которое предлагается закрыть, является пассивным, но с точки зрения клиента идет обработка запроса.
Это означает, что клиенты, серверы и прокси должны быть способны восстанавливаться после случаев асинхронного закрытия. Программа клиента должна заново открыть транспортное соединение и повторно передать неисполненный запрос без вмешательства пользователя, хотя агент пользователя может предложить оператору выбор, сопряженный с повторением запроса. Однако эта повторная попытка не должна повторяться при повторной неудаче.
Серверам следует всегда реагировать, по крайней мере, на один запрос при соединении, если это возможно. Серверам не следует закрывать соединение в процессе передачи отклика, если только не произошло отказа в сети или выключения клиента.
Клиенты, которые применяют постоянные соединения, должны ограничивать число одновременных связей, которые они поддерживают с конкретным сервером. Однопользовательскому клиенту рекомендуется поддерживать не более двух соединений с любым сервером или прокси. Прокси следует использовать до 2*N соединений с другим сервером или прокси, где N равно числу активных пользователей. Эти рекомендации призваны улучшить время отклика HTTP и исключить перегрузки Интернет и других сетей.
Требования к передаче сообщений
Общие требования
HTTP/1.1 серверам следует поддерживать постоянные соединения и использовать TCP механизмы контроля информационного потока для преодоления временных перегрузок, а не разрывать соединение в расчете на то, что клиент совершит повторную попытку. Последнее может усугубить сетевую перегрузку.
Клиент HTTP/1.1 (или более поздней версии), посылая тело сообщения, должен мониторировать сетевое соединение на наличие сигнала ошибки. Если клиент обнаружил состояние ошибки, он должен немедленно прервать передачу. Если тело передается с использованием блочной кодировки (chunked encoding), возможно применение фрагмента нулевой длины и пустой завершающей секции для обозначения преждевременного конца сообщения. Если телу предшествовал заголовок ContentLength, клиент должен разорвать соединение.
Клиент HTTP/1.1 (или более поздней версии) должен быть готов принять код статуса 100 (Continue — продолжить), за которым следует обычный отклик.
Сервер HTTP/1.1 (или позднейшей версии), который получает запрос от клиента HTTP/1.0 (или более ранней), не должен передавать отклик 100 ( continue — продолжение), ему следует или ждать нормального завершения запроса (таким образом, избегая его прерывания) или преждевременно разрывать соединение.
Клиентам следует запомнить номер версии, по крайней мере, сервера, с которым проводилась работа последним. Если клиент HTTP/1.1 получил отклик от сервера HTTP/1.1 (или позднейшей) и обнаружил разрыв соединения до получения какого-либо статусного кода, клиенту следует повторно попытаться направить запрос без участия пользователя. Если клиент действительно повторяет запрос, то должен:
сначала послать поля заголовка запроса, а затем
ждать, того, что сервер пришлет отклик 100 ( Continue ), тогда клиент продолжит работу, или код статуса, сигнализирующего об ошибке.
Если клиент HTTP/1.1 не получил отклика от сервера HTTP/1.1 (или более поздней версии), ему следует считать, что сервер поддерживает версию HTTP/1.0 или более раннюю и не использует отклик 100 ( Continue ). Если в этом случае клиент обнаруживает закрытие соединения до получения какого-либо статусного кода от сервера, следует повторить запрос. Если клиент повторил запрос серверу HTTP/1.0, ему нужно применить следующий алгоритм получения надежного отклика:
1. инициировать новое соединение с сервером;
2. передать заголовок запроса;
3. инициализировать переменную R для оценки задержки отклика сервера (roundtrip time) (например, на основе времени установления соединения), если RTT не доступно, ему присваивается значение 5 секунд;
4. вычислить T = RTT * (2N), где N равно числу предыдущих попыток запроса;
5. ждать в течение Т секунд или до прихода статуса ошибки (что наступит раньше);
6. если не получен сигнал ошибки, после T секунд передается тело запроса;
7. если клиент обнаруживает преждевременное прерывание связи, повторяется шаг 1 до тех пор, пока запрос не будет принят или будет получен сигнал ошибки, или пока нетерпеливый пользователь не завершит процесс посылки повторных запросов.
Вне зависимости от версии сервера, если получен статус ошибки, то клиент:
не должен продолжать операции и
должен прервать соединение, если процедура не завершена посылкой сообщения.
Клиент HTTP/1.1 (или более поздней версии), который обнаруживает разрыв соединения после получения флага 100 (Continue), но до получения какого-либо статусного кода, должен повторить запрос и не должен ждать отклика 100 (Continue), но может и делать это, если такие действия упрощают реализацию программы.
Метод определений
Набор общих методов для HTTP/1.1 определен ниже. Хотя этот набор может быть расширен, нельзя предполагать, что дополнительные методы следуют той же семантике для разных клиентов и серверов. Поле заголовка запроса Host должно присутствовать во всех запросах HTTP/1.1.