ObjectInput-, ObjectOutputStream und flush()

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • ObjectInput-, ObjectOutputStream und flush()

    Hallo,

    ich arbeite gerade an einem kleinen Servermodell. Dem liegt ein relativ einfaches Prinzip zu Grunde:
    Jeweils ein Server vertreten durch class Server extends BaseServer extends ServerSocket und Clients durch class Client extends BaseClient extends Socket.
    Beide Server und Client instanzieren eine Protokollklasse class BaseProtocol, welche Protokollthreads class BaseProtocolThread generieren kann.
    Diese Protokollthreads werden durch den Server generiert, wenn ein Client durch die accept()-Threadschleife verbunden wurde. Beim Client wird ein Protokollthread direkt nach dem Verbinden zum Server generiert.

    Ein Protokollthread kann nur mit einem Socket instanziert werden, da dieser auf den Output- und InputStream des Sockets zugreift.
    Der Thread handlet die Streams als ObjectInput- und ObjectOutputStream. Der Thread bestitz eine Schleife die auf 1 Byte wartet. Je nach Inhalt des Bytes wird eine interne Methode aufgerufen (0xC => readXYZRequest()), die dann von den Streams liest und wieder auf sie schreibt. Im Endeffekt ein Handler für Anfragen, die durch 1 Byte identifiziert werden. Zusätzlich bietet der Protokollthread die Möglichkeit eine Anfrage an die Gegenseite zu schicken (requestXYZ()).

    Im Idealfall sollte das so funktionieren (keine Subthreads):
    Clientseite:
    Serverseite

    1 schreibe meinAnfrageByte;
    2 schreibe meinStringXYZ;
    3 schreibe meinIntegerXYZ;
    4 schreibe meinObjectXYZ;
    5 flush;
    1 lese meinAnfrageByte;
    2 aufrufen readAnfrageRequest:
    3 lese meinStringXYZ;
    4 lese meinIntegerXYZ;
    5 lese meinObjectXYZ;
    6 verarbeiteDaten;
    7 schreibe meineAntwort;
    8 flush;
    6 lese meineAntwort;


    Leider funktioniert das nicht, denn ich bekomme eine StreamCorruptedException mit der Nachricht "invalid type code: 00" auf der Clientseite.
    Die Serverseite bekommt einfach nur eine EOFException spendiert, weil die Clientklasse den Socket schließt sobald ein unerwarteter Fehler auftritt.

    Ich bin mir nicht sicher, aber ich glaube das Protokoll des ObjectOutputStream funktioniert in etwa so (korrigiert mich wenn ich falsch liege):
    unsigned byte TypDerGesendetenDaten, unsigned scalar LängeDerDaten, byte[] SerialisierteDaten

    Aufgrund dieser Protokollstruktur, schließ ich einfach mal darauf, dass sich ein Nicht-Object-Packet eingeschlichen hat, obwohl ich ein Object lesen möchte. Bisher trat das Problem nämlich nur beim lesen der Antwort auf, die ein Object in meinem Fall ist. Meine Theorie ist, dass flush() etwas auf den Stream schreibt, dass readObject() aus dem ObjectInputStream davon abhält das Object korrekt zu lesen.

    Jedenfalls benötige ich das flush(), da ohne keine Daten ankommen. Der Sendepuffer ist anscheinend noch größer als geschriebene Daten.
    Vermutlich würde es ohne das flush() funktionieren. Leider konnte mir Google bis jetzt noch nicht so viel helfen, da es verschiedene "invalid type codes" gibt.

    Es ist etwas schwierig Codebeispiele zu posten, da das Servermodell in ein großes Projekt eingebunden ist. Ich hoffe Folgendes reicht um mein Problem zu verstehen:

    Schleife zum Lesen der Anfragen:

    Quellcode

    1. public void run(){
    2. System.out.println(getLogIdent() + " started");
    3. while(client.connected()){
    4. try {
    5. readLoop = true;
    6. byte preByte = input.readByte();
    7. switch(preByte){
    8. case PreBytes.Call:
    9. readCallRequest();
    10. break;
    11. case PreBytes.Auth:
    12. readAuthRequest();
    13. break;
    14. case PreBytes.Error:
    15. readErrorMessage();
    16. break;
    17. }
    18. }catch(IOException e){ // Hier wird die StreamCorruptedException gefangen, somit außerhalb des try-Blocks in der Funktion.
    19. System.out.println(getLogIdent() + " Exception caught: " + e.getClass().getName());
    20. if(e instanceof EOFException){
    21. client.disconnect();
    22. break;
    23. }else if(e instanceof SocketException){
    24. client.disconnect();
    25. }else{
    26. e.printStackTrace();
    27. }
    28. }
    29. }
    30. readLoop = false;
    31. System.out.println(getLogIdent() + " stopped");
    32. }
    Alles anzeigen


    readCallRequest():

    Quellcode

    1. private void readCallRequest() throws IOException {
    2. System.out.println(getLogIdent() + " Reading Call Request:");
    3. System.out.println(getLogIdent() + " Procedure Name");
    4. String procedureName = input.readUTF();
    5. System.out.println(getLogIdent() + " = " + procedureName);
    6. System.out.println(getLogIdent() + " Argument Length");
    7. int countArgs = input.readInt();
    8. System.out.println(getLogIdent() + " = " + countArgs);
    9. Object[] args = new Object[countArgs];
    10. try {
    11. for(int i = 0; i < args.length; i++){
    12. System.out.println(getLogIdent() + " Argument " + i);
    13. args[i] = input.readObject();
    14. System.out.println(getLogIdent() + " = " + args[i]);
    15. }
    16. System.out.println(getLogIdent() + " Running existence check");
    17. if(parent.containsKey(procedureName)){
    18. System.out.println(getLogIdent() + " Calling procedure");
    19. Object returnObject = parent.get(procedureName).call(this, args);
    20. System.out.println(getLogIdent() + " Writing Call Response");
    21. output.writeObject(returnObject);
    22. System.out.println(getLogIdent() + " Flushing");
    23. output.flush();
    24. }else{
    25. error(new ProcedureNotFound(procedureName));
    26. }
    27. }catch(ClassNotFoundException e){
    28. System.out.println(getLogIdent() + " Call Request failed due to type-missmatch");
    29. }catch(Exception e){
    30. System.out.println(getLogIdent() + " Exception caught: " + e.getClass().getName());
    31. }
    32. }
    Alles anzeigen


    Methode zum Senden einer call-Anfrage:

    Quellcode

    1. public Object call(String procedure, Object[] args){
    2. waitTillStarted();
    3. System.out.println(getLogIdent() + " calling Procedure: " + procedure);
    4. Object returnedObject = null;
    5. try {
    6. System.out.println(getLogIdent() + " Sending Call Request:");
    7. System.out.println(getLogIdent() + " PreByte " + PreBytes.Call);
    8. output.writeByte(PreBytes.Call);
    9. System.out.println(getLogIdent() + " Procedure Name " + procedure);
    10. output.writeUTF(procedure);
    11. System.out.println(getLogIdent() + " Argument Length " + args.length);
    12. output.writeInt(args.length);
    13. for(int i = 0; i < args.length; i++){
    14. System.out.println(getLogIdent() + " Argument " + i + " = " + args[i]);
    15. output.writeObject(args[i]);
    16. }
    17. System.out.println(getLogIdent() + " Flushing");
    18. output.flush();
    19. System.out.println(getLogIdent() + " Waiting for Call Response");
    20. returnedObject = input.readObject();
    21. }catch(IOException e){
    22. System.out.println(getLogIdent() + " Exception caught: " + e.getClass().getName());
    23. if(e instanceof EOFException){
    24. client.disconnect();
    25. }else if(e instanceof SocketException){
    26. client.disconnect();
    27. }else{
    28. e.printStackTrace();
    29. }
    30. }catch(ClassNotFoundException e){
    31. System.out.println(getLogIdent() + " receiving Call Response failed due to type missmatch");
    32. }
    33. System.out.println(getLogIdent() + " Returning Call Response");
    34. return returnedObject;
    35. }
    Alles anzeigen


    Wichig ist, dass wenn ich in Eclipse mir einen Breakpoint in die call()-Methode setze und dann schrittweise durchgehe entsteht kein Fehler.

    Könnt ihr mir Helfen, dass die Objects korrekt übertragen werden?
    Danke im Vorraus.
    IMP, out.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von TheIMP ()