Управление соединением HTTP

173

Поддержка активного соединения HTTP

Постоянные соединения или поддерживаемые активными (keep-alive) соединения были введены в HTTP/1.0, чтобы позволить клиенту, использующему HTTP, экономить сетевые ресурсы и действовать более эффективно, поддерживая активным и используя существующее TCP-соединение, вместо того чтобы закрывать его и создавать новое соединение для очередного запроса.

Заголовок Connection управляет сохранением соединения. По умолчанию все соединения HTTP/1.1 считаются постоянными, пока в запросе или ответе не появится заголовок Connection: close. Когда сервер или клиент получает сообщение с этим заголовком, он закрывает соединение по завершении транзакции.

По умолчанию в свойстве KeepAlive объекта HttpWebRequest установлено значение true. Это приводит к созданию постоянного соединения с сервером, при условии, что сервер поддерживает это поведение. Важно иметь в виду, что при обращении к поддерживающему серверу из приложения ASP.NET среднего уровня, соединение остается открытым, пока сервер не разорвет его по тайм-ауту.

Если в свойстве KeepAlive установлено значение true, соединение не будет закрыто, пока не истечет интервал тайм-аута до поступления нового запроса или сервер явно завершит соединение. В большинстве случаев как клиенту, так и серверу разрешается закрыть соединение через отправку в запросе или ответе заголовка Connection: close.

Управление соединением HTTP

Управление соединением — важное средство в достижении максимальной масштабируемости и производительности сетевого приложения. Эти цели достигаются ограничением числа установленных сокетов, ориентированных на вывод, и использованием для оптимизации взаимодействия клиент-сервер таких дополнительных средств HTTP, как постоянные соединения. Платформа .NET управляет соединениями через классы ServicePoint и ServicePointManager.

Класс ServicePoint из пространства имен System.Net управляет соединениями с ресурсом Интернета на основе информации о хосте, передаваемой в URI ресурса. Начальное соединение с ресурсом определяет информацию, которая должна поддерживаться классом ServicePoint, а он, в свою очередь, совместно используется всеми последующими запросами к этому ресурсу.

Объект ServicePoint представляет соединение с URI, имеющим конкретные идентификатор протокола (например, http://) и имя хоста (например, www.professorweb.ru). Если два и более запросов обращаются к ресурсам с одним и тем же протоколом и одним именем хоста, то для всех этих запросов будет использоваться одно и то же соединение.

Создадим экземпляр класса ServicePoint, используя статический метод FindServicePoint() класса ServicePointManager. Он принимает объект Uri, представляющий ресурс Интернета, для соединения с которым будет использоваться эта точка обслуживания. Например:

// Получаем URI сайта
Uri siteUri = new Uri("http://www.professorweb.ru");

// ServicePoint для этого URI
ServicePoint spSite = ServicePointManager.FindServicePoint(siteUri);

Тайм-аут соединения

Когда создается экземпляр ServicePoint, он поддерживает соединение с указанным ресурсом Интернета, пока не истечет тайм-аут. Можно менять значение этого тайм-аута для отдельного объекта ServicePoint, устанавливая свойство ServicePointManager.MaxServicePointIdleTime. Кроме того, через свойство IdleSince выясним время, прошедшее с тех пор, как было установлено последнее соединение с точкой обслуживания:

// Получаем время существование соединения 
DateTime idleTime = spSite.IdleSince;

// Установка MaxIdleTime в миллисекундах 
spSite.MaxIdleTime = 5000;

По умолчанию значение MaxIdleTime равно 900 000 мс (15 мин).

Можно также установить в MaxIdleTime значение Timeout.Infinite (из пространства имен System.Threading), чтобы указать, что объект ServicePoint никогда не должен закрываться по тайм-ауту (хотя соединение, конечно, может завершаться сервером):

spSite.MaxIdleTime = System.Threading.Timeout.Infinite;

Предельное число соединений

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

Uri siteUri = new Uri("http://www.professorweb.ru");
ServicePoint spSite = ServicePointManager.FindServicePoint(siteUri);

spSite.ConnectionLimit = 4;

Максимальное число используемых соединений зависит от условий, в которых выполняется приложение. Поэтому лучше начать с оценки эффективности работы приложения со значением, принятым по умолчанию, а затем изменять это значение и наблюдать за влиянием на производительность. Например, полагая, что по умолчанию значение равно двум, можно попытаться изменить его на четыре. В спецификации НТТР/1.1 рекомендуется, чтобы приложение-клиент имело не более двух одновременно открытых соединений с сервером.

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

Пройди тесты
Лучший чат для C# программистов