BufferedInputStream.read() blockiert und verweigert die Arbeit



  • Hi,

    meine Frage bezieht sich sowohl auf Java als auch auf C. Darum stelle ich sie einfach mal hier rein.

    Ich habe Probleme, eine einfache Datei zu senden. Zuerst sende ich die Dateigröße, dann splitte ich die Datei in 1000 Byte Blöcke und sende diese von einem C zu einem Java Socket.

    int coverLength = f3->picture().size(); // Größe in Bytes
    sprintf_s(buf, 10, "%d\n", coverLength);
    
    // send file size
    result = send(c,buf,strlen(buf),0);
    
    // file data
    int result;
    
    bool carry = false;
    int count, maxCount = f3->picture().size() / 1000;	// 1000 byte Blöcke
    if((f3->picture().size() % 1000) != 0)
    {
    	maxCount++;
    	carry = true;
    }
    
    for(count = 0; count < maxCount; count++)
    {
    	if(count == maxCount-1 && carry == true)
    		result = send(c, f3->picture().data()+count*1000, (f3->picture().size() % 1000), 0);
    	else
    		result = send(c, f3->picture().data()+count*1000, 1000, 0);
    
    	if (result == -1)
    		return -1;
    }
    

    Mit Java (Android SDK) werden die Daten empfngen:

    int coverLength;
    
    // receive file size
    try {
    	coverLength = Integer.parseInt(inFromServer.readLine()); // Das funktioniert perfekt, die korrekte Dateigröße wird empfangen. inFromServer ist ein BufferedReader
    } catch (IOException e) {
    	return 1;
    }
    
    // file data
    if(coverLength != 0)
    {
    	try {
    		byte[] imageBytes = new byte[coverLength];
    
    		int length, count = 0;
    
    		while(count < coverLength)
    		{
    			length = inputStream.read(imageBytes, count, coverLength-count); // inputStream ist ein BufferedInputStream
    			count += length;
    		}
    	} catch (IOException e) {
    		return 1;
    	}
    }
    

    Doch das ganze funktioniert nicht 100%ig. Mit dem Debugger konnte ich zwei Fälle feststellen:

    1. Die Daten werden gesendet, bevor sie empfangen werden: inputStream.read() blockiert total, nichts passiert. Es gibt nichts aus, obwohl Daten schon angekommen sein sollten.

    2. inputStream.read() wird aufgerufen, bevor die Daten gesendet werden: alles funktioniert 100%ig. Die Daten werden korrekt übermittelt.

    Ich kämpfe nun seit Stunden damit, doch ich konnte es einfach nicht ordentlich zum Laufen bekommen. Besonders der erste Fall ist mir wichtig wegen der langsamen JVM.

    Stimmt irgendetwas mit dem Code nicht? Oder habe ich etwas vergessen? Das wirkt etwas merkwürdig auf mich, weil read() einfach die Arbeit verweigert.

    Würde mich über ein paar Tipps sehr freuen,
    danke 🙂
    Martin



  • inFromServer
    ...
    inputStream
    

    Warum hast du 2 InputStreams die aus der selben Quelle lesen? Kein Wunder dass das nicht funktioniert.

    Besonders der erste Fall ist mir wichtig wegen der langsamen JVM

    lol



  • Oh, ich wollte einfach eine readLine() und eine read(byte[] b, int off, int len) Methode haben. Beides zusammen habe ich nur in der Klasse DataInputStream gefunden, doch dort heißt es bei getline(): "Deprecated. This method does not properly convert bytes to characters."

    http://download.oracle.com/javase/1.4.2/docs/api/java/io/DataInputStream.html#readLine()

    Gibt es da denn da gar keine passende Klasse für?



  • In den Docs der von dir verlinkten Methode steht doch welche Klasse du statt dessen einsetzen kannst:

    in = new BufferedReader(new InputStreamReader(socket.getInputStream()))
    in.readLine()
    

    Alternativ kannst du auch einen Scanner benutzen, der ein bisschen einfacher in der Handhabung ist:

    in = new Scanner(socket.getInputStream())
    in.nextLine()
    


  • Ja aber wenn ich in = new BufferedReader(new InputStreamReader(socket.getInputStream())) benutze, kann ich kein
    in.read(byte[] b, int off, int len) sondern nur ein
    in.read(char[] cbuf, int off, int len) ausführen.

    Der Scanner sieht ganz gut aus, da er readLine() hat, er kann jedoch nur einzelne Bytes lesen, wie ich das sehe. Würde zwar gehen, aber nicht so schön wie ein Byte array einzulesen mit dem BufferedInputStream.



  • Mit

    new Scanner(...).useDelimiter("\n").next().getBytes()
    

    kannst du den Scanner dazu bringen bis zu einem bestimmten Zeichen deiner Wahl zu lesen (hier '\n') und dir dann ein Byte-Array zurück zu geben.
    Ansonsten bietet dir die Klasse ByteArrayInputStream vllt. was du suchst.



  • Tut mir Leid, ich muss mich nocheinmal melden, trotz eurer tollen Bemühungen :| Die Scannermethode sieht gut aus, doch brauche ich die Bytedarstellung wirklich um eine Datei zu empfangen. Und da bringt ein String-Delimiter nichts, der würde ja mitten drin unterbrechen. Und die Klasse ByteArrayInputStream bietet keine Möglichkeit, um einen String bis zu einem Zeilenumbruch zu lesen...

    EDIT: ein ankommendes Byte-Array wird immer durch einen bestimmten String angekündigt, also sollte das doch ohne Probleme klappen?



  • Die Dateien werden doch bestimmt anhand von irgendwelchen nicht druckbaren Steuerzeichen begrenzt (z.B. '\0')? Oder gibt es keine Begrenzer?



  • '\0' begrenzt doch normalerweise eine Zeichenkette? Eine JPG-/PNG-Datei (nur solche werden verschickt) werden hingegen doch durch ein EOF begrenzt? Und das ist doch gar nicht als character darstellbar, so wie '\0'?
    Mein Gedanke war nur gerade, dass ein Begrenzer auch eine Byte-Darstellung hat und diese könnte zufällig in der Byte-Darstellung der Datei vorkommen...


Anmelden zum Antworten