2016-03-24 7 views
0


Ich habe den Java-Server, der die RTMP-Pakete empfängt, die von der Client-App gesendet werden. Der Server liest die packet header mit InputStream, erkennt, wie groß die packet body ist, erstellt dann byte array mit der size und liest dann die body von InputStream in der .
Das Problem ist: der empfangene Satz von Bytes sind geändert - es gibt notwendige Bytes (die in der Quelle existieren) stehen mit zusätzlichen Bytes, die nicht im Quellpaket existieren (ich beobachte den Inhalt des Quellpakets über WireShark und vergleichen Sie sie mit den Bytes, die ich auf dem Server erhalten habe).
Diese zusätzlichen Bytes 0xc6 Bytes sind, die periodisch von der Art und Weise treffen ...
Es sieht wie folgt aus:
Source: ... 75 f1 f5 55 73 .... fc a9 47 14 ... 40 ca d5 75 ... fe 30 a7
Received: ... 75 f1 f5 55 73 c6 .... fc a9 47 14 c6 ... 40 ca d5 75 c6 ... fe 30 a7
... - bedeutet "eine gewisse Menge von Bytes hier"
Als Ergebnis Ich kann keine notwendigen Daten empfangen, weil es gestreckt ist, es ist größer als es sein muss, als die body size, die ich von rtmp header erhalten habe. Und am wichtigsten ist, dass diese modifizierten Daten nicht das sind, was ich empfangen musste!
Meine Fragen sind: Wie kann es behoben werden? Was ist los mit InputStream? Warum fügt es diese 0xc6 Bytes in das empfangende Array ein?
Ich verstehe, dass ich empfangene Array einfach analysieren und diese zusätzlichen Bytes ausschließen kann, aber das ist schlechte Lösung, da Geschwindigkeit und Leistung erforderlich sind (und in diesem Fall ist es nicht klar, dass es ein zusätzliches Byte oder Byte aus der Quelle ist) der Vergleich von ganzer Arrays) ...InputStream liest zusätzliche Bytes, die in Quelle nicht vorhanden sind

enter code here 
public static void getRtmpPacket(InputStream in) throws Exception { 

    byte[] rtmpHeader = new byte[8]; 
    byte[] rtmpBody; 
    int bodySize = 0; 

    //reading rtmp header: 
    in.read(rtmpHeader); 
    //reading the body size. This method works fine 
    bodySize = Server.bigEndianBytesToInt(rtmpHeader, 4, 3); 
    rtmpBody = new byte[bodySize]; 
    in.read(rtmpBody); 
    //printing received data: 
    System.out.println("Packet:"); 
    System.out.println("Body size: " + bodySize); 
    System.out.print(bytesToString(rtmpHeader) + " "); 
    System.out.print(bytesToString(rtmpBody)); 
    System.out.println(); 

} 
+1

-Code, bitte. Vorzugsweise reduziert auf [mcve]. – RealSkeptic

+1

'InputStream' macht das nie. Wenn dies der Fall ist, bedeutet dies, dass die Quelle nicht so gut gebunden ist, wie Sie denken. – fge

+0

Dies ist nicht glaubwürdig. Offensichtlich haben Sie Bugs in dem Code, den Sie nicht gepostet haben, wie zum Beispiel 'bytesToString()'. – EJP

Antwort

2

Nach dem RTMP spec verhält es sich ganz normal.Sie müssen die eingehenden Daten "entknüpfen", so dass das Lesen in einem einzigen Lesevorgang() nicht funktioniert.

Etwas in dieser Richtung (Pseudo-Code):

int remaining = payloadSize; 
int totalRead = 0; 
int totalReadForChunk = 0; 
while (true) { 
    int num = read(buf, 0, min(remaining, chunkSize - totalReadForChunk)) 
    if (num < 0) break; // i/o error 
    appendData(<buf>, 0, num) 
    totalReadForChunk += num 
    remaining -= num 
    if (remaining == 0) break; // end of payload 

    if (totalReadForChunk == chunkSize) { 
    totalReadForChunk = 0; 
    // read the chunk header (it's not neccessarily 0xc6) 
    int header = read() 
    if (header != currentStreamEmptyHeader) { // 0xc6 
     // ... parse the new rtmp message according to header value 
     // (usually invoke the upper-level message reading method "recursively") 
    } 
    } 
} 
+0

danke für Ihr Beispiel. Bitte korrigieren Sie mich, wenn ich falsch liege: Wie ich verstanden habe, meinen Sie, dass ich alle Pakete Stück für Stück lesen muss (zum Beispiel, wenn die Stückgröße 128 Bytes beträgt, lesen Sie diese 128 Bytes, und tun Sie es dann erneut bis zur Ende der Körpergröße)? Sorry für dumme Fragen, ich bin ein Neuling in diesem Bereich ... – Aeon

+0

Ja, versuchen Sie einen ganzen Chunk zu lesen (oder weniger, wenn die verbleibenden erwarteten Daten kleiner sind), und nach jedem ganzen Chunk, wiederholen Sie den Prozess von der höheren layer (z. B. so, als ob Sie eine neue Nachricht lesen würden, die sich im selben Stream oder in einem anderen befindet, entsprechend dem nächsten Byte, das Sie lesen werden, welches der nächste Chunk-Header ist). Das bedeutet, dass Sie mit einigen anderen Nachrichten aus anderen Streams enden können, bevor Sie die Nutzdaten des aktuellen gelesen haben. –

+0

Bitte beachten Sie mein aktuelles Codebeispiel. –

0

Wahrscheinlich, sollten Sie (und verwenden) Code von Red5 Media Server und anderen Open-Source-Lösungen sehen, die RTMP-Protokoll implementieren.

0

InputStream.read (Byte []) ist nur garantiert, ein Byte zu lesen, und es gibt die Länge als int der tatsächlichen Länge gelesen.

in.read(rtmpHeader); // might read 1, 2, 3, .. 8 bytes. 
//reading the body size. This method works fine 
bodySize = Server.bigEndianBytesToInt(rtmpHeader, 4, 3); 
rtmpBody = new byte[bodySize]; 
in.read(rtmpBody); // might read 1, 2, 3, ... bodySize bytes. 

Wenn Sie nicht die tatsächliche Länge überprüfen und übernehmen die byte [] voll ist, können Sie bekommen, was Bytes, wo es, bevor Sie lesen() aufgerufen.

Was Sie da gedacht ist Datainputstream mit

DataInputStream dis = new DataInputStream(in); 

int len = dis.readInt(); // read an int in big endian. 
byte[]] bytes = new byte[len]; 
dis.readFully(bytes); // read the whole byte[] or throw an IOException. 
+1

Alles, was Sie geschrieben haben, ist völlig richtig, aber es scheint nicht den Hauptanspruch und die Sorge des OP zu erklären: dass in seiner einzigen 'read()', die die gesamte Nachrichtennutzlast eingeben soll, falsche Bytes mit den erwarteten vermischt werden (nicht nur am Ende). –

+0

@JohnBollinger es ist nicht klar, ob die falschen Bytes in der Kopfzeile, im Körper oder am Ende sind. Es ist möglich, dass das Format nicht das ist, was das OP erwartet, z.B. es könnte ein 9-Byte-Header sein .... –

0

Das Problem behoben ist.
Diese zusätzlichen 0xc6 Bytes waren die Chunking-Bytes des RTMP-Pakets, die vom WireShark nicht sichtbar waren.
Mehr als das, empfangen Header sagt die tatsächliche Körpergröße und WireShark "bestätigt" es, aber in der Tat wird die Körpergröße größer sein, und sollte berechnet werden.

+0

RTMP-Chunking ist auf der unteren Ebene des Transports, daher sollte es Priorität beim Zerlegen der tatsächlichen RTMP-Nachrichtennutzlast haben. Beachten Sie, dass es mit jeder neuen RTMP-Nachricht zurückgesetzt wird. Vergessen Sie nicht, es auch bei der Datenrückmeldung hinzuzufügen. Es kann passieren, dass Ihre Payload manchmal größer ist als die aktuelle Chunkgröße und Sie nicht wissen, warum Sie eine geschlossene Verbindung haben (der Server ist nicht in der Lage) Parsen Ihrer Nachrichten). –

+0

@ AdrianCreţu Könnten Sie mir bitte ein Beispiel für diesen Prozess geben? Ich brauche wirklich detaillierte Informationen über Chunking (richtig receiving diese Stücke auf dem Server und Senden an andere Peer), weil ich einige Probleme damit habe, und offizielle Spezifikation ist nicht genug – Aeon