2009-08-22 12 views
3

Ich möchte eine Zeichenfolge aus einem TCP-Stream lesen, die mit einer Byte-Länge gefolgt von den tatsächlichen Daten angegeben wird. In Python würde ich tunJava NIO: Blöcke variabler Größe lesen

length = ord(stream.read(1)) 
data = stream.read(length) 

Wie mache ich das gleiche in Java NIO? Was ich habe, ist ein Puffer (Kapazität 257)

stream.read(buffer); // cannot specify a size here 
int length = buffer.get(); 
byte[] data = new byte[length]; 
buffer.get(data); 

Leider ist dies nicht funktioniert: die get() Anrufe lesen Vergangenheit die Daten im Puffer :-(

ich wahrscheinlich brauchen einige Kombination von Flip, Zurückspulen, Reset, etc., aber ich kann es nicht herausfinden ..

+0

Was für eine Art von Objekt ist 'Stream' in Ihrem Java-Beispiel? – Bkkbrad

+0

Es ist ein SocketChannel. –

Antwort

5

wenn stream ist ein SocketChannel und buffer ein ByteBuffer ist, können Sie wie folgt vorgehen:

//assuming buffer is a ByteBuffer 
buffer.position(0); 
buffer.limit(1); 
while (buffer.hasRemaining()) { 
    stream.read(buffer); 
} 
buffer.rewind(); 

//get the byte and cast it into the range 0-255 
int length = buffer.get() & 0xFF; 
buffer.clear(); 
buffer.limit(length); 
while (buffer.hasRemaining()) { 
    stream.read(buffer); 
} 
buffer.rewind(); 
//the buffer is now ready for reading the data from 
+0

Danke, das sollte gut funktionieren - obwohl es ziemlich kompliziert aussieht. –

+1

Ausführlich, nicht kompliziert. –

+0

es ist nicht so einfach, man muss bedenken, dass es nicht notwendig ist, alle Bytes auf einmal zu empfangen oder mehrere Nachrichten gleichzeitig empfangen zu haben. –

0

Ich schlage vor, Sie haben einen Blick in java.nio.channel.GatheringByteChannel und DatagramChannel.Sie müssen angeben, a Datagramm für Ihre Bedürfnisse

Das ist wh Bei Ihrem Python-Beispiel (das erste Byte gibt die Nutzlastlänge an, lesen Sie das Playload mit dieser Länge), das wirklich fehleranfällig aussieht (!).

Ein Datagramm ist eine Spezifikation für einen Datenstrom. Es unterteilt Ihren Stream logisch in Pakete. Eine bessere Strategie wäre also, zuerst ein Payload-Paket zu senden, das die Länge der Payload (und die Paketgröße) angibt. Edit: Natürlich müssen beide Seiten des Streams die gleiche Protokoll/Datagramm-Sprache sprechen.

+0

Ich verstehe Ihre Empfehlung nicht. GatheringByteChannel ist eine Schnittstelle, die bereits von SocketChannel implementiert wird, die ich bereits verwende - AFAIU, das ist der Standardkanal für TCP. DatagramChannel ist irrelevant, wie es für UDP ist, und ich mache TCP. Ich verstehe auch nicht, warum ein Protokoll, das zuerst die Länge und dann die Nutzlast sendet, fehleranfällig ist - so funktioniert beispielsweise HTTP 1.1. –

+0

Ich habe einige Details mit Ihrem Problem verpasst. Dachte, du hast mehr ein Problem mit der Zuweisung als mit ByteBuffer Methoden;) Wie auch immer, wenn Ihre Nutzlast 255 Byte nicht überschreitet, ist Bkkbrads Lösung geradlinig. – cafebabe