Готовый перевод HttpClient 4.x (Tutorial) / HttpClient 4.x (Учебник): 2. Connection management (Диспетчер соединений)

Внимание! Этот перевод, возможно, ещё не готов, так как модераторы установили для него статус «идёт перевод»

Глава 2. Управление соединениями

HttpClient имеет полный контроль над процессами инициализации и прерывания соединения, а также над операциями ввода/вывода активных соединений. Однако различными аспектами соединений можно управлять с помощью ряда параметров.
2.1. Параметры соединения

Ниже представлены параметры, влияющие на операции над соединения:

'http.socket.timeout': определяет тайм-аут для сокета (SO_TIMEOUT), в миллисекундах (максимальный период между двумя последовательными пакетами данных, в течении которого сокет будет бездействовать). Значение 0 интерпретируется как бесконечное время ожидания.
Тип параметра: java.lang.Integer.
Значение по умолчанию: SO_TIMEOUT = 0. Операции чтения не будут иметь тайм-аут (бесконечно время ожидания).

'http.tcp.nodelay': определяет, будет ли алгоритм Nagle будет использоваться. Алгоритм Nagle пытается сохранить пропускную способность путем сведения к минимуму числа отправляемых сегментов. Когда вашему приложению нужно минимизировать задержки сети и повысить производительность, вы можете отключить алгоритм Nagle (т.е. enable TCP_NODELAY). Данные будут отправляться быстрее за счет увеличения пропускной способности.
Тип параметра: java.lang.Boolean.
Значение по умолчанию: TCP_NODELAY = enable (без задержки).

'http.socket.buffer-size': определяет размер внутреннего буфера сокета, использующегося для буферизации данных во время приема/передачи HTTP сообщений.
Тип параметра: java.lang.Integer
Значение по умолчанию: HttpClient выделит 8192 байт под буферы сокета.

'http.socket.linger': определяет SO_LINGER с указанным временем задержки в секундах. Максимальное значение тайм-аута зависит от платформы. Значение 0 означает, что опция отключена. Значение -1 означает, что используется значение по умолчанию для JRE. Настройка влияет только на операции закрытия сокета.
Тип параметра: int.
Значение по умолчанию: SO_LINGER = -1.

'http.connection.timeout': определяет тайм-аут для устанавливления соединения, в миллисекундах. Значение 0 интерпретируется как бесконечное.
Тип параметра: java.lang.Integer.
Значение по умолчанию: 0. Операции соединения не будут иметь тайм-аут (бесконечного ожидание).

'http.connection.stalecheck': определяет, нужно ли использовать проверку старых подключений. Отключение проверки старых подключений может привести к заметному улучшению производительности (проверка может вызывать до 30 миллисекунд накладныех расходов для каждого запроса), однако при этом есть риск ошибки ввода-вывода при выполнении запроса на соединение, которое было закрыто на стороне сервера. Для выполнения критических операций проверки должны быть отключены.
Тип параметра: java.lang.Boolean.
Значение по умолчанию: true. Cтарое соединение будет проверяться перед каждым выполнением запроса.

'http.connection.max-line-length': определяет максимальный предел длины линии. Если установлено в положительное значение, любая HTTP линия, превышающая этот предел, будет вызывать java.io.IOException. Отрицательное или нулевое значение будет одинаково отключить проверку.
Тип параметра: java.lang.Integer.
Значение по умолчанию: 0. Предел не определен.

'http.connection.max-header-count': определяет максимально допустимое количество HTTP заголовков. Если установлено положительное значение, и число HTTP заголовков, полученных из потока данных, превышает этот предел будет выброшено java.io.IOException. Отрицательное или нулевое значение будут одинаково отключать проверку.
Тип параметра: java.lang.Integer.
Значение по умолчанию: 0. Предел не определен.

ConnConnectionPNames.MAX_STATUS_LINE_GARBAGE='http.connection.max-status-line-garbage': определяет максимальное количество игнорируемых строк перед ожидаемой строкой статуса HTTP-ответа. С HTTP/1.1 постоянными соединениями возникает проблема, когда сломанный сценарий может вернуть неверный Content-Length (послать больше байт, чем указано). К сожалению, в некоторых случаях, это не может быть обнаружено сразу после плохого ответа, а лишь перед следующим ответом. Таким оборазом, HttpClient должны быть в состоянии пропустить эти лишнии строки.
Тип параметра: java.lang.Integer.
Значение по умолчанию: java.lang.Integer.MAX_VALUE.
Значение: 0. Устанавливает запрет на какие-либо мусорные/пустые строки перед строкой состояния.
Значение: java.lang.Integer.MAX_VALUE. Устанавливает неограниченное число мусорных/пустых строк перед строкой состояния.

2.2. Постоянные соединения

Процесс установления соединения одного хоста с другим является довольно сложным и включает в себя несколько обменов пакетов между двумя конечными точками, которые могут занимать довольно много времени. Накладные расходы на «рукопожатия» соединения могут быть значительными, особенно для небольших HTTP сообщений. Можно добиться гораздо более высокой пропускной способности, если открывать соединения, которые могут быть использованы повторно, выполняющие несколько запросов.

HTTP/1.1 заявляет, что HTTP соединения могут быть использованы повторно для нескольких запросов по умолчанию. HTTP/1.0 совместимые хосты также могут использовать аналогичный механизм явно сообщить свои предпочтения поддерживать соединение и использовать его для нескольких запросов. HTTP агенты также могут удерживать простаивающие соединения действующими в течение определенного периода времени в случае если для последующих запросов понадобится соединение с тем же самым хостом. Способность сохранять соединения действующими, как правило, называют постоянство соединения. HttpClient полностью поддерживает постоянные соединения.

2.3. Маршрутизация HTTP-соединений

HttpClient в состоянии наладить связь с целевым хостом либо непосредственно, либо через маршрут, который может включать несколько промежуточных соединений также называемях хопами (hops). HttpClient различает соединения по обычному туннелированому и уровневому маршрутам. Использование нескольких промежуточных прокси-серверов для туннеллирования соединения к хост называется цепочкой прокси.

Обычные маршруты устанавливаются путем непосредственного соединения с целевым хостом или через единственный прокси. Туннелированые маршруты устанавливаются путем подключения к первому прокси туннелирование через цепочку прокси-серверов до цели. Маршруты без прокси не могут быть туннелированными. Уровневые маршруты устанавливаются слоев протокол в существующее соединение. Протоколы могут быть только уровневыми по туннелю к цели, или через прямое соединение без прокси.
2.3.1. Вычисление маршрута

Интерфейс RouteInfo представляет информацию о точном маршруте к целевому хосту, включая одно или несколько промежуточных шагов или хопов. HttpRoute является конкретной реализацией RouteInfo, которая не может быть изменена (неизменна). HttpTracker является изменяемой реализацией RouteInfo, исползуемой внутри HttpClient отслеживать остальные прыжки с конечной целью маршрута. HttpTracker может быть обновлен после успешного выполнения следующего шага в направлении маршрута цели. HttpRouteDirector является вспомогательным классом, который может быть использован для вычисления следующего шага маршрута. Этот класс предназначен для внутреннего использования HttpClient.

Интерфейс HttpRoutePlanner представляет стратегию для вычисления полного пути к требуемой цели на основе контекста выполнения. HttpClient умолчанию поставляется с двумя реализациями HttpRoutePlanner. Реализация ProxySelectorRoutePlanner основана на java.net.ProxySelector. По умолчанию, он будет брать настройки прокси из JVM, либо из свойств системы или из браузера, запустившего приложение. Реализация DefaultHttpRoutePlanner не использует ни системные свойства Java, ни свойства самой системы или настройки прокси из браузера. Она вычисляет маршруты, основываясь исключительно на параметрах HTTP, описанных ниже.

2.3.2. Защищенные HTTP-соединения

HTTP-соединения можно считать безопасным, если информация, передаваемая между двумя конечными точками соединения не могут быть прочитаны или изменены неуполномоченным третьим лицом. SSL/TLS протокол является наиболее широко используемой техникой для обеспечения безопасности HTTP-транспортировки. Однако, могут быть использованы и другие методы шифрования. Обычно, над HTTP транспортировкой надстраивают уровень SSL/TLS для зашифрованных соединений.

2.4. Параметры HTTP-маршрута

На вычисление маршрута могут влиять следующие параметры:

'http.route.default-proxy': определяет прокси-сервер, который будет использоваться планировщиками маршрутов по умолчанию, которые не используют настройки JRE.
Тип параметра: HttpHost.
Значение по умолчанию: Будет предпринята попытка непосредственного соединение с целевым хостом.

'http.route.local-address': определяет локальный адрес, которые будут использоваться всеми планировщиками маршрутов по умолчанию. На машинах с несколькими сетевыми интерфейсами, этот параметр может быть использован для выбора сетевого интерфейса, через который происходит соединение.
Тип параметра: java.net.InetAddress.
Значение по умолчанию: Локальный адрес будет задаваться автоматически.

'http.route.forced-route': определяет вынужденный маршрут, который будет использоваться всеми планировщиками маршрутов по умолчанию. Вместо вычисления маршрута будет возвращен данный вынужденный маршрут, даже если он указывает на совершенно другой целевой хост.
Тип параметра: HttpRoute.

2.5. Фабрики сокетов

HTTP-соединения внутренне используют объекты java.net.Socket для управления передачей данных по сети. Они, однако, полагаться на интерфейс SocketFactory для создания, инициализации и подключения сокетов. Это позволяет пользователям HttpClient реализовавать специфичный для приложения код инициализации сокета во время выполнения. PlainSocketFactory является фабрикой по умолчанию для создания и инициализации простого(без шифрования) сокета.

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

PlainSocketFactory sf = PlainSocketFactory.getSocketFactory();
Socket socket = sf.createSocket();

HttpParams params = new BasicHttpParams();
params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 1000L);
sf.connectSocket(socket, "locahost", 8080, null, -1, params);

2.5.1. Уровневые защищенные сокеты

LayeredSocketFactory расширяет интерфейс SocketFactory. Фабрики уровневых сокетов способны создавать сокеты, которые образуют дополнительный уровень над существующими простыми сокетами. Уровневые сокеты используются в основном для создания безопасных соединений через прокси. HttpClient содержит SSLSocketFactory, который реализует SSL/TLS уровни. Пожалуйста, обратите внимание, что HttpClient не использует какие-либо собственные функции шифрования. Он полностью зависит от стандартных Java Cryptography (JCE) и Secure Sockets (JSEE) расширений.

2.5.2. SSL/TLS настройки

HttpClient использует SSLSocketFactory для создания SSL-соединения. SSLSocketFactory позволяет выполнить настройку очень гибко. Она может принять экземпляр javax.net.ssl.SSLContext в качестве параметра и использовать его для создания соединений SSL с пользовательскими настройками.

TrustManager easyTrustManager = new X509TrustManager()
{

@Override
public void checkClientTrusted( X509Certificate[] chain, String authType) throws CertificateException
{
// Oh, I am easy!
}

@Override
public void checkServerTrusted( X509Certificate[] chain, String authType) throws CertificateException
{
// Oh, I am easy!
}

@Override
public X509Certificate[] getAcceptedIssuers()
{
return null;
}

};

SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(null, new TrustManager[]
{
easyTrustManager
}, null);

SSLSocketFactory sf = new SSLSocketFactory(sslcontext);
SSLSocket socket = (SSLSocket) sf.createSocket();
socket.setEnabledCipherSuites(new String[]{ "SSL_RSA_WITH_RC4_128_MD5" });

HttpParams params = new BasicHttpParams();
params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 1000L);
sf.connectSocket(socket, "locahost", 443, null, -1, params);

Адаптация SSLSocketFactory подразумевает определенную степень знакомства с концепциями SSL/TLS протокола, подробное описание которого выходит за рамки этого документа. Пожалуйста, обратитесь к Java Secure Socket Extension за более подробным описанием javax.net.ssl.SSLContext и связанными с ними инструментами.

2.5.3. Проверка имени хоста

В дополнение к проверке доверия и аутентификации клиента осуществляется на SSL/TLS уровне протокола, HttpClient дополнительно можно проверить совпадения имен целевых хостов хранятся в сертификат X.509 сервера, когда соединение было установлено. Эта проверка может обеспечить дополнительные гарантии подлинности материала доверия сервера. X509HostnameVerifier интерфейс представляет стратегию для хоста проверки. HttpClient поставляется с тремя X509HostnameVerifier. Важно: имя хоста проверки не следует путать с проверкой доверия SSL.

StrictHostnameVerifier: строгий верификатор имени хоста работает так же, как Sun Java 1.4, Sun Java 5, Sun Java 6. Это также довольно близко к IE6. Эта реализация, как представляется, совместимый с RFC 2818 для работы с маски. Имя должно совпадать с первым CN, или любой из предмета альтов. Шаблон может произойти в CN, и в любом из предмета альтов.

BrowserCompatHostnameVerifier: имя верификатор, который работает так же, как Керл и Firefox. Имя должно совпадать с первым CN, или любой из предмета альтов. Шаблон может произойти в CN, и в любом из предмета альтов. Единственное различие между BrowserCompatHostnameVerifier и StrictHostnameVerifier в том, что шаблон (например, "*. foo.com") с BrowserCompatHostnameVerifier матчи все поддомены, в том числе "abfoo.com".

AllowAllHostnameVerifier: Это имя верификатор существу превращается хоста проверки с. Эта реализация не-оп, и никогда не бросает javax.net.ssl.SSLException.

По умолчанию HttpClient использует реализацию BrowserCompatHostnameVerifier. При желании можно задать другие реализации верификации хоста.

SSLSocketFactory sf = new SSLSocketFactory(SSLContext.getInstance("TLS")); sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);

2.6. Схемы протоколов

Класс Scheme представляет схемы протоколов, такие как "HTTP" или "HTTPS", и содержит ряд свойств протоколов, таких как порт по умолчанию и фабрику сокетов, которая будет использоваться для создания экземпляров java.net.Socket для данного протокола. Класс SchemeRegistry используется для поддержания набора объектов Scheme, из которого экземпляр HttpClient может выбирать при попытке установить соединение с требуемым URI:

Scheme http = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80);

SSLSocketFactory sf = new SSLSocketFactory(SSLContext.getInstance("TLS")); sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER); Scheme https = new Scheme("https", sf, 443);

SchemeRegistry sr = new SchemeRegistry(); sr.register(http); sr.register(https);

2.7. Конфигурация прокси в HttpClient

Хотя HttpClient поддерживает комплекс маршрутизации scemes и цепочки прокси, он поддерживает только простые непосредственные соединения или соединения через единственный прокси "из коробки".

Самый простой способ указать экземпляру HttpClient подключаться к целевому хосту через прокси-сервер — установить значение параметра прокси-сервера по умолчанию:

DefaultHttpClient httpclient = new DefaultHttpClient();

HttpHost proxy = new HttpHost("someproxy", 8080); httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);

Можно также указать экземпляру HttpClient использовать стандартный JRE прокси-селектор для получения информации о прокси:

DefaultHttpClient httpclient = new DefaultHttpClient();

ProxySelectorRoutePlanner routePlanner = new ProxySelectorRoutePlanner( httpclient.getConnectionManager().getSchemeRegistry(), ProxySelector.getDefault()); httpclient.setRoutePlanner(routePlanner);

Кроме того, можно предоставить собственную реализацию RoutePlanner, чтобы иметь полный контроль над процессом вычисления маршрута HTTP:

DefaultHttpClient httpclient = new DefaultHttpClient(); httpclient.setRoutePlanner(new HttpRoutePlanner() {

public HttpRoute determineRoute( HttpHost target, HttpRequest request, HttpContext context) throws HttpException { return new HttpRoute(target, null, new HttpHost("someproxy", 8080), "https".equalsIgnoreCase(target.getSchemeName())); }

});

2.8. Диспетчеры HTTP-соединений

2.8.1. Операции над соединениями

Оперируемые соединения — это соединения на стороне клиента, для которых предусмотрена возможность манипулирования сокетами, лежащими в их основе, или их состоянием посредством внешних компонентов, обычно называемых операторами соединений. Интерфейс OperatedClientConnection расширяет интерфейс HttpClientConnection и определяет дополнительные методы для управления сокетом соединения. Интерфейс ClientConnectionOperator представляет стратегию для создания экземпляров OperatedClientConnection и обновления сокетов, лежащих в основе этих экземпляров. Реализации будут, скорее всего, использовать SocketFactory для создания экземпляров java.net.Socket.
Интерфейс ClientConnectionOperator позволяет пользователям HttpClient определять собственную стратегию для операторов соединений, а также возможность определять альтернативные реализации интерфейса OperatedClientConnection.

2.8.2. Управление соединениями и диспетчеры соединений

HTTP соединения являются сложными, хранящими состояние, поточно-опасными объектами, которые, для правильной работы, должны быть надлежащим образом сконфигурированы. HTTP соединения могут быть использованы лишь одним потоком одновременно. HttpClient использует специальный компонент для управления доступом к HTTP соединениям, называемый диспетчер HTTP соединения и представленный интерфейсом ClientConnectionManager. Цель диспетчера HTTP соединений состоит в том, чтобы служить фабрикой для новых HTTP соединений, управлять постоянными соединениями и синхронизировать доступ к ним, убедившись, что лишь один поток может иметь доступ к соединению одновременно.

Внутренне диспетчеры HTTP соединений работают с экземплярами OperatedClientConnection, но пользователям сервиса они передают экземпляры ManagedClientConnection. ManagedClientConnection выступает в качестве оболочки для экземпляра OperatedClientConnection, которая управляет его состоянием и контролирует все операции ввода/вывода для этого соединения. Он также абстрагирует от операций непосредственно над сокетом и предоставляет удобные методы для открытия сокета, а также его обновления для установки маршрута. Экземпляры ManagedClientConnection поддерживают связь с диспетчером соединений, который их создал, и осведомлены, что они должны быть возвращены обратно диспетчеру, когда они больше не используются. Классы ManagedClientConnection также реализуют интерфейс ConnectionReleaseTrigger, который может быть использован для активации процесса освобождения соединения и возвращения его обратно диспетчеру. После того, как был активирован процесс освобождения соединения, обернутое соединение получает сигнал к отделению от оболочки ManagedClientConnection и экземпляр OperatedClientConnection возвращается к диспетчеру. Хотя обслуживание пользователей по-прежнему содержит ссылку на экземпляр ManagedClientConnection, он уже не в состоянии выполнить какие-либо операции ввода/вывода или изменения состояния OperatedClientConnection умышленно или неумышленно. Ниже представлен пример получения соединения от диспетчера соединений:

Вот пример получения экземпляра соединения от диспетчера соединений:

HttpParams params = new BasicHttpParams(); Scheme http = new Scheme("http", PlainSocketFactory.getSocketFactory(), 80); SchemeRegistry sr = new SchemeRegistry(); sr.register(http);

ClientConnectionManager connMrg = new SingleClientConnManager(params, sr);

// Request new connection. This can be a long process
ClientConnectionRequest connRequest = connMrg.requestConnection( new HttpRoute(new HttpHost("localhost", 80)), null);

// Wait for connection up to 10 sec.
ManagedClientConnection conn = connRequest.getConnection(10, TimeUnit.SECONDS);
try
{
// Do useful things with the connection.
// Release it when done.
conn.releaseConnection();
}
catch (IOException ex)
{
// Abort connection upon an I/O error.
conn.abortConnection();
throw ex;
}

Запрос на соединение может быть прекращен, досрочно лишь вызвать метод ClientConnectionRequest.abortRequest(), если это необходимо. Это позволит разблокировать поток заблокированный в методе ClientConnectionRequestgetConnection().

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

ClientConnectionRequest connRequest = connMrg.requestConnection( new HttpRoute(new HttpHost("localhost", 80)), null); ManagedClientConnection conn = connRequest.getConnection(10, TimeUnit.SECONDS); try { BasicHttpRequest request = new BasicHttpRequest("GET", "/"); conn.sendRequestHeader(request); HttpResponse response = conn.receiveResponseHeader(); conn.receiveResponseEntity(response); HttpEntity entity = response.getEntity(); if (entity != null) { BasicManagedEntity managedEntity = new BasicManagedEntity(entity, conn, true); // Replace entity response.setEntity(managedEntity); } // Do something useful with the response // The connection will be released automatically // as soon as the response content has been consumed } catch (IOException ex) { // Abort connection upon an I/O error. conn.abortConnection(); throw ex; }

2.8.3. Простой диспетчер соединений

SingleClientConnManager является простым диспетчером соединений, который поддерживает только одно соединение единовременно. Хотя этот класс является поточно-ориентированным, тем не менее, он должен быть использован лишь одним потоком выполнения. SingleClientConnManager старается повторно использовать соединения для последующих запросов с тем же маршрутом. Однако, он закроет существующее соединение и откроет его для требуемого маршрута, если маршрут постоянного соединения не совпадает с маршрутом запроса на соединение. Если соединение уже было выделено выбрасывается исключение java.lang.IllegalStateException.

HttpClient использует SingleClientConnManager по умолчанию.

2.8.4. Диспетчер соединений, организующий пул соединений

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

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

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

HttpParams params = new BasicHttpParams();
// Increase max total connection to 200
ConnManagerParams.setMaxTotalConnections(params, 200);
// Increase default max connection per route to 20
ConnPerRouteBean connPerRoute = new ConnPerRouteBean(20);
// Increase max connections for localhost:80 to 50
HttpHost localhost = new HttpHost("locahost", 80);
connPerRoute.setMaxForRoute(new HttpRoute(localhost), 50);
ConnManagerParams.setMaxConnectionsPerRoute(params, connPerRoute);

SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register( new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register( new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));

ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
HttpClient httpClient = new DefaultHttpClient(cm, params);

2.8.5. Отключение диспетчера соединений

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

DefaultHttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet("http://www.google.com/");
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
System.out.println(response.getStatusLine());
if (entity != null)
{
entity.consumeContent();
}
httpclient.getConnectionManager().shutdown();

2.9. Параметры диспетчера соединений

Для настройки стандартных реализаций диспетчеров HTTP-соединений используются следующие параметры:

'http.conn-manager.timeout': определяет время ожидания в миллисекундах используемое для получения экземпляра ManagedClientConnection от ClientConnectionManager.
Тип параметра: java.lang.Long.
Значение по умолчанию: 0. Тайм-аут не установлен (бесконечное ожидание).

'http.conn-manager.max-per-route': определяет максимальное количество соединений для определенного маршрута. Этот предел интерпретируется диспетчером клиентских подключений и распространяется на отдельные экземпляры диспетчеров.
Значение по умолчанию: ConnPerRoute.

"http.conn-manager.max-total": определяет максимальное количество соединений в целом. Этот предел интерпретируется диспетчерами клиентских подключений и распространяется на отдельные экземпляры менеджеров.
Тип параметра: java.lang.Integer.

2.10. Многопоточное выполнение запроса

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

ThreadSafeClientConnManager выделяет соединения, в зависимости от своей конфигурации. Если все соединения для требуемого маршрута уже были задействованы, запрос на подключение будет заблокирован до того, как какое-либо из соединений будет освобождено и передано обратно в пул. Можно указать Connection Manager, чтобы запрос на подключение не блокировался на неопределенное время, установив свойство "http.conn-manager.timeout" в положительное значение. Если запрос на соединение не может быть обслужен в течение определенного периода времени, будет выброшено исключение ConnectionPoolTimeoutException.

HttpParams params = new BasicHttpParams();
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register( new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));

ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
HttpClient httpClient = new DefaultHttpClient(cm, params);

// URIs to perform GETs on
String[] urisToGet =
{
"http://www.domain1.com/", "http://www.domain2.com/", "http://www.domain3.com/", "http://www.domain4.com/"
};

// create a thread for each URI
GetThread[] threads = new GetThread[urisToGet.length];
for (int i = 0; i < threads.length; i++)
{
HttpGet httpget = new HttpGet(urisToGet[i]);
threads[i] = new GetThread(httpClient, httpget);
}

// start the threads
for (int j = 0; j < threads.length; j++)
{
threads[j].start();
}

// join the threads
for (int j = 0; j < threads.length; j++)
{
threads[j].join();
}

static class GetThread extends Thread
{

private final HttpClient httpClient;
private final HttpContext context;
private final HttpGet httpget;

public GetThread(HttpClient httpClient, HttpGet httpget)
{
this.httpClient = httpClient;
this.context = new BasicHttpContext();
this.httpget = httpget;
}

@Override public void run()
{
try
{
HttpResponse response = this.httpClient.execute(this.httpget, this.context);
HttpEntity entity = response.getEntity();
if (entity != null)
{
// do something useful with the entity
// ...
// ensure the connection gets released to the manager
entity.consumeContent();
}
}
catch (Exception ex)
{
this.httpget.abort();
}
}

}

2.11. Политика вытеснения соединений

Одним из основных недостатков классической модели блокировки ввода/вывода является то, что сетевой сокет может реагировать на события ввод/вывод только тогда, когда заблокированы в операции ввода/вывода. Когда соединение освобождено и возвращено обратно диспетчеру, оно все еще может быть активно, однако оно не в состоянии контролировать состояние сокета и реагировать на какие-либо события ввода/вывода. Если соединение закрывается на стороне сервера, связь на стороне клиента не в состоянии обнаружить изменения в состоянии соединения и адекватно отреагировать на закрытие сокета на другом конце.

HttpClient пытается смягчить проблему путем проверки соединения на пригодность('stale') перед его использованием для выполнения запроса HTTP; непригодное соединение больше не допустимо, поскольку оно было закрыто на стороне сервера. Проверка соединения на пригодность надежна не на 100% и добавляет от 10 до 30 мс накладных расходов на каждое выполнение запроса. Единственно возможным решением, которое не связано с одного потока на сокет модель для простаивающие соединения является выделенный поток монитора используется для выселить соединения, которые считаются истек из-за длительного периода бездействия. Поток мониторинга может периодически вызывать метод ClientConnectionManager.closeExpiredConnections(), чтобы закрыть все устаревшие соединения и вытеснить закрытые соединения из пула. Она также может опционально вызывать метод ClientConnectionManager.closeIdleConnections(), чтобы закрыть все соединения, которые простаивают в течение определенного периода времени.

public static class IdleConnectionMonitorThread extends Thread
{

private final ClientConnectionManager connMgr;
private volatile boolean shutdown;

public IdleConnectionMonitorThread(ClientConnectionManager connMgr)
{
super();
this.connMgr = connMgr;
}

@Override
public void run()
{
try
{
while (!shutdown)
{
synchronized
(this)
{
wait(5000);
// Close expired connections
connMgr.closeExpiredConnections();
// Optionally, close connections
// that have been idle longer than 30 sec
connMgr.closeIdleConnections(30, TimeUnit.SECONDS);
}
}
}
catch (InterruptedException ex)
{
// terminate
}
}

public void shutdown()
{
shutdown = true;
synchronized (this)
{
notifyAll();
}
}

}

2.12. Стратегия сохранения активности соединений

Спецификация HTTP не определяет, как долго постоянное соединение может быть и должно быть активным. Некоторые HTTP серверы используют нестандартные заголовки Keep-Alive, чтобы условиться с клиентом о периоде времени в секундах, в течении которого они намерены сохранять соединение на стороне сервера активным. HttpClient использует эту информацию, если она доступна. Если заголовка Keep-Alive в ответе нет, HttpClient полагает, что соединение может оставаться активным в течении неопределенного срока. Однако, многие HTTP-серверы настроены на прекращение постоянного соединения после определенного периода бездействия с целью экономии системных ресурсов, нередко без уведомления клиента. В случае, если по умолчанию стратегия оказывается слишком оптимистичной, можно хотим предоставить пользовательские Keep-Alive стратегии.

DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.setKeepAliveStrategy(new ConnectionKeepAliveStrategy()
{

public long getKeepAliveDuration(HttpResponse response, HttpContext context)
{
// Honor 'keep-alive' header
HeaderElementIterator it = new BasicHeaderElementIterator( response.headerIterator(HTTP.CONN_KEEP_ALIVE));
while (it.hasNext())
{
HeaderElement he = it.nextElement();
String param = he.getName();
String value = he.getValue();
if (value != null && param.equalsIgnoreCase("timeout"))
{
try
{
return Long.parseLong(value) * 1000;
}
catch(NumberFormatException ignore)
{
}
}
}
HttpHost target = (HttpHost) context.getAttribute( ExecutionContext.HTTP_TARGET_HOST);
if ("www.naughty-server.com".equalsIgnoreCase(target.getHostName()))
{
// Keep alive for 5 seconds only return 5 * 1000;
}
else
{
// otherwise keep alive for 30 seconds return 30 * 1000;
}
}

});

Внимание! Этот перевод, возможно, ещё не готов.
Его статус: идёт перевод

Переведено на Нотабеноиде
http://notabenoid.org/book/12990/42257

Переводчики: gi1gi

Настройки

Готово:

100.00% КП = 1.0