Socket Daten lesen ohne Längenangabe

kennux

Mitglied
Hallo Forum,
Ich bin eben auf dieses Forum per google gestoßen und möchte mal fragen,
Wie ich Daten aus einem Socket (Mit dem BufferedReader) auslesen kann, ohne dass ich eine längen angabe habe.
readLine() würde nicht funktionieren, da in den Daten kein \n ist.
Es sind mit rc4 verschlüsselte Pakete. readLine() lässt also den SocketThread freezen.

Ich wäre über jede Hilfe sehr dankbar 🙂
 
Kenne mich nicht mit rc4 aus, aber gibts dafür keinen decoder, wenn du das encoded hast?

Ansonsten wäre es möglich mit einer while-Schleife bis zum Ende des Stream per read() zu lesen und das dann manuell zusammenbauen.
 
Ja, das ist mir auch schon eingefallen. Ich könnte die Daten theoretisch mit ner Buffer Methode lesen, aber das ist mir eigentlich zu umständlich.
Wer nicht weis, wie die Daten mit RC4 gesendet werden:
Hexadezimal (z.B. FFEEAA = 3 char's)
Daher habe ich auch keinen Endpunkt.
 
Okay, ich werd das mal eben versuchen. Weist du evtl. wie ich die länge der Daten im Stream herausbekomme (für das erstellen des Arrays)?
 
Da es ein Stream ist, kannst du es nicht wissen. Aber wenn du ein bufferedReader hast, dann kannst du dir ja ein String zusammenbauen.

Java:
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
char[] cb = new char[1];

String hallo = "";
while(br.read(cb) != -1) {
     hallo = hallo + new String(cb);
}

Keine Garantie, dass das die beste Lösung ist. Mir fällt aber nix anderes ein, außer du erstellst bis zu einer Grenze immer wieder neue Buffer, bis das Ende des Streams erreicht ist.
 
Funktioniert auch soweit ganz gut, nur der Code danach (Wenn ich es mit System.out.println() ausgeben will) läuft nicht durch. Das gesamte Thread feezed dann. Ich weis auch nicht, wodran das liegt.
Im Debugmodus bekommt er die Paketdaten ganz brav aber er läuft einfach nach dem while nicht weiter (auch nach dem die Schleife durch ist, hab mit Breakpoints geschaut).
Edit://
Hier ist der Code:

Java:
char[]buffer = new char[1];
String tmp_rc4 = "";
while(in.read(buffer) != 1) {
	tmp_rc4 = tmp_rc4 + new String(buffer);
}
System.out.println(tmp_rc4); // Hier bleibts hängen. Es wird nix ausgegeben und läuft ned weiter.
 
Zuletzt bearbeitet:
Also wieso hast du denn das:

Java:
while(in.read(buffer) != 1)

read() liefert doch beim Ende eine -1 .

Hast du beim debuggen mal geschaut, ob dein String richtig aufgebaut wird?
 
Ah, hab's nur falsch abgeschrieben. Programmiere den Server auf meinem Laptop (Keine Internetverbindung). Habe im SourceCode -1 stehen.
 
Die while Schleife läuft solange die Verbindung noch offen ist.
Entweder Du beendest die Verbindung zwischen Server und Client.
Oder benutzt für die Kommunikation ein Protokoll.
 
Wäre natürlich auch eine Möglichkeit. Wenn du selbst rc4 Daten sendest, kannst die nochmal in ein Container packen, damit du weisst, wann eine Nachricht zu Ende ist. Ansonsten wirst du wohl die Verbindung jedes mal schliessen müssen (Server-Seite). Oder vllt. hilft ein flush() ?
 
Hab grad was gefunden (arbeite auch z.Z. mit sockets etc.)

If there are no bytes buffered on the socket, and the socket has not been closed using close, then available() will return 0.

Also versuch mal sowas:
Java:
while (socket.getInputStream().available() != 0) { 
     .... String zusammenbauen ...
}
 
Java:
tmp_rc4 = tmp_rc4 + new String(buffer);

Für solche Sachen bitte den StringBuilder verwenden. Das liegt daran, das beim 'addieren' von Strings immer wieder ein neues Stringobjekt erstellt wird, und folglich immer wieder Platz geschaffen werden muss. Außerdem muss das alte Stringobjekt immer wieder gelöscht (durch gc) werden. Bei langen Strings kommt es deshalb zu echten Performance-Problemen!

Also besser so:
Java:
StringBuilder builder=new StringBuilder();
char c;
while((c=in.read()) != -1) {
   builder.append(c);
}
String fertigerString=builder.toString();
(nicht getestet)
 
So, erstmal danke für die Antworten. Das mit dem != -1 funktioniert irgendwie nicht.
Das mit dem available() werd ich noch testen. Ich kann das Protokoll nicht verändern, da das ein kleines Private Server projekt ist.
Ich poste, wenn ich das mit available() getestet hab.

Edit://
Hab's gelöst bekommen. Danke!
 
Zuletzt bearbeitet:
Es kann gar nicht korrekt funktionieren.
Daten werden über das Netzwerk/Internet in kleine Packages aufgeteilt, was du mit einem Befehl über die Leitung sendet, kann in echt in 20 einzelnen Paketen ankommen.
Das wäre soweit natürlich noch kein Problem, jedoch folgt daraus auch, dass wenn 2 Nachrichten hintereinander verschickt werden, es unbekannt ist, wo die eine Nachricht aufhört und die andere anfängt, oder ob eine Nachricht überhaupt schon komplett empfangen wurde.

Du musst also entweder einen Delimiter zum Trennen implementieren (NUL-Byte, \n) oder vor einem Paket eine Größenangabe als 4Byte Integer vorrausschicken, also nach dem Motto: es folgt eine Nachricht von x Bytes.

Pseudocode:
Code:
byte b[] = read4Byt();
int len = b[] in integer umwandeln

while geleseneBytes < len
  bytes von Stream lesen



PS.: Available kann auch nicht funktionieren, wirf einen Blick in die Java-Dokumentation zu InputStream.available()
 
Das steht aber bei Socket.getInputStream() in der API ...

If there are no bytes buffered on the socket, and the socket has not been closed using close, then available will return 0.

Im Umkehrschluss heißt das für mich: Wennd a noch was ist, dann ist available() ungleich 0. Ich erinner mich dunkel, dass ich das damit mal probiert hatte und es funktionierte.

Aber bei dem Rest stimme ich ohne bedenken zu. Ohne einen definierten Endpunkt kann es sein, dass du nur halbe Nachrichten dekodierst etc.
 
K, kann möglich sein, InputStream.available() gibt per Default aber immer 0 zurück, wenn der Socket einen InputStream zurückliefert, der diese Eigenschaft erfüllt, kann er zwar lesen, wieviele Daten noch im Buffer stecken, das Problem mit dem erkennen der Nachrichtengrenzen besteht aber noch immer.
 
Es war etwas mit der RC4-Klasse! Ich kann wenn z.B.
A3FD10E5 gesendet wird ist bei dem Privateserver das erste Byte immer "@", dann kommt eine Längenverschlüsselung (immer 2 Bytes) und dann der Header + Daten.
Ich habe dann anhand von dem String (A3FD10E5) erstmal die ersten 6 Bytes ausgelesen (rc4 macht 3 Bytes wegen Hexadezimal draus), dann die Länge gesplittet und dann die länge mal 2 (Wegen RC4) ausgelesen und boom, das paket kommt perfekt an (Wusste nicht, dass ich die Paketteile einzeln durch die RC4 jagen kann 😀)
 

Zurück
Oben