\


 Monday, 03 May 2004
Znáte třídy ServicePoint a ServicePointManager? Měli byste...

Při používání více threadů například pro získání obsahu WWW stránek ze stejného URI nebo při asynchronním a současně prováděném volání více metod jedné WWW služby se můžete setkat s podivnými výjimkami nebo ještě podivnějšími prodlevami mezi jednotlivými voláními.
Za rovnoměrné využití síťových zdrojů je odpovědná třída ServicePointManager. Ta obhospodařuje kolekci objektů ServicePoint, které jsou vytvářeny při prvním požadavku na dané URI. Třída ServicePointManager má několik zajímavých vlastností a metod.
Vlastnost DefaultConnectionLimit - hodnota vlastnosti určuje, kolik konkurenčních připojení může ve stejném okamžiku přistupovat ke stejnému URI. V .Net Frameworku 1.1 jsou ve výchozím nastavení povolena dvě konkurenční připojení na stejné URI. Jestliže například z nějakého důvodu potřebujete asynchronně a "najednou" volat více metod WWW služby, měli byste ConnectionLimit zvýšit.
Vlastnost MaxServicePointIdleTime - tato vlastnost říká, jak dlouho musí být dané URI neaktivní, aby se stalo kořistí Garbage Collectoru. Neaktivní znamená, že s daným URI nebylo po zadanou dobu vytvořeno žádné spojení. Výchozí hodnotou je 900.000 milisekund (15 minut)
Vlastnost MaxServicePoints - tato vlastnost říká, kolik instancí ServicePoint může být vytvořeno. Jinými slovy, tato vlastnost omezuje počet URI, na které se lze v jednom okamžiku připojit. Ve výchozím nastavení žádný limit neexistuje (vlastnost obsahuje hodnotu 0).
Metoda FindServicePoint - přetížená metoda FindServicePoint vrátí objekt ServicePoint pro zadané URI. Když ServicePoint pro URI ještě neexistuje, tak metoda vytvoří a vrátí nový objekt ServicePoint, jinak je vrácen existující ServicePoint.

U třídy ServicePoint můžeme upravit vlastnosti, jež jsou po vytvoření objektu inicializovány výchozími hodnotami převzatými z třídy ServicePointManager.

ConnectionLimit - má stejný význam jako vlastnost DefaultConnectionLimit u ServicePointManageru.
MaxIdleTime = má stejný význam jako vlastnost DefaultConnectionLimit u ServicePointManageru.

Tak a teď jednoduchý demonstrační kód konzolové aplikace. Nejdříve kód, který změní DefaultConnectionLimit tak, aby odpovídal počtu požadavků (WebRequest). Vše proběhne relativně rychle a dle očekávání.

using System;
using System.Net;
using System.Threading;
namespace RStein.ServicePointManagerTester
{
  class ServicePointManagerTest
  {
    static void Main(string[] args)
    {
      Console.WriteLine(ServicePointManager.DefaultConnectionLimit);
       ServicePointManager.DefaultConnectionLimit = 4;
       WebRequest reg = WebRequest.Create("http://wwww.atlas.cz");
       WebRequest reg2 = WebRequest.Create("http://wwww.atlas.cz");
       WebRequest reg3 = WebRequest.Create("http://wwww.atlas.cz");
       WebRequest reg4 = WebRequest.Create("http://wwww.atlas.cz");
       WaitHandle handle0 = reg.BeginGetResponse(new AsyncCallback(test), reg).AsyncWaitHandle;
       WaitHandle handle1 = reg2.BeginGetResponse(new AsyncCallback(test), reg2).AsyncWaitHandle;
       WaitHandle handle2 =reg3.BeginGetResponse(new AsyncCallback(test), reg3).AsyncWaitHandle;
       WaitHandle handle3 =reg4.BeginGetResponse(new AsyncCallback(test), reg4).AsyncWaitHandle;
       WaitHandle.WaitAll(new WaitHandle[] {handle0, handle1, handle2, handle3});
       Console.WriteLine("vse");
       Console.Read();
     }

     private static void test(IAsyncResult ar)
     {
       Console.WriteLine("Konec requestu");
       try
       {
         WebRequest reg = (WebRequest)ar.AsyncState;         

        WebResponse response = reg.EndGetResponse(ar);         

        response.GetResponseStream().Close();       

     }
       catch(Exception e)
       {
         Console.WriteLine(e.ToString());
       }
     }
   }
}
Nyní změňte DefaultConnectionLimit na 1. Jak můžete pozorovat, vyřízení všech požadavků je citelně pomalejší (alespoň u mě na GPRS), protože jsou vyřizovány jeden po druhém. K URI "www.atlas.cz" může vždy přistoupit pouze jedno připojení. Mimochodem, víte proč se v MSDN neustále zdůrazňuje, že je třeba co nejdříve uzavřít všechny použité streamy? Jestliže ne, upravte řádku response.GetResponseStream() Close() ; na response.GetResponseStream(); a spusťte znovu aplikaci.



Monday, 03 May 2004 21:21:00 (Central Europe Standard Time, UTC+01:00)       
Comments [6]  .NET Framework


Tuesday, 19 July 2005 11:02:04 (Central Europe Standard Time, UTC+01:00)
Podle dokumentace se servicePoint pouziva pro HTTP komunikaci. chapu to tedy dobre, ze v pouze v tridach WebRequest a spol?

jde mi o tom, pokud pouziji System.Net.Sockets.TcpClient na 80 port, tak to pujde mimo ServicePoint?

Jen tam BTW, narazil ...
Tuesday, 19 July 2005 11:02:04 (Central Europe Standard Time, UTC+01:00)
Kdyz pouzijes soket, tak jde vse mimo ServicePoint. Hledani ServicePointu je soucasti tridy HttpWebRequest (dokumentace je obcas prachbidna ze). Samozrejme ti nic nebrani Logiku tridy ServicePoint pouzivat taky a volat jeji metodu FindServicePoint.
Tuesday, 19 July 2005 11:02:04 (Central Europe Standard Time, UTC+01:00)
A jeste, ty problemy, co popisujes ve svem spotu jsou pomerne zname. Narazil jsem na ne u WWW sluzeb, ale neslo o zadnou kritickou zalezitostm tak jsem to nechal plavat. :)
Tuesday, 19 July 2005 11:02:04 (Central Europe Standard Time, UTC+01:00)
ne, naopak, ServicePoint se velmi rad vyhnu. Moc nevim, co dobreho by mi prinesl :-)

Jeste jedna malickost k nemu.
neni mi uplne zrejme a priznam se, ze se mi to nechce zkouset

Pokud .DefaultConnectionLimit aplikovany na jedinecne URI, jak je ...
Tuesday, 19 July 2005 11:02:05 (Central Europe Standard Time, UTC+01:00)
Ty jsi lenoch Michale, ale reknu ti to.:)V uvahu se u ServicePoint bere pouze protokol,host a port. Zadny QueryString.
Tuesday, 19 July 2005 11:02:05 (Central Europe Standard Time, UTC+01:00)
URI je podle mne jedinecne URL vcetne parametru. Jenze v podani MS je to pokazde neco jineho. :-(

Ano, jsem lenoch v tom smyslu, ze se zeptam nekoho, kdo to uz vi, nez abych to musel v praxi zjistovat. Ale v tom vidim kouzlo komentaru a vlastne i ...
Comments are closed.