Управление соединением HTTP
173C# и .NET --- Сетевое программирование --- Управление соединением HTTP
Поддержка активного соединения 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 рекомендуется, чтобы приложение-клиент имело не более двух одновременно открытых соединений с сервером.
Как правило число параллельно существующих соединений не должно быть слишком велико, поскольку между преимуществом, получаемым приложением, имеющим несколько соединений, и накладными расходами, вызванными созданием нового соединения, существует тонкий баланс. В некоторый момент приложение, создающее слишком много соединений, будет на самом деле выполняться медленнее, чем приложение, благоразумно использующее меньше соединений.