Как программно удалить ограничение на 2 подключения в WebClient

88

Эти "прекрасные" RFC предписывают каждому RFC-клиенту избегать использования более двух соединений на хост ...

Microsoft реализовала это в WebClient. Я знаю, что это можно выключить с помощью

App.config:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
 <system.net> 
  <connectionManagement> 
   <add address="*" maxconnection="100" /> 
  </connectionManagement> 
 </system.net> 
</configuration> 

(можно найти на http://social.msdn.microsoft.com/forums/en-US/netfxnetcom/thread/1f863f20-09f9-49a5-8eee-17a89b591007 )

Но как это сделать программно?

Согласно http://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.defaultconnectionlimit.aspx

«Изменение свойства DefaultConnectionLimit не влияет на существующие объекты ServicePoint; оно влияет только на объекты ServicePoint, которые инициализируются после изменения. Если значение этого свойства не было установлено напрямую или через конфигурацию, по умолчанию используется константа DefaultPersistentConnectionLimit».

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

Сервер, к которому я обращаюсь, не является обычным веб-сервером в Интернете, но находится под моим контролем и в локальной сети. Я хочу делать API-вызовы, но не использую веб-сервисы и удаленное взаимодействие

Христианин
источник
15
Это не совсем стандарт. RFC «рекомендует» ограничивать клиентов двумя подключениями, но на самом деле это не является обязательным требованием. Скорее всего, постеру необходимо загрузить более 2-х элементов одновременно.
Эрик Функенбуш
12
Я получаю доступ к API на моем собственном сервере. Я не хочу причинять вред хостам в Интернете.
Christian
12
Я увеличил ограничение на количество подключений, чтобы создать инструмент для тестирования нагрузки. Очень сложно провести нагрузочный тест с двумя небольшими соединениями. Я уверен, что есть много причин, не связанных с просмотром, для использования большого количества подключений.
ScottS
1
Кстати, приведенная выше конфигурация повлияет на все соединения, контролируемые .Net, а не только на веб-клиент.
ScottS
2
Почему больше двух? Давайте вернемся к вопросу: почему я не мог отправить более двух запросов к серверу одновременно в асинхронном режиме? 2 - это буквально ограничение.
Csaba Toth

Ответы:

50

С некоторыми советами отсюда и из других источников мне удалось исправить это в моем приложении, переопределив класс WebClient, который я использовал:

class AwesomeWebClient : WebClient {
    protected override WebRequest GetWebRequest(Uri address) {
        HttpWebRequest req = (HttpWebRequest)base.GetWebRequest(address);
        req.ServicePoint.ConnectionLimit = 10;
        return (WebRequest)req;
    }
}
Шизам
источник
28
ИМХО, установка System.Net.ServicePointManager.DefaultConnectionLimit- лучшее решение, так как нельзя предполагать, что WebRequestэто HttpWebRequest, например, может быть FileRequest.
Деннис
120

для заинтересованных:

System.Net.ServicePointManager.DefaultConnectionLimit = x (где x - желаемое количество подключений)

нет необходимости в дополнительных ссылках

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

Lilmoe
источник
Так можно ли добавить это в application_start в глобальном масштабе? так это влияет на все сделанные подключения?
TheAlbear
Как и куда добавить System.Net.ServicePointManager.DefaultConnectionLimit = x?
Арул Сидтхан,
Как ни странно, в комментарии к коду для DefaultConnectionLimit (переход с помощью F12) указано, что по умолчанию используется Int32.MaxValue. Однако при проверке отладки это 2, как заявлено.
crokusek
7

Это решение позволяет в любой момент изменить лимит подключения :

private static void ConfigureServicePoint(Uri uri)
{
    var servicePoint = ServicePointManager.FindServicePoint(uri);

    // Increase the number of TCP connections from the default (2)
    servicePoint.ConnectionLimit = 40;
}

В первый раз, когда кто-либо вызывает этот FindServicePoint , создается экземпляр ServicePoint и создается WeakReference, чтобы удерживать его внутри ServicePointManager . Последующие запросы к менеджеру для одного и того же Uri возвращают тот же экземпляр. Если после этого соединение не используется, GC очищает его.

Георгий Циокос
источник
1
Единственная проблема с FindServicePoint заключается в том, что он возвращает вам одну ServicePoint, но вы не знаете, будет ли она такой же ServicePoint, которую получает ваш клиент.
jeffa00
2
Это не «проблема», это просто нормальная часть работы. Как и во всех решениях, вы должны найти способ проверить это. Мой способ состоял в том, чтобы установить для параметра .config значение «1», наблюдать ужасную производительность и установить его в коде (как здесь), наблюдая за улучшением производительности.
Abacus
1
Это ServicePointпотеряно (вместе с вашими настройками) послеMaxIdleTime
Колин Брим
5

Если вы обнаружите, что объект ServicePoint используется вашим WebClient, вы можете изменить его ограничение на количество подключений. У объектов HttpWebRequest есть метод доступа для извлечения того, который они были созданы для использования, поэтому вы можете сделать это таким образом. Если вам повезет, все ваши запросы могут в конечном итоге использовать одну и ту же ServicePoint, поэтому вам нужно будет сделать это только один раз.

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

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

Кейтлин Гэдд
источник
Этот сервер не будет меня задушить (на самом деле, будет, но по-другому), так как он полностью под моим контролем,
Кристиан,
1
Сервер может блокировать большое количество подключений, но я не испытывал этого даже с небольшим сервером (размещенным на ограниченной виртуальной машине). Предел 2 на стороне клиента сдерживал меня, с другой стороны. Повышение лимита раскрепощало ситуацию.
Csaba Toth
1
Я также сомневаюсь, что какой-либо из сегодняшних браузеров будет подчиняться пределу 2 RFC HTTP 1.1
Чаба Тот
4

У нас есть ситуация с приведенной выше конфигурацией в App.Config.

Чтобы это было действительным в КОНСОЛЬНОМ приложении, мы добавили ссылочную dll System.Configuration. Без ссылки все вышесказанное было бесполезно.

Тео-Костас
источник