Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Java: URL getInputStream "pysähtyy"

Sivun loppuun

JussiR [11.12.2013 11:36:59]

#

Hei,

Minulla on tämmöinen koodi, joka hakee dataa json API:sta. Käytän tuota pätkää ohjelmassani koko ajan loopissa ja haen eri URL osoitteista tietoa. En näe tarpeelliseksi laittaa tänne koko koodia.

Ohjelma saatta pyöriä tuntejakin hyvin, mutta sitten yhtäkkiä se vaan "pysähtyy" ja viimeinen teksti, jonka se sanoo on "Getting trades... jne". Mitään virheitä ei näy eikä ohjelman suoritus keskeydy (Eclipsessä ei lue "terminated").

Mistäköhän tälläinen voisi johtua? Olen antanut sen olla pysähtyneenä useamman tunnin eikä tullut mitään timeout virheitäkään.

       lib.conprint("A");

        InputStream in=null;
        boolean error;
       do {
    	  error=false;
		try {
	    	lib.conprint("getTrades: Getting trades since " + since + " ..." );
			in = new URL(Global.tradesURL+since.toString()).openConnection().getInputStream();
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			lib.conprint("Connection error: " + e1);
			lib.conprint("Reconnecting in 5 seconds...");
			lib.sleep(20); //odotetaan 20x250ms
			error=true;
		}
        }while (error);

       lib.conprint("B");

Grez [11.12.2013 12:11:59]

#

Kokeile katsoa montako yhteyttä on auki. (windowsilla netstat -n )

Joskus käynyt niin, että kun yhteyksiä ei suljeta ja ne jää auki, eikä roskienkerääjä tajua poimia niitä. Sitten kun maksimimäärä avoimia yhteyksiä on avoinna, se jää vaan odottelemaan että yhteyksiä vapautuu.

Voi tietty olla että on ihan muusta kyse.

JussiR [11.12.2013 13:15:43]

#

Ei noita näytä kerääntyvän. Ehdotuksia miten debugata vielä?

JussiR [23.01.2014 10:09:03]

#

Koodi olisinyt kaikinpuolin muuten valmis, mutta edelleen tätä tapahtuu :( Softasta pitäisi tulla sellainen, että sitä voi ajaa vaikka vuoden, joten tälläinen ei ole sallittua.

Tapahtuu näköjään myös linuxilla. Mitään ehdotuksia debuggaukseen? En keksi oikein mitään.

Grez kirjoitti:

Joskus käynyt niin, että kun yhteyksiä ei suljeta ja ne jää auki, eikä roskienkerääjä tajua poimia niitä.

Pitäisikö nämä yhteydet jotenkin sulkea erikseen? En ole huomannut, että tuo vika tulisi säännöllisesti tietyn ajan jälkeen. Joskus ohjelma pyörii monta päivää.

EDIT: Löysin tälläisen ja taidan kokeilla tuossa vikassa viestissä olevaa koodia: http://stackoverflow.com/questions/7439463/java-url-hangs-and-never-reads-in-website
Kokeillaas taas muutama päivä...

    public String getData(String URL){

		String data="";

		try {

		    URL link = new URL(URL);
		    BufferedReader in = new BufferedReader(new InputStreamReader(link.openStream()));
		    //InputStream in = link.openStream();
		    String inputLine = "";

			while ((inputLine = in.readLine()) != null) {
				data = data + inputLine;
			}

		    in.close();

		} catch(Exception e){
			lib.conprint2("\n\t\tConnection error: " + e,false);
			lib.writeLog("errors", "getData() error: " + e + "\n" + data,true,true);
			data="";
		}

    	return data;

    }

Metabolix [23.01.2014 15:31:41]

#

JussiR kirjoitti:

Ei noita näytä kerääntyvän.

Miten katsoit?

JussiR kirjoitti:

Pitäisikö nämä yhteydet jotenkin sulkea erikseen?

Kai close-metodikin on tarkoituksella olemassa?

JussiR [24.01.2014 18:48:35]

#

Metabolix kirjoitti:

JussiR kirjoitti:

Ei noita näytä kerääntyvän.

Miten katsoit?

Linuxilla "netstat -ntap".

Tuo vika tuli taas vaikka käytössä on nyt tuo getData metodi. Tuolla java prosessilla ei ole netstat komennon mukaan mitään yhteyttä mihinkään ja CPU käyttö on 0%.

Samaan aikaan kun tuo vika tuli, mulla meni kaikkien koneiden netti tosi hitaaksi. Puolet IRC servuista ping timeouttasi yms ja nettisivuilla kesti monta minuuttia aueta.

Kaikki muu palasi puolessa tunnissa normaaliksi paitsi mun java ohjelma, joka pysyyy jumissa tuossa "Get 5 min avg. price since ID 1390570541110572"

Vois varmaan värkätä jotain tuon getData:n while loopin sisälle debuggausta varten. Onko mahdollista, että link.openStream() olisi "null" koko ajan, kun verkkoon tule jotain vikaa?
Ainakin jos katkaisen koneesta netin ihan normaalisti, tulee UnknownHostException.
Ajattelin laittaa semmoisen, että se pysyy tuossa while loopissa enintään 60 s.

Metabolix [24.01.2014 18:57:24]

#

Oletko varma, että et aiheuta ikuisella silmukalla sellaista kuormitusta, että esimerkiksi verkkosi reititin tai tukiasema tilttaisi? Myös vastaanottavalta palvelimelta voi joskus saada hetkelliset bannit, jos tekee liikaa pyyntöjä lyhyessä ajassa.

JussiR [24.01.2014 19:04:42]

#

Kyl mä aika varma oon, kun sitä dataa haetaan vain n. 5 min välein ja silloinkin jotain 5 KB 5-10 kertaa peräkkäin ja niiden hakujen välissäkin 200 ms tauko. API palauttaa vain 100 rivillistä (pieniä) json objekteja kerralla. Muistaakseni jos tuo palvelu antaa bännit, sieltä tulee jokin ilmoitus kyselyihin ja se bänni ei lähde hetkessä pois.

Muut softat, jotka käyttää samaa API:a näyttää hakevan joka sekunti dataa. Tosin ne hakee eri dataa.

En ole varma "hajosiko" mun verkkoyhteys ennen vai jälkeen tuon viimeisimmän haun, johon se jäi, kun sitä ennen oli juurikin tuo 5 min tauko. Reitittimen prossunkäyttö ja kaikki näytti hallinnan sivulla normaalilta.

Kokeilen nyt tämmöistä. Myöhemmin ehkä tuo URL-luokka vaihtoon johonkin muuhun.

    public String getData(String URL){

		String data="";
    	int endTime=(int) (System.currentTimeMillis() / 1000L)+180; // 3 min without/with data and we'll stop

		try {

		    URL link = new URL(URL);
		    BufferedReader in = new BufferedReader(new InputStreamReader(link.openStream()));
		    //InputStream in = link.openStream();
		    String inputLine = "";

			while ((inputLine = in.readLine()) != null) {
				data = data + inputLine;
				if((int) (System.currentTimeMillis() / 1000L)>endTime){
					lib.conprint2("\n\t\tConnection error: we are hanging in here for some reason",false);
					lib.writeLog("errors", "getData() error: we are hanging in here for some reason\n" + data,true,true);
					in.close();
					data="";
					break;
				}
			}

		    in.close();

		} catch(Exception e){
			lib.conprint2("\n\t\tConnection error: " + e,false);
			lib.writeLog("errors", "getData() error: " + e + "\n" + data,true,true);
			data="";
		}

    	return data;

    }

JussiR [06.02.2014 18:03:30]

#

Nyt jäi taas "jumiin" eikä tuo koodi ilmoittanut mitään. Mitäköhän tässä pitäis tehdä?

1. Jumituskohta on tämä:

BufferedReader in = new BufferedReader(new InputStreamReader(link.openStream()));

2. Jumiutumisen (joka ei koskaan lopu) aikana ei ole yhteyttä auki
3. Prosessin CPU käyttö on jumiutumisen aikana 0%
4. Vähintään sekunnin ennen ja jälkeen jumiutumisen alun, on mahdollista yhdistää serverille, mutta jumitushetken alusta ei ole tietoa. Tuo ~1 sekunti tulee siitä, kun olen kokeillut juuri silloin manuaalisesti.

Metabolix [06.02.2014 18:16:19]

#

Jos et saa vian syytä selville, voit kokeilla purkkaviritelmää: laita tuo rivi eri säikeeseen ja yritä keskeyttää se, jos se jumiutuu.

Thread jumi = new Thread() {
	public void run() {
		in = new BufferedReader(new InputStreamReader(link.openStream()));
	}
};
jumi.start();
jumi.join(aikaraja);
if (jumi.isAlive()) {
	System.err.println("Keskeytetään...");
	jumi.interrupt();
	jumi.join();
	System.err.println("Keskeytetty!");
}

JussiR [08.02.2014 21:19:38]

#

Kiitos, kokeilin tuota.

Samalla, kun interruptoin threadin sen jumiutumisen jälkeen, poikkeus tuosta URL luokasta:
java.net.ConnectException: Connection timed out

Jos interruptoin vaikka ei jumita, tulee eri poikkeus: java.net.SocketException: Connection reset

EDIT: nyt se oli näköjään mennyt yöllä monta kertaa peräkkäin jumiin ja lopulta jäänyt jumiin interrupt() kohtaan eli threadia ei saatu keskeytettyä.

Taidanpa ottaa Apache HttpClient käyttöön.

EDIT: Ihan samat ongelmat Apache HttpClientin kanssa. Välillä interrupt() kohtaan ei jäädä ikuisesti jumiin vaan esim. vartiksi.

12:34:44: getData(): the thread is hanging. Interrupting...
12:51:50: org.apache.http.impl.execchain.RetryExec execute
INFO: I/O exception (java.net.SocketException) caught when processing request: Connection timed out
12:51:50: org.apache.http.impl.execchain.RetryExec execute
INFO: Retrying request
12:51:53: getData(): thread interrupted succesfully

Kokeilin stop() komentoa ja sillä pysäyttäminen onnistuu aina, mutta kestää 69 sekuntia. Hmm, mistäköhän tuo aika tulee? 60 sekuntia voisi olla jokin timeout...

13:10:53: getData(): the thread is hanging...
13:12:02: getData(): dataGet thread stopped succesfully

13:14:08: getData(): the thread is hanging...
13:15:17: getData(): dataGet thread stopped succesfully

13:17:23: getData(): the thread is hanging...
13:18:32: getData(): dataGet thread stopped succesfully

Tässä on tällä hetkellä käytössä oleva getData() metodi kokonaisuudessaan:

    @SuppressWarnings("deprecation")
	public String getData(final String url){

    	stop=false;
    	data="";

		Thread dataGet = new Thread() {

			public void run() {
				StringBuffer result = new StringBuffer();
		    	HttpClient client = HttpClientBuilder.create().build();

		    	HttpResponse response = null;

		    	try {

		        	HttpGet request = new HttpGet(url);

			    	request.addHeader("User-Agent", "Advanced-java-client API v2");

					response = client.execute(request);

			    	BufferedReader rd = null;

					rd = new BufferedReader(
					new InputStreamReader(response.getEntity().getContent()));

			    	String line = "";


					while ((line = rd.readLine()) != null && stop==false) {
						result.append(line);
					}

				} catch (Exception e) {
					lib.error("getData() error: " + e +  (response==null ? "" : " (response code: " + response.getStatusLine().getStatusCode() + ")"));
				}finally{
					data=result.toString();
				}
			}
		};

		dataGet.start();

		try {
			dataGet.join(120000); // 2 min
		} catch (InterruptedException e) {
			lib.conprint3("");
			lib.error("getData(): dataGet.join A error: " + e + (data.equals("") ? "" : " - Data: " + data));
			stop=true;
			data="";
			e.printStackTrace();
		}

		if(dataGet.isAlive()){
			lib.conprint3("");
			lib.error("getData(): the thread is hanging... " + (data.equals("") ? "" : "Data: " + data));
			stop=true;
			dataGet.stop();
			data="";

			try {
				dataGet.join();
			} catch (Exception e) {
				lib.error("getData(): dataGet.join B error: " + e);
				e.printStackTrace();
			}finally{
				lib.conprint("getData(): dataGet thread stopped succesfully");
			}

		}


        return data;

    }

JussiR [10.03.2014 17:44:45]

#

Jahas nyt ei ollut pysähtynyt edes stop() komennolla. On se nyt vi**u... Kolme kuukautta jo täs testaillu... Vielä ehdotuksia tuon thread purkan sijaan?

JussiR [08.04.2014 11:18:53]

#

Kokeilin nyt sitten jättää koko threadin päälle, kun sitä ei aina saa pysäytettyä, mutta laittaa tuon stop booleanin todeksi ettei tapahdu mitään hassua. Kolmen jumiutumisen jälkeen java kaatui, mutta ei oo varmaan mikään ihme tälläisellä pelleilyllä:

# A fatal error has been detected by the Java Runtime Environment:
#
#  Internal Error (os_linux_zero.cpp:236), pid=26968, tid=1753244816
#  Error: caught unhandled signal 11
#
# JRE version: 6.0_18-b18
# Java VM: OpenJDK Zero VM (14.0-b16 mixed mode linux-arm )
# Derivative: IcedTea6 1.8.4
.... monta sataa riviä .....
Java Threads: ( => current thread )
=>0x68a00468 JavaThread "Thread-3208" [_thread_in_native, id=31767, stack(0x68687000,0x68807000)]
  0x001aa630 JavaThread "Java2D Disposer" daemon [_thread_blocked, id=26986, stack(0x67dc7000,0x67f47000)]
  0x00087ad8 JavaThread "Low Memory Detector" daemon [_thread_blocked, id=26974, stack(0x67b65000,0x67ce5000)]
  0x00086448 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=26973, stack(0x679e5000,0x67b65000)]
  0x000718e8 JavaThread "Finalizer" daemon [_thread_blocked, id=26972, stack(0x67665000,0x677e5000)]
  0x000705c0 JavaThread "Reference Handler" daemon [_thread_blocked, id=26971, stack(0x674e5000,0x67665000)]
  0x0001e5f8 JavaThread "main" [_thread_blocked, id=26969, stack(0x40dd2000,0x40f51000)]

steelydan [15.05.2014 23:05:14]

#

URLConnectionilla ei välttämättä ole oletuksena mitään timeoutia. Eli jos palvelin ei anna mitään dataa yhteyden avauksen jälkeen niin ohjelma jää odottamaan ikuisesti. Kokeile asettaa timeout kuten alla.

URLConnection urlConnection = new URL("...").openConnection();
urlConnection.setConnectTimeout(5000);

Moni palvelin ei myöskään automaattisesti sulje yhteyttä kun kaikki data on luettu joten readLine() ei välttämättä koskaan palauta nullia.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta