Socket InputStream liest nicht vollständig

MichaelGER

Mitglied
Hallo,

ich schreibe zurzeit ein kleines Projekt für Minecraft. Unter anderem soll damit die Konsole überwacht werden.

Auf dem Server läuft ein ServerSocket, der die Verbindungen entgegennimmt.
Der Client verbindet über "normalen" Socket.
Die Verbindung findet über Streams statt (TCP).

Wenn ich den Server bei mir starte, und dort den Inhalt der Konsole abfrage, kommt der komplette Inhalt an. Sobald ich das gleiche auf einem externen Server probiere gibts allerdings Probleme. Zu Übertragung habe ich mir ein paar Methoden geschrieben.

Hier ein Auszug der wichtigen (die System.out.println() sind nur zum Finden des Fehlers drin)

Java:
    public static void writeStringList(ArrayList<String> strings, OutputStream out) throws IOException
    {
        writeInt(strings.size(), out);
        for (String s : strings)
        {
            writeString(s, out);
        }
    }

    public static String[] readStringList(InputStream in) throws IOException
    {
        int num = readInt(in);
        String[] strings = new String[num];
        for (int i = 0; i < num; i++)
        {
            strings[i] = readString(in);
        }
        return strings;
    }

    public static void writeString(String string, OutputStream out) throws IOException
    {
        byte[] bytes = string.getBytes();
        System.out.println("Schreibe int: " + bytes.length);
        writeInt(bytes.length, out);
        System.out.println("Schreibe String:" + string);
        out.write(bytes);
        out.flush();        
    }

    public static String readString(InputStream in) throws IOException
    {
        int len = readInt(in);
        System.out.println("Empfange String der Laenge: " + len);
        byte[] bytes = new byte[len];
        in.read(bytes);
        String s = new String(bytes);
        System.out.println("String empfangen: " + s );
        return s;
    }

    public static void writeInt(int i, OutputStream out) throws IOException
    {
        out.write(intToByteArray(i));
        out.flush();
    }

    public static int readInt(InputStream in) throws IOException
    {
         byte[] intBytes = new byte[4];
         in.read(intBytes);
         ByteBuffer buff = ByteBuffer.wrap(intBytes);
         int i = buff.getInt();
         return i;
    }

    public static byte[] intToByteArray(int i)
    {
        byte[] intBytes = new byte[4];
        ByteBuffer buff = ByteBuffer.wrap(intBytes);
        buff.putInt(i);
        return intBytes;
    }

Der Server hat jede Zeile der Konsole als eigenen String in einer ArrayList. Diese sendet er über die Methode writeStringList().

Der Client liest mit readStringList().

Das ganze klappt mit den ersten ca. 150 Zeilen ohne Probleme.

Doch dann tritt folgendes auf:

Server:
Schreibe int: 56
Schreibe String: [WorldGuard] (world_nether) Fire spread is UNRESTRICTED.

Client:
Empfange String der Laenge: 56
String empfangen: [WorldGuard] (worl

Empfange String der Laenge: 1683975781
Exception in thread "IOQueue" java.lang.OutOfMemoryError: Java heap space

Diese 1683975781 sind genau die nächsten 4 Bytes (d_ne).
Außer dieser einen Exception wurde keine weitere geworfen.

Meine Fragen:
Wieso bricht der Stream hier ab, bevor er die 56 Bytes vollständig gelesen hat?
Ich übergebe den oben genannten Methoden Buffered Streams, hat das etwas mit dem Problem zu tun? (kann ich mir zwar nur schwer vorstellen, aber wer weiß 😛)
Hab ich hier einen Fehler drin?
Gibts eine bessere Möglichkeit das zu erledigen?

Für Antworten, Hinweise, Ideen, Vorschläge, etc. bin ich dankbar 🙂
 
Du mußt erstmal den OutOfmemory wegbekommen, sonst kannst halt auch nix mehr lesen.

Empfange String der Laenge: 1683975781

ist ein bisschen irreführend. Ich hatte gedacht der String wäre 1683975781 Zeichen lang, es ist wohl aber einfach ein int, das gelesen wurde.
 
Erstmal danke für die Antwort 🙂

Du mußt erstmal den OutOfmemory wegbekommen, sonst kannst halt auch nix mehr lesen.

Der OutOfMemory ist eher das Resultat eines Fehlers(siehe nächster Absatz)


ist ein bisschen irreführend. Ich hatte gedacht der String wäre 1683975781 Zeichen lang, es ist wohl aber einfach ein int, das gelesen wurde.

Richtig. Erst wird der int gelesen. Dieser sagt, wie lange der folgende String ist. Dementsprechend viel Speicher wird reserviert. Weil der int hier so groß ist -> OutOfMemory.

So groß ist der int aber eigentlich gar nicht (der Server schreibt ja einen viel kleineren int). Aber da hier mitten im String aufgehört wird zu lesen, werden die nächsten 4 bytes (in dem Fall "d_ne") eingelesen und als int gewertet. Daher der falsche Wert.
 
@TO
ich geb dir mal n tipp

1) das hier ist KEIN minecraft-forum ... melde dich bei problemen bitte in den entsprechendne foren *so wie mir das aussieht ist das Bukkit*
2) wenn überhaupt ... dann verwendet man für Objekte den [japi]ObjectOutputStream[/japi]
alternativ kann man bei reinen Strings auch BufferedWriter/PrintStream und auf der anderen seite BufferedReader verwenden ...
3) nimm um gottes willen das static raus ... das sieht ja aus wie von nem 2-wochen-anfänger ...
 
1) das hier ist KEIN minecraft-forum ... melde dich bei problemen bitte in den entsprechendne foren *so wie mir das aussieht ist das Bukkit*

Jop, ist Bukkit. Aber ich arbeite hier beim versenden der Daten (und beim Clienten) nur mit Java Bordmitteln, da bin ich hier, glaub ich jedenfalls, besser aufgehoben 😉

2) wenn überhaupt ... dann verwendet man für Objekte den [japi]ObjectOutputStream[/japi]
alternativ kann man bei reinen Strings auch BufferedWriter/PrintStream und auf der anderen seite BufferedReader verwenden ...

Bisher schicke ich das alles über byte Arrays (byte[]). Also meinst du, es ist sinnvoller, das mit oben genannten Mitteln zu machen?
Dachte halt, dass byte Arrays universal einsetzbar sind.


3) nimm um gottes willen das static raus ... das sieht ja aus wie von nem 2-wochen-anfänger ...

Ich hätte vielleicht dazu schreiben sollen:
Oben handelt sich es um eine eigene kleine Library, welche eingebunden wird (der Server und Client müssen ja auf die gleiche Weise die Daten behandeln). Da diese Library nur ein paar Methoden hat und keinerlei Variablen, oder sonstwas, erschien mir hier das static ein wenig sinnvoller (ähnlich dem Java Math Paket).

Wenn das aber natürlich totaler Schwachsinn ist, änder ich das gerne um 🙂
 
Zuletzt bearbeitet:
mit dem verweis aufs bukkit forum wollte ich eigentlich eher sagen das die da genau wissen wie sowas mit SE mitteln baut ...
wir können dir hier dafür eher weniger bis gar keinen support geben

ja ... ansich ist es besser nur dierekt mit byte-arrays zu arbeiten ... aber da du damit ja probleme hast und eigentlich ein komplexes object ... nämlich die List<?> ... wäre es für dich einfacher mit [japi]ObjectInputStream[/japi] und [japi]ObjectOutputStream[/japi] zu arbeiten ... da du dir dann auch keine gedanken über z.b. irgendwelche längen zu machen wo es ja gerade dran hakt

und das static gehört da nicht rein weil du auf beiden seiten instanzen hast ... sowohl im bukkit die instanz von "JavaPlugin" als auch in deinem client iwas

zusätzlich solltest du deine "lib" in server-plugin und client aufteilen ... das spart einem später viel arbeit
 
wir können dir hier dafür eher weniger bis gar keinen support geben

Keine Sorge, das verlange ich auch gar nicht 🙂

ja ... ansich ist es besser nur dierekt mit byte-arrays zu arbeiten ... aber da du damit ja probleme hast und eigentlich ein komplexes object ... nämlich die List<?> ... wäre es für dich einfacher mit [japi]ObjectInputStream[/japi] und [japi]ObjectOutputStream[/japi] zu arbeiten ... da du dir dann auch keine gedanken über z.b. irgendwelche längen zu machen wo es ja gerade dran hakt

Erkennt dann die readObject() Methode vom ObjectInputStream automatisch wie lange das Objekt ist? Vorallem da der ObjectOutputStream ja noch andere Methoden zum Schreiben von Strings, Integers, etc. bietet wär das dann wirklich die bessere Alternative.

und das static gehört da nicht rein weil du auf beiden seiten instanzen hast ... sowohl im bukkit die instanz von "JavaPlugin" als auch in deinem client iwas

Also zählt hier das static auch nicht, obwohl die Funktionen in einer Utility-Klasse (jedenfalls ist sie so designed) sind?

zusätzlich solltest du deine "lib" in server-plugin und client aufteilen ... das spart einem später viel arbeit

Bisher ist das so:
Server und Client sind jeweils eigenständige Projekte. Die lib (komplett eigenständige Klasse) wird halt von beiden genutzt (wie gesagt, Utility-Klasse), damit die gleiche Vorgehensweise bei beiden sichergestellt ist.
 
Zuletzt bearbeitet:
Sorry für Doppelpost, aber dank dem Hinweis von "irgendjemand" konnte ich das Problem lösen.

Vor lauter selber machen, hab ich ganz übersehen, dass es dafür bereits fertige Lösungen gibt.

In meinem Fall wären das, wie von irgendjemand schon angesprochen, der ObjectOutput/InputStream und der DataOutput/InputStream. Damit klappt die Übertragung auch einwandfrei.

Nochmals danke an alle für die Antworten 🙂
 

Zurück
Oben