Jak programowo usunąć limit 2 połączeń w programie WebClient

88

Te „dobre” dokumenty RFC nakazują każdemu klientowi RFC, aby nie korzystał z więcej niż 2 połączeń na hosta ...

Microsoft zaimplementował to w WebClient. Wiem, że można to wyłączyć za pomocą

App.config:

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

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

Ale jak mogę to zrobić programowo?

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

„Zmiana właściwości DefaultConnectionLimit nie ma wpływu na istniejące obiekty ServicePoint; ma wpływ tylko na obiekty ServicePoint, które są inicjowane po zmianie. Jeśli wartość tej właściwości nie została ustawiona ani bezpośrednio, ani przez konfigurację, wartość domyślna to stała DefaultPersistentConnectionLimit”.

Chciałbym najlepiej skonfigurować limit, kiedy instaluję WebClient, ale samo usunięcie tego smutnego ograniczenia programowo na początku mojego programu też byłoby w porządku.

Serwer, do którego mam dostęp, nie jest zwykłym serwerem WWW w Internecie, ale pod moją kontrolą i w lokalnej sieci LAN. Chcę wykonywać wywołania API, ale nie używam usług sieciowych ani usług zdalnych

chrześcijanin
źródło
15
To naprawdę nie jest standard. Dokument RFC „zaleca” ograniczenie klientów do dwóch połączeń, ale tak naprawdę nie jest to wymagane. Najprawdopodobniej plakat musi pobrać jednocześnie więcej niż 2 elementy.
Erik Funkenbusch
12
Mam dostęp do API na moim własnym serwerze. Nie chcę krzywdzić hostów w internecie.
Christian
12
Zwiększyłem limit połączeń, aby zbudować narzędzie do testowania obciążenia. Naprawdę trudno jest załadować test z 2 połączeniami pomiarowymi. Jestem pewien, że istnieje wiele powodów niezwiązanych z przeglądaniem, aby korzystać z wielu połączeń.
ScottS
1
BTW, powyższa konfiguracja będzie miała wpływ na wszystkie kontrolowane połączenia .Net, nie tylko na klienta WWW.
ScottS
2
Dlaczego więcej niż dwa? Odwróćmy pytanie: dlaczego nie mogłem wysłać asynchronicznie więcej niż dwóch żądań do serwera w tym samym czasie? 2 to dosłownie ograniczenie.
Csaba Toth

Odpowiedzi:

50

Dzięki kilku wskazówkom z tego miejsca i innych miejsc udało mi się to naprawić w mojej aplikacji, zastępując klasę WebClient, której używałem:

class AwesomeWebClient : WebClient {
    protected override WebRequest GetWebRequest(Uri address) {
        HttpWebRequest req = (HttpWebRequest)base.GetWebRequest(address);
        req.ServicePoint.ConnectionLimit = 10;
        return (WebRequest)req;
    }
}
Shizam
źródło
28
IMHO, że ustawienie System.Net.ServicePointManager.DefaultConnectionLimitjest lepszym rozwiązaniem, ponieważ nie można założyć, że WebRequestjest to HttpWebRequest, np. Może to być FileRequest.
Dennis
120

dla zainteresowanych:

System.Net.ServicePointManager.DefaultConnectionLimit = x (gdzie x to żądana liczba połączeń)

nie ma potrzeby dodatkowych referencji

po prostu upewnij się, że nazywa się to PRZED utworzeniem punktu obsługi, jak wspomniano powyżej w poście.

lilmoe
źródło
Czy można to dodać do application_start w globalnej? więc ma to wpływ na wszystkie wykonane połączenia?
TheAlbear
Jak i gdzie dodać System.Net.ServicePointManager.DefaultConnectionLimit = x?
Arul Sidthan
Co dziwne, komentarz do kodu DefaultConnectionLimit (nawigacja za pomocą F12) mówi, że jego wartością domyślną jest Int32.MaxValue. Jednak przez kontrolę debugowania jest to 2, jak twierdzono.
crokusek
7

To rozwiązanie pozwala w dowolnym momencie zmienić limit połączeń :

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

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

Za pierwszym razem, gdy ktokolwiek wywołuje ten FindServicePoint , tworzona jest instancja ServicePoint i WeakReference jest tworzone w celu zatrzymania go wewnątrz ServicePointManager . Kolejne żądania kierowane do menedżera dotyczące tego samego Uri zwracają to samo wystąpienie. Jeśli połączenie nie jest używane później, GC czyści je.

George Tsiokos
źródło
1
Jedynym problemem związanym z FindServicePoint jest to, że zwraca ci jeden ServicePoint, ale nie wiesz, czy będzie to ten sam ServicePoint, który dostanie twój klient.
jeffa00
2
To nie jest „problem”, to po prostu normalna część pracy. Jak w przypadku wszystkich rozwiązań, musisz znaleźć sposób, aby to przetestować. Mój sposób polegał na tym, aby ustawić w pliku .config wartość „1”, obserwować straszną wydajność i ustawić ją w kodzie (jak tutaj), obserwując poprawę wydajności.
Abacus
1
ServicePointJest tracona (wraz z ustawieniami) poMaxIdleTime
Colin Breame
5

Jeśli zauważysz, że obiekt ServicePoint jest używany przez klienta WebClient, możesz zmienić jego limit połączeń. Obiekty HttpWebRequest mają metodę dostępu do pobierania tego, do którego zostały skonstruowane, więc można to zrobić w ten sposób. Jeśli masz szczęście, wszystkie Twoje żądania mogą skończyć się współdzieleniem tego samego ServicePoint, więc będziesz musiał to zrobić tylko raz.

Nie znam żadnego globalnego sposobu na zmianę limitu. Jeśli zmienisz DefaultConnectionLimit wystarczająco wcześnie podczas wykonywania, prawdopodobnie wszystko będzie dobrze.

Alternatywnie możesz po prostu żyć z limitem połączeń, ponieważ większość oprogramowania serwera i tak będzie Cię dławić. :)

Katelyn Gadd
źródło
Ten serwer mnie nie dusi (w rzeczywistości będzie, ale w inny sposób), ponieważ jest całkowicie pod moją kontrolą
Christian
1
Serwer może się dławić z wieloma połączeniami, ale nie doświadczyłem tego nawet w przypadku małego serwera (hostowanego na ograniczonej maszynie wirtualnej). Z drugiej strony, limit 2 po stronie klienta powstrzymał mnie. Zwiększenie limitu uwolniło sytuację.
Csaba Toth
1
Wątpię też, czy którakolwiek z dzisiejszych przeglądarek przestrzegałaby ograniczenia protokołu HTTP 1.1 RFC wynoszącego 2.
Csaba Toth
4

Mamy sytuację dotyczącą powyższej części konfiguracji w App.Config

Aby było to poprawne w aplikacji CONSOLE, dodaliśmy bibliotekę dll odniesienia System.Configuration. Bez odniesienia powyższe było bezużyteczne.

Teo-Kostas
źródło