Como posso remover programaticamente o limite de 2 conexões no WebClient

88

Essas RFCs "finas" exigem de todos os clientes RFC que tomem cuidado para não usar mais de 2 conexões por host ...

A Microsoft implementou isso no WebClient. Eu sei que pode ser desligado com

App.config:

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

(encontrado em http://social.msdn.microsoft.com/forums/en-US/netfxnetcom/thread/1f863f20-09f9-49a5-8eee-17a89b591007 )

Mas como posso fazer isso programaticamente?

Acordo para http://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.defaultconnectionlimit.aspx

"Alterar a propriedade DefaultConnectionLimit não tem efeito nos objetos ServicePoint existentes; afeta apenas objetos ServicePoint que são inicializados após a alteração. Se o valor desta propriedade não foi definido diretamente ou por meio da configuração, o valor padrão é a constante DefaultPersistentConnectionLimit."

Eu gostaria melhor de configurar o limite quando eu instanciar o WebClient, mas apenas remover essa limitação triste programaticamente no início do meu programa também estaria bom.

O servidor que eu acesso não é um servidor normal da internet, mas está sob meu controle e na lan local. Quero fazer chamadas API, mas não uso webservices ou remoting

cristão
fonte
15
Não é realmente um padrão. A RFC "recomenda" que você limite os clientes a duas conexões, mas não é realmente um requisito. Mais do que provavelmente, o pôster precisa baixar mais de 2 itens de uma vez.
Erik Funkenbusch
12
Eu acesso uma API em meu próprio servidor. Não quero prejudicar hosts na Internet.
Cristão
12
Aumentei o limite de conexão para construir uma ferramenta de teste de carga. É realmente difícil fazer o teste de carga com 2 conexões do sarampo. Tenho certeza de que há muitos motivos de não navegação para usar muitas conexões.
ScottS de
1
BTW, a configuração acima afetará todas as conexões controladas por .Net, não apenas o webclient.
ScottS de
2
Por que mais de dois? Vamos virar a questão: por que não pude emitir mais de duas solicitações para um servidor ao mesmo tempo de forma assíncrona? 2 é literalmente uma limitação.
Csaba Toth

Respostas:

50

Com algumas dicas daqui e de outros lugares, consegui corrigir isso em meu aplicativo, substituindo a classe WebClient que estava usando:

class AwesomeWebClient : WebClient {
    protected override WebRequest GetWebRequest(Uri address) {
        HttpWebRequest req = (HttpWebRequest)base.GetWebRequest(address);
        req.ServicePoint.ConnectionLimit = 10;
        return (WebRequest)req;
    }
}
Shizam
fonte
28
IMHO que definir o System.Net.ServicePointManager.DefaultConnectionLimité a melhor solução, pois não se pode assumir que WebRequesté a HttpWebRequest, por exemplo, poderia ser a FileRequest.
Dennis
120

para os interessados:

System.Net.ServicePointManager.DefaultConnectionLimit = x (onde x é o número desejado de conexões)

sem necessidade de referências extras

apenas certifique-se de que isso seja chamado ANTES de o ponto de serviço ser criado conforme mencionado acima na postagem.

lilmoe
fonte
Então, isso poderia ser adicionado ao application_start no global? por isso afeta todas as conexões feitas?
TheAlbear
Como e onde adicionar System.Net.ServicePointManager.DefaultConnectionLimit = x?
Arul Sidthan
Estranhamente, o comentário do código para DefaultConnectionLimit (navegando usando F12) diz que seu padrão é Int32.MaxValue. No entanto, pela inspeção de depuração, é 2, conforme reivindicado.
crokusek
7

Esta solução permite que você altere o limite de conexão a qualquer momento :

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

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

Na primeira vez que alguém chama este FindServicePoint , uma instância do ServicePoint é criada e um WeakReference é criado para mantê-lo dentro do ServicePointManager . As solicitações subsequentes ao gerente para o mesmo Uri retornam a mesma instância. Se a conexão não for usada depois, o GC a limpará.

George Tsiokos
fonte
1
O único problema com FindServicePoint é que ele devolve um ServicePoint, mas você não sabe se será o mesmo ServicePoint que seu cliente obtém.
jeffa00
2
Isso não é um "problema", é apenas uma parte normal do trabalho. Como acontece com todas as soluções, você deve encontrar uma maneira de testar isso. Minha maneira era definir a configuração no .config para "1", observar o péssimo desempenho, e configurá-lo no código (como aqui), observando o desempenho melhorado.
Abacus
1
O ServicePointé perdido (junto com suas configurações) apósMaxIdleTime
Colin Breame
5

Se você encontrar o objeto ServicePoint sendo usado por seu WebClient, poderá alterar seu limite de conexão. Os objetos HttpWebRequest têm um acessador para recuperar aquele para o qual foram construídos para usar, portanto, você pode fazer isso dessa maneira. Se você tiver sorte, todas as suas solicitações podem acabar compartilhando o mesmo ServicePoint, então você só terá que fazer isso uma vez.

Não conheço nenhuma forma global de alterar o limite. Se você alterou DefaultConnectionLimit no início da execução, provavelmente não terá problemas.

Como alternativa, você pode simplesmente viver com o limite de conexão, uma vez que a maioria dos softwares de servidor vai restringi-lo de qualquer maneira. :)

Katelyn Gadd
fonte
Este servidor não vai me estrangular (na verdade, vai, mas de uma maneira diferente), pois está completamente sob meu controle
Christian
1
Um servidor pode ficar estrangulado com muitas conexões, mas não experimentei isso, mesmo com um servidor pequeno (hospedado em uma VM limitada). O limite de 2 do lado do cliente me impediu de voltar. Aumentar o limite liberou a situação.
Csaba Toth,
1
Também duvido que qualquer navegador de hoje obedecesse ao limite de 2 do RFC HTTP 1.1.
Csaba Toth
4

Temos uma situação em relação à peça de configuração acima em App.Config

Para que isso seja válido em um aplicativo CONSOLE, adicionamos a dll de referência System.Configuration. Sem a referência, o anterior era inútil.

Teo-Kostas
fonte