Socket Cipher Streams

C

codemaker

Gast
Folgendes Problem:
Ich versuch ein sichere Server-Client-Vernidung aufzubauen. Da hab ich das nützliche Feature des ClientInputStream bzw ClientOutputStream gefunden. In folgendem kurzem Bsp wird das Problem klar. In Prinzip soll einfach nur eine Textzeile vom auf der Serverseite eingegeben werden. Diese wird dann verschlüsselt an den Client geschickt. Ich will das jetzt aber auf Zeilenbasis in Echtzeit übertragen. Führt man das unter Bsp aus wird nur ab und zu geflusht. Z.b kann dass so aussehen:
Eingabe: Hallo
Eingabe:Hallo!!
Eingabe:1234
Ausgabe:Hallo
Eingabe:Test
Ausgabe:Hallo!!
Eingabe:Mach doch jetzt!!!
Ausgabe:1234
Test
Weiß jemand Rat?

Gruß.
Java:
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

public class CipherExample extends Thread {

	private static SecretKey pass;

	public static void main(String[] args) {
		try {

			KeyGenerator kg = KeyGenerator.getInstance("DES");
			kg.init(56);
			pass = kg.generateKey();

			new CipherExample().start();

			ServerSocket ss = new ServerSocket(1010);

			Socket s = ss.accept();

			Cipher desC = Cipher.getInstance("DES");
			desC.init(Cipher.ENCRYPT_MODE, pass);

			CipherOutputStream cos = new CipherOutputStream(
					s.getOutputStream(), desC);

			OutputStreamWriter osw = new OutputStreamWriter(cos);

			Scanner sc = new Scanner(System.in);
			while (true) {
				String line = sc.nextLine();
				if (line.equalsIgnoreCase("exit")) {
					osw.write(line + "\n");
					osw.flush();
					break;
				} else {
					osw.write(line + "\n");
					osw.flush();
				}
			}

			sc.close();
			osw.close();
			ss.close();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void run() {
		try {

			Socket s = new Socket("127.0.0.1", 1010);

			Cipher desC = Cipher.getInstance("DES");
			desC.init(Cipher.DECRYPT_MODE, pass);

			CipherInputStream cis = new CipherInputStream(s.getInputStream(),
					desC);
			Scanner sc = new Scanner(cis);

			while (true) {
				String line = sc.nextLine();
				System.out.println(line);
				if (line.equalsIgnoreCase("exit"))
					break;
			}

			sc.close();
			s.close();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
 
Zuletzt bearbeitet von einem Moderator:
T

tröööt

Gast
das wohl größte problem dürften irgendwelche buffer sein die halt nicht genug daten bekommen ...

im klartext :

fast jedes krypto-verfahren arbeitet mit blöcken einer bestimmten länge ...

liegen nun nicht genug daten vor um einen kompletten block zu füllen wird auch nichts gemacht sondern auf weitere daten gewartet ... was zu deinem problem führt ...

CipherIn/OutputStream haben ihre macken ... auch ich hab damit mal angefangen und bin mitlerweile deutlich weiter : http://www.java-forum.org/java-basics-anfaenger-themen/146264-verschluesseln.html#post977690

das ist mein aktueller code zum sichern einer verbindung mit RSA2048/AES128 ...

wenn das ganze string-basiert ist (wobei auch code für binäre daten vorhanden ist) garantiert der code das auch wirklich "echtzeit-kommunikation" stattfindet ...

wenn du fragen dazu hast nutzt mal die sufu hier im netz-forum oder frag einfach ...

von CipherStream würde ich aber bei sowas abraten ...
 
C

codemaker

Gast
Vielen Dank für den Link und den Hinweis. Wie Tröööt gesagt hat arbeitet Cipher mir Blöcken. Z.b. Bei DES mit 8-Byte Blöcken. Die Blockgröße kann man einfach mit der Methode cipher.getBlockSize() nachschauen. Ich hätte dann gedacht, dass, wenn 8-Byte geschrieben werden, diese auch losgeschickt werden. Klappt aber erst nach 16-Byte. Warum hab ich nicht herausgefunden. Also wenn 16-Byte geschrieben werden, werden die 1. 8-Byte losgeschickt.

Dann hab ich mir den Quellcode der Cipherstreams angeschaut und nachgeguckt, warum das so ist. Mir ist aufgefallen das diese auf dem Cipher-Objeckt mit cipher.update() arbeiten. Um Daten zu verschlüsseln, die nicht diese vorgeschriebene Blockgöße erreichen, muss cipher.dofinal() aufgerufen werden. Das tun diese Standard-Cipherstreams z.B. bei stream.close().

Ich habe jetzt den Quellcode angepasst. Wird auf dem Stream stream.flush()
aufgerufen, wird ein cipher.dofinal() ausgelöst.

Das geht aber nur auf Umwegen. Der Empfänger muss wissen, ob die Daten in ein einfaches cipher.update() geschrieben werden oder in ein cipher.dofinal().

Ich habe das so lösen können, dass es so eine Art Header gibt. Da steht drin, ob der Empfänger ein cipher.update() oder ein cipher.dofinal() aufrufen soll.

Des weiteren wird eine Art Datenlängenfeld, die angibt wie lang die nächsten Nutzdaten sind, mit geschickt, da sonst ab und zu diese update/dofinal Feld als Nutzdaten gesehen wird und dann abgeschmiert.

Auf Grund deiner Hilfe (danke nochmal Trööt ;-) ) Poste ich jetzt meine Lösung wie ich sie nutze. Mit ein Paar wichtigen Hinweisen:
1) Ich kann nicht versprechen, dass das Fehlerfrei funktioniert. Für mein Anwendungsbereich scheint es zu funktionieren.
2) Und der viel wichtigere Punkt, der den Sicherheitsaspekt betrifft, ist dass dieses update/dofinal Flag sowie dieses Datenlängenfeld in Klartext übermitteltet werden.

Bauchschmerzen macht mir vor allem Punkt 2. Über Feedback würde ich mich sehr freuen.

So genug gelabter hier der Quellcode:

Inputstream:
Java:
package codemaker.stream;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NullCipher;

public class OCipherInputStream extends FilterInputStream {

	private Cipher cipher;
	private InputStream input;
	private byte[] ibuffer = new byte[512];
	private boolean done = false;
	private byte[] obuffer;
	private int ostart = 0;
	private int ofinish = 0;

	private boolean deb = false;
	private void println(String line) {

		if (deb) {
			System.out.println(line);
		}
	}
	
	private int getMoreData() throws IOException {
		if (done)
			return -1;

		int dofinal = input.read();
		println("IN_FINAL>" + dofinal);
		int dataLength=input.read();

		int readin = input.read(ibuffer,0,dataLength);
		println("IN_REDED>" + readin);
		for (int i = 0; i < ibuffer.length; i++) {
			if (ibuffer[i] != 0)
				println("IN_DATA>" + ibuffer[i]);
		}
		

		if (readin == -1) {
			done = true;
			try {
				obuffer = cipher.doFinal();
			} catch (IllegalBlockSizeException e) {
				obuffer = null;
			} catch (BadPaddingException e) {
				obuffer = null;
			}
			if (obuffer == null)
				return -1;
			else {
				ostart = 0;
				ofinish = obuffer.length;
				return ofinish;
			}
		}

		if (dofinal == 1) {
			try {
				obuffer = cipher.doFinal(ibuffer, 0, readin);
			} catch (Exception e) {
				throw new IOException(e.getMessage());
			}
		} else {
			try {
				obuffer = cipher.update(ibuffer, 0, readin);
			} catch (IllegalStateException e) {
				obuffer = null;
			}
		}

		ostart = 0;
		if (obuffer == null)
			ofinish = 0;
		else
			ofinish = obuffer.length;

		return ofinish;
	}

	public OCipherInputStream(InputStream is, Cipher c) {
		super(is);
		input = is;
		cipher = c;
	}

	protected OCipherInputStream(InputStream is) {
		super(is);
		input = is;
		cipher = new NullCipher();
	}

	public int read() throws IOException {
		if (ostart >= ofinish) {
			// we loop for new data as the spec says we are blocking
			int i = 0;
			while (i == 0)
				i = getMoreData();

			if (i == -1)
				return -1;
		}
		return ((int) obuffer[ostart++] & 0xff);

	}

	public int intread(byte b[]) throws IOException {
		return read(b, 0, b.length);
	}

	public int read(byte b[], int off, int len) throws IOException {
		if (ostart >= ofinish) {
			// we loop for new data as the spec says we are blocking
			int i = 0;
			while (i == 0)
				i = getMoreData();

			if (i == -1)
				return -1;
		}

		if (len <= 0) {
			return 0;
		}

		int available = ofinish - ostart;

		if (len < available)
			available = len;

		if (b != null) {
			System.arraycopy(obuffer, ostart, b, off, available);
		}

		ostart = ostart + available;
		return available;
	}

	public long skip(long n) throws IOException {
		int available = ofinish - ostart;
		if (n > available) {
			n = available;
		}

		if (n < 0) {
			return 0;
		}

		ostart += n;
		return n;

	}

	public int available() throws IOException {
		return (ofinish - ostart);
	}

	public void close() throws IOException {
		input.close();
		try {
			// throw away the unprocessed data
			cipher.doFinal();
		} catch (BadPaddingException ex) {
		}

		catch (IllegalBlockSizeException ex) {
		}

		ostart = 0;
		ofinish = 0;
	}

	public boolean markSupported() {
		return false;
	}
}

Outputstream:
Java:
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NullCipher;

public class OCipherOutputStream extends FilterOutputStream {
	private Cipher cipher;
	private OutputStream output;
	private byte[] ibuffer = new byte[1];
	private byte[] obuffer;

	private boolean deb = false;

	private void println(String line) {
		if (deb) {
			System.out.println(line);
		}
	}

	public OCipherOutputStream(OutputStream os, Cipher c) {
		super(os);
		output = os;
		cipher = c;
	}

	protected OCipherOutputStream(OutputStream os) {
		super(os);
		output = os;
		cipher = new NullCipher();
	}

	private void personalWrite(byte[] arr, boolean dofinal) throws IOException {
		if (arr.length == 0)
			return;

		println("OUT_DOFINAL>" + (dofinal ? "1" : "0"));
		println("OUT_WRITED>" + arr.length);
		for (int i = 0; i < arr.length; i++) {
			println("OUT_DATA>" + arr[i]);
		}

		if (dofinal)
			output.write(1);
		else
			output.write(0);
		output.write(arr.length);
		output.write(arr);
	}

	public void write(int b) throws IOException {
		ibuffer[0] = (byte) b;
		obuffer = cipher.update(ibuffer, 0, 1);

		if (obuffer != null) {
			personalWrite(obuffer, false);
			obuffer = null;
		}
	}

	public void write(byte b[]) throws IOException {
		write(b, 0, b.length);
	}

	public void write(byte b[], int off, int len) throws IOException {
		obuffer = cipher.update(b, off, len);

		if (obuffer != null) {
			personalWrite(obuffer, false);
			obuffer = null;
		}
	}

	public void flush() throws IOException {

		try {
			obuffer = cipher.doFinal();
		} catch (IllegalBlockSizeException e) {
			obuffer = null;
		} catch (BadPaddingException e) {
			obuffer = null;
		}

		if (obuffer != null) {
			personalWrite(obuffer, true);
			obuffer = null;
		}
		output.flush();
	}

	public void close() throws IOException {
		try {
			flush();
		} catch (IOException ignored) {
		}
		out.close();
	}

}
 
T

tröööt

Gast
dein problem ist es zu erkennen wann die daten vollständig auf der gegenseite sind ...

in meinem beispiel versende ich HEX-strings die mit einem NEWLINE terminiert werden ... auf welches readLine() reagiert und so erkennt wann der daten-block vollständig ist ...

wenn ich das ganze mit FilterStreams umsetzen müsste würde ich wahrscheinlich auch erstmal vor dem selben problem stehen ... denn wenn man mit RAW-daten arbeitet ist es schwer einen sichere terminator zu finden ... denn der output der crypt-methode kann dieses auch liefern ...

man könnte sich behelfen in dem man read(byte[]) so delegiert das man einen zur blockgröße teilerfremden buffer nutzt und sich so die eigenschaft zu nutze macht das dieser nicht mehr komplett gefüllt ist wenn der daten-block vollständig ist ...

verwendet man also z.b. 1023byte als buffer größe und nutzt AES128 (16byte) als cipher wäre erst bei 16*1023 = 16368 die "kollision" das der buffer voll ist ...
natürlich könnte man sagen das man dann einfach den nächsten block liest und prüft ob dieser leer ist ... aber dort würde read(byte[]) blockieren ...
also könnte man mit InputStream.available() rumtricksen und gucken ob man read(byte[]) noch ohne blockade callen könnte ...
sollten also mal wirklich genau 16368bytes übertragen werden würde available() "0" liefern und man weis damit das der nächste block leer wäre ... so hat man seinen terminator und weis das der daten-block vollständig ist ...

auf der outputstream seite braucht man sich dann nicht um irgendwelche flags kümmern sondern schreibt einfach den output der crypt-methode in den stream und lässt das bisschen logik vom inputstream machen ...


wäre jetzt nur so ne idee und gibt bestimmt bessere methoden ... und bestimmt auch welche um den overhead zu sparen wenn man HEX-strings nutzt ... aber es sind halt einfache möglichkeiten ... und der overhead wird erst bei größeren datenmengen wirklich von bedeutung ...

ich versuch mal n beispiel
Java:
public class CustomCipherOutputStream extends FilterOutputStream
{
	private Cipher cipher;
	public CustomCipherOutputStream(OutputStream out, Cipher cipher)
	{
		super(out);
		this.cipher=cipher;
	}
	public void write(byte[] data) throws IOException
	{
		try
		{
			out.write(crypt(data));
		}
		catch(Exception e)
		{
			throw new IOException(e);
		}
	}
	private byte[] crypt(byte[] data) throws Exception
	{
		ByteArrayInputStream bais=new ByteArrayInputStream(data);
		ByteArrayOutputStream baos=new ByteArrayOutputStream();
		int blockSize=cipher.getBlockSize();
		int outputSize=cipher.getOutputSize(blockSize);
		byte[] input=new byte[blockSize];
		byte[] output=new byte[outputSize];
		int inLength=0;
		boolean finished=false;
		while(!finished)
		{
			inLength=bais.read(input);
			if(inLength==blockSize)
			{
				int outLength=cipher.update(input, 0, blockSize, output);
				baos.write(output, 0, outLength);
			}
			else
			{
				finished=true;
			}
		}
		if(inLength>0)
		{
			output=cipher.doFinal(input, 0, inLength);
		}
		else
		{
			output=cipher.doFinal();
		}
		baos.write(output);
		return baos.toByteArray();
	}
}
Java:
public class CustomCipherInputStream extends FilterInputStream
{
	private Cipher cipher;
	byte[] dataBuffer;
	public CustomCipherInputStream(InputStream in, Cipher cipher)
	{
		super(in);
		this.cipher=cipher;
		dataBuffer=new byte[0];
	}
	public int read(byte[] data) throws IOException
	{
		if(dataBuffer.length==0)
		{
			byte[] buffer=new byte[1024];
			ByteArrayOutputStream baos=new ByteArrayOutputStream();
			while(available()>0)
			{
				int r=in.read(buffer);
				baos.write(buffer, 0, r);
			}
			baos.close();
			byte[] output=crypt(baos.toByteArray());
			if(output.length>data.length)
			{
				System.arraycopy(output, 0, data, 0, data.length);
				dataBuffer=new byte[output.length-data.length];
				System.arraycopy(output, data.length, dataBuffer, 0, output.length-data.length);
				return data.length;
			}
			if(output.length==data.length)
			{
				System.arraycopy(output, 0, data, 0, data.length);
				dataBuffer=new byte[0];
				return data.length;
			}
			if(output.length<data.length)
			{
				System.arraycopy(output, 0, data, 0, output.length);
				dataBuffer=new byte[0];
				return output.length;
			}
			return -1;
		}
		else
		{
			if(dataBuffer.length>data.length)
			{
				System.arraycopy(dataBuffer, 0, data, 0, data.length);
				byte[] dataBufferCopy=dataBuffer.clone();
				dataBuffer=new byte[dataBuffer.length-data.length];
				System.arraycopy(dataBufferCopy, data.length, dataBuffer, 0, dataBufferCopy.length);
				return data.length;
			}
			if(dataBuffer.length==data.length)
			{
				System.arraycopy(dataBuffer, 0, data, 0, data.length);
				dataBuffer=new byte[0];
				return data.length;
			}
			if(dataBuffer.length<data.length)
			{
				System.arraycopy(dataBuffer, 0, data, 0, dataBuffer.length);
				int dbl=dataBuffer.length;
				dataBuffer=new byte[0];
				return dbl;
			}
		}
	}
	private byte[] crypt(byte[] data) throws Exception
	{
		ByteArrayInputStream bais=new ByteArrayInputStream(data);
		ByteArrayOutputStream baos=new ByteArrayOutputStream();
		int blockSize=cipher.getBlockSize();
		int outputSize=cipher.getOutputSize(blockSize);
		byte[] input=new byte[blockSize];
		byte[] output=new byte[outputSize];
		int inLength=0;
		boolean finished=false;
		while(!finished)
		{
			inLength=bais.read(input);
			if(inLength==blockSize)
			{
				int outLength=cipher.update(input, 0, blockSize, output);
				baos.write(output, 0, outLength);
			}
			else
			{
				finished=true;
			}
		}
		if(inLength>0)
		{
			output=cipher.doFinal(input, 0, inLength);
		}
		else
		{
			output=cipher.doFinal();
		}
		baos.write(output);
		return baos.toByteArray();
	}
}
NICHT GETESTET !
ist jetzt nur mal so ausm kopf geschrieben ... kann sein das es noch logik-fehler gibt ... müsste man mal compilen und ausprobieren ... aber das wäre jetzt in etwa so das wie ich n FilterStream implementieren würde ...
kann auch sein das es totaler mist ist und so überhaupt nicht funktionieren kann ... für kritik bin ich offen
 
T

tröööt

Gast
[java=23]byte[] output=crypt(baos.toByteArray());[/code]

doch noch n fehler gefunden ...
müsste natürlich so aussehen
[java=23]try
{
byte[] output=crypt(baos.toByteArray());
}
catch(Exception e)
{
throw new IOException(e);
}[/code]

wie gesagt : mal eben schnell ausm kopf geschrieben ... da passiert so n schusselfehler mal
 
C

codemaker

Gast
Ein kleines Problem ist glaub ich, dass man bei stream.available() ja nur die Anzahl der Bytes bekommt, die bereits beim Client angekommen sind. Jetzt geh im einem Beispiel davon aus, dass wird 20 Bytes Übertragen möchten. Jetzt wird irgendwo im Netz diese 20 Byte in verschiedene TCP-Pakete aufgeteilt. Sagen wir mal in ein 5-Byte, 7-Byte und ein 8-Byte Pakete. Die Pakete mit der Größe 5 und 7 sind schon beim Server angekommen und stream.available() liefert 12 zurück. Das 8-Byte Paket hat auf Grund eines Überlasteten Netzes eine deutliche Verzögerung. Ich glaube, wenn genau dieser Fall eintritt, wird es hier zu Problemen kommen. Ich konnte diesen Fall jetzt nicht simulieren, aber ich könnte mir vorstellen, dass der Server nun denkt die verschlüsselten Daten haben nur eine Länge von 12-Byte wobei 8 fehlen. Ich hoffe meine Bedenken sind nachvollziehbar geschildert. Hast du Tröööt oder sonst wer, schon mal Probleme mit diesem Ansatz gehabt?
Weil das Problem ist, die Pakete die ein Benutzer im Internet losschickt, können von diversen zwischen Stationen in verschiedene Pakte nochmal aufgeteilt werden. Dh. Wenn wir wie in diesem Bsp ein 20-Byte (ok ein sehr kleine Zahl) Paket losschicken heißt das nicht das diese 20-Byte auch in einem Paket ankommen.
Grüße
 
T

tröööt

Gast
Ein kleines Problem ist glaub ich, dass man bei stream.available() ja nur die Anzahl der Bytes bekommt, die bereits beim Client angekommen sind.
schon mal grundsätzlich falsch ...
InputStream.available() liefert nur die anzahl an bytes die mit read() gelesen werden können OHNE das read() blockiert ... diese zahl ist aber nur ein richtwert .. sie kann auch kleiner sein als die tatsächlich im stack liegenden daten ... aber immer nur maximal genau so groß wie wirklich vorhanden ... NIE größer
Jetzt geh im einem Beispiel davon aus, dass wird 20 Bytes Übertragen möchten. Jetzt wird irgendwo im Netz diese 20 Byte in verschiedene TCP-Pakete aufgeteilt. Sagen wir mal in ein 5-Byte, 7-Byte und ein 8-Byte Pakete.
unmöglich ... TCP/IP-pakete werden in der regel nicht fragmentiert ... wenn also eine TCP-seite EIN paket losschickt wird dieses auch so komplett als EIN paket durchs netz geleitet und kommt auch als EIN paket beim empfänger wieder an ...
IP besitzt zwar ein flag welches angibt ob ein IP-paket fragmentiert werden darf oder ob es intakt bleiben muss ... für TCP hat das aber so gut wie keine bedeutung und wird meist nur mit UDP bzw ICMP/PING verwendet um zu sehen wie groß die aktuelle framegröße ist ...
Die Pakete mit der Größe 5 und 7 sind schon beim Server angekommen und stream.available() liefert 12 zurück. Das 8-Byte Paket hat auf Grund eines Überlasteten Netzes eine deutliche Verzögerung. Ich glaube, wenn genau dieser Fall eintritt, wird es hier zu Problemen kommen. Ich konnte diesen Fall jetzt nicht simulieren, aber ich könnte mir vorstellen, dass der Server nun denkt die verschlüsselten Daten haben nur eine Länge von 12-Byte wobei 8 fehlen.
wie bereits gesagt : dieser fall tritt in der regel bei TCP/IP nicht auf ... und wird wenn bereits vom TCP-stack selbst geregelt ... java bekommt davon nichts mit ...
Ich hoffe meine Bedenken sind nachvollziehbar geschildert. Hast du Tröööt oder sonst wer, schon mal Probleme mit diesem Ansatz gehabt?
Weil das Problem ist, die Pakete die ein Benutzer im Internet losschickt, können von diversen zwischen Stationen in verschiedene Pakte nochmal aufgeteilt werden. Dh. Wenn wir wie in diesem Bsp ein 20-Byte (ok ein sehr kleine Zahl) Paket losschicken heißt das nicht das diese 20-Byte auch in einem Paket ankommen.
Grüße
wie gesagt ... heutzutage sind die bedenken eher weniger nachvollziehbar da die heutige infrastruktur so ausgelegt ist das dies in der praxis eben nicht mehr passiert ... obwohl es in den RFCs natürlich immer noch "möglich" ist ...
und selbst wenn es mal vorkommen sollte ... dann fliegt im cipher eine exception weil der block halt nicht vollständig ist ... und die kann man abfangen und dann einfach die letzte nachricht noch mal vom server anfordern ...

wenn du also auf nummer sicher gehen willst sind es nur ein paar mehr zeilen ... aber praktisch hat sowas halt heute keine bedeutung mehr
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
M Verständnisfrage zu den Streams Netzwerkprogrammierung 7
J Threads & Streams Netzwerkprogrammierung 9
N Paket-Analysieren Byte-Streams Netzwerkprogrammierung 12
E Verfügbarkeit von Daten in Streams Netzwerkprogrammierung 4
V HTTP Streams setzen Netzwerkprogrammierung 10
N Socket Fehler bei Streams Netzwerkprogrammierung 2
1 SSH-Kommunikation - Ende eines Streams nicht erkenntlich Netzwerkprogrammierung 2
D Socket Streams schliessen .. Exception gewollt? Netzwerkprogrammierung 4
B Server mit meheren Streams/Aufgaben? Netzwerkprogrammierung 9
H RMI RPC "not suitable for streams and.." Netzwerkprogrammierung 2
T HTTP Encoding von Http-Streams Netzwerkprogrammierung 2
L mehrere Streams über einen Socket? Netzwerkprogrammierung 8
V Mehrere Streams durch einen Stream senden Netzwerkprogrammierung 14
M Streams verwenden Netzwerkprogrammierung 3
A Streams per RMI übergeben Netzwerkprogrammierung 6
P problem beim schließen eines Streams Netzwerkprogrammierung 6
K Selbe Streams mehrfach nutzen (zusätl. Thread) Netzwerkprogrammierung 6
J while-Schleife / Abbruchbed. beim Einlesen eines Streams Netzwerkprogrammierung 4
J Länge eines Streams Netzwerkprogrammierung 4
M Streams Bündeln Netzwerkprogrammierung 10
P Probleme mit Input- / Output-Streams Netzwerkprogrammierung 2
M Ende des Streams ohne Schließen/Checksumme mitsenden Netzwerkprogrammierung 2
M Probleme beim Abfangen von Streams Netzwerkprogrammierung 5
8 Socket Streams nur mit Byte? Netzwerkprogrammierung 2
E frage zu streams Netzwerkprogrammierung 2
F ResultSet in Streams Netzwerkprogrammierung 8
C IRC CHAT auslesen -> Sockets/input und output Streams Netzwerkprogrammierung 9

Ähnliche Java Themen

Neue Themen


Oben