Eigener InputStream will nicht mit BufferedReader

Metta

Mitglied
Hallo liebe Java-Gemeinde,

mein Problem ist folgendes:
Ich habe mir eine eigene Klasse von InputStream abgeleitet welche ich später mit einem InputStreamReader und einen BufferedReader gewrapped habe.

Der InputStream dient als Puffer zur Entschlüsselung und Weiterleitung einer verschlüsselten Netzwerkverbindung und überschreibt read(), available(), skip() und markSupported().

Wenn nun die Methode readLine() von BufferedReader mehr Bytes vom stream lesen will, als vorerst da sind, dann blockt der InputStream seinerseits und wartet auf Netzwerkdaten.

Soweit so gut.

Nur komisch ist, dass wenn im Puffer (dh. bereits entschlüsselt) z.B. der String "ich bin ein String\nhallo\n" habe, readLine() einfach nicht mehr aufhört neue Bytes anzufordern, obwohl er schon 2 mal '\n' "überlesen" hat.

Ich habe in die read() Methode meines InputStreams mal eine Debug-Ausgabe geschrieben, welche bestatigt, dass read() solange aufgerufen wird, bis der Puffer "leer" ist und auf neue Netzwerkdaten gewartet werden muss.

Wahrscheinlich eine Kleinigkeit ...
Vielen Dank im vorraus :-D


Hinweis:
- "decrypted" ist der Puffer
- "lastindex" der index des zuletzt aus dem Puffer gelesenem Byte
- die Methode decrypt holt ein neues vershclüsseltes "Paket" vom Netzwerk (evt blockend)

Die Methode decrypt läuft einwandfrei.


Java:
private class AlgoInputStream extends InputStream {
	byte[] decrypted = null;
	int lastindex = -1;
	Cipher cipher = null;
	BufferedReader br = null;
	public AlgoInputStream(BufferedReader br) {
		this.br = br;
		try {
		cipher = Cipher.getInstance("AES");
		cipher.init(Cipher.DECRYPT_MODE, AESKey);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		}
	}
	@Override
	public int read() throws IOException {
		while (decrypted==null || !(lastindex+1<decrypted.length)) {
			if (!decrypt()) {
				return -1;
			}
		}
		lastindex++;
		System.out.println("read a byte from the buffer: (byte)"+decrypted[lastindex]+" (char)"+(char)decrypted[lastindex]);
		return decrypted[lastindex];
	}
	@Override
	public int available() throws IOException {
		return decrypted.length-1-lastindex;
	}
	@Override
	public boolean markSupported() {
		return false;
	}
		
	@Override
	public long skip(long n) throws IOException {
		long skipnbr = (n<available())? n : available();
		lastindex = (int) (lastindex+skipnbr);				
		return skipnbr;
	}
			
	private boolean decrypt() throws IOException {
		lastindex=-1;
		decrypted = null;
		String input = null;
		try {
			System.out.println("trying to fetch & deBase64 a new line");
			if ((input = br.readLine())!=null) {
				decrypted = cipher.doFinal(Config.fromBase64_2(input));
				return true;
			}
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		return false;
	}			
}
 
Damit das nicht so ganz unübersichtlich ist mit dem ganzen Exceptions und den Cipher-Geschichten nochmal das gleiche Problem auf trivialer Ebene:

Java:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;


public class StreamTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		StreamTest st = new StreamTest();

		st.start();
		
	}
	
	public void start() {
		BufferedReader br = new BufferedReader(new InputStreamReader(new MyInputStream()));
		try {
			String line ="";
			while (line!=null && !line.equals("q")) {
					line = br.readLine();                 //////////<---  Hier bleibt er einfach hängen und fordert
					System.out.println("received: "+line);//////////      immmer mehr bytes an.
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	
	public class MyInputStream extends InputStream {
		byte[] buffer = null;
		int lastindex = -1;
		@Override
		public int read() throws IOException {
			while (buffer==null || !(lastindex+1<buffer.length)) { ///wenn bufferunderrun
				if (!fetchinput()) {
					return -1;
				}
			}
			lastindex++;
			System.err.print("read (char)"+(char)buffer[lastindex]);
			return buffer[lastindex];
		}
		private boolean fetchinput() throws IOException {
			buffer = null;
			lastindex=-1;
			String line = null; 
			if ((line =(new BufferedReader(new InputStreamReader(System.in))).readLine())!=null) {  //// neue Zeile von der Console holen
				buffer=line.concat("\n").getBytes();
				return true;
			}
			return false;
		}
		@Override
		public int available() throws IOException {
			return buffer.length-1-lastindex;
		}
		@Override
		public boolean markSupported() {
			return false;
		}
		@Override
		public long skip(long n) throws IOException {
			int skipnr = (int) ((n<available())? n : available());
			lastindex = lastindex+skipnr;
			return skipnr;
		}		
	}

}
 
immer diese Streams, eigentlich ein schönes Thema, solche Fragen nehme ich gerne, verwirrt mich aber noch nach wie vor 😉

das Problem ist nun letztlich, dass du die Methode read(byte[] b, int off, int len) nicht überschrieben hast,
die wird vom InputStreamReader mit einem 8192er Array aufgerufen
und in der Default-Implementierung von InputStream wird in einer Schleife entsprechend oft read() aufgerufen,

wenn du in fetchinput() testweise paar tausend bytes hinzufügst dann klappt das langsam mit dem bisherigen Code,
ansonsten die Methode überschreibe und genau überlegen, unter welchen Bedingungen schon vorher abgebrochen wird,
nur genau einmal aus System.in lesen? spielt Zeilenumbruch eine Rolle? available() abfragen, usw.

den Quellcode von BufferedInputStream usw. als (wenn auch wenig anschauliches) Beispiel hast du/ brauchst du?
 
danke :-D

stimmt:
(localSkipBuffer, 0, (int) Math.min(SKIP_BUFFER_SIZE, remaining));
und SKIP_BUFFER_SIZE = 2048

war ja so klar ... ich hatte read(byte[] b, int off, int len) schon abgehakt und nicht mehr daran gedacht, weil sie ja in InputStream schon implementiert wurde, aber wer den Javadoc dazu lesen kann ist stark im Vorteil.

"Reads up to len bytes of data from the input stream into an array of bytes. An attempt is made to read as many as len bytes, but a smaller number may be read." - "Up to" gibt hier den entscheidenden Ausschlag.


War eindeutig zu früh für mein Gerhirn.

Danke für die schnelle Hilfe
Metta
 

Zurück
Oben