Строг и надежден таймаут на HttpClient

Чета уеб страница, използвайки HttpClient по този начин:

        httpclient = new DefaultHttpClient();
        httpget = new HttpGet("http://google.com");
        HttpResponse response = httpclient.execute(httpget);
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            InputStream PIS = entity.getContent();
        }  

Имам нужда от таймаут за цялата работа (свързване, изчакване и четене - всички заедно или поотделно).
Опитах се да задам параметри за таймаут точно след httpclient = new DefaultHttpClient(); ред:

        int timeout=10;
        httpclient.getParams().setParameter("http.socket.timeout", timeout * 1000);
        httpclient.getParams().setParameter("http.connection.timeout", timeout * 1000);
        httpclient.getParams().setParameter("http.connection-manager.timeout", new Long(timeout * 1000));
        httpclient.getParams().setParameter("http.protocol.head-body-timeout", timeout * 1000);

Но не проработи (Изтича времето за изчакване след около 10 пъти повече от времето за изчакване, което зададох).
Така че опитах нишка за анулиране на заявка след време, използвайки httpget.abort() & httpclient.getConnectionManager().shutdown() точно след httpget = new HttpGet("http://google.com"); ред по следния начин:

        (new Timer()).schedule(new java.util.TimerTask() {
            public void run() {
                httpget.abort();
                httpclient.getConnectionManager().shutdown();
            }
        },10000);

но нямаше ефект (таймерът работи; но тези два реда код не правят нищо!)!!
Опитах се да използвам и това:

URL url = new URL("http://google.com");
URLConnection con = url.openConnection();
con.setConnectTimeout(10000);
con.setReadTimeout(10000);
InputStream PIS = con.getInputStream();

но беше същото като първия ми опит (задаване на параметри за изчакване в HttpClient)!!

какъв е проблемът?
Как мога да разреша проблема си с изчакване?

Благодаря


person Ariyan    schedule 31.01.2012    source източник
comment
Това винаги е главоболие. Вижте Това   -  person Jacob    schedule 16.03.2012


Отговори (1)


Не решението, а по-скоро обяснение на случващото се.

Това, което правите е правилно.

Първо, ако използвате Log4J, уверете се, че виждате всичко, което HttpClient иска да ви покаже:

log4j.logger.org.apache.http=trace

Тогава погледнете този клас:

http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/DefaultClientConnectionOperator.html

Този оператор на свързване е наясно с многодомната мрежа и ще опита да повтори неуспешни връзки срещу всички известни IP адреси последователно, докато свързването е успешно или всички известни адреси не успеят да отговорят. Моля, обърнете внимание, че същата стойност на CoreConnectionPNames.CONNECTION_TIMEOUT ще бъде използва се за всеки опит за свързване, така че в най-лошия случай общото изминало време преди таймаут може да бъде CONNECTION_TIMEOUT * n, където n е броят на IP адресите на дадения хост.

Това най-вероятно се случва във вашия случай.

Освен това е по-добре да използвате константи от този интерфейс HttpConnectionParams:

SO_TIMEOUT = "http.socket.timeout"
TCP_NODELAY = "http.tcp.nodelay"
SOCKET_BUFFER_SIZE = "http.socket.buffer-size"
SO_LINGER = "http.socket.linger"
SO_REUSEADDR = "http.socket.reuseaddr"
CONNECTION_TIMEOUT = "http.connection.timeout"
STALE_CONNECTION_CHECK = "http.connection.stalecheck"
MAX_LINE_LENGTH = "http.connection.max-line-length"
MAX_HEADER_COUNT = "http.connection.max-header-count"
MIN_CHUNK_LIMIT = "http.connection.min-chunk-limit"

Трябват ви само две от тях:

HttpConnectionParams.CONNECTION_TIMEOUT
HttpConnectionParams.SO_TIMEOUT

Така че най-добрият начин да разрешите това е да приложите персонализиран метод ClientConnectionOperator.resolveHostname, който връща само един IP адрес.

person serg.nechaev    schedule 15.06.2012