ObjectInputStream: Unregelmäßige EOF Exceptions.

mccae

Senfdazugeber
Hallo!

Leider erhalte ich zufällig EOF Exceptions, wenn ich aus einem ObjectInputStream lese.

Der Stacktrace lautet:

Code:
Exception in thread "main" java.io.EOFException
    at java.io.ObjectInputStream$BlockDataInputStream.peekByte(Unknown Source)
    at java.io.ObjectInputStream.skipCustomData(Unknown Source)
    at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
    at java.io.ObjectInputStream.readClassDesc(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at ****.net.debug.DummyClient.main(DummyClient.java:70)


Ich verfahre wie folgt:

Ich verbinde mich mit dem Server auf localhost.
Danach werden die Streams erstellt.

Java:
Socket s = new Socket(InetAddress.getLocalHost(),5667);
       
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(s.getInputStream()));


Bei meinem Beispiel wird auf beiden Seiten jeweils ein Mal gelesen, und ein Mal geschrieben.

Java:
oos.writeObject(someObject);
oos.flush();

ois.readObject();

Danach wird der Socket ordungsgemäß geschlossen.

Mein Problem ist jetzt, dass ab und zu (nach 2-5 Mal aufrufen des Client codes) EOF Exceptions auftreten (beim Client).


Auf der Serverseite ist tritt dann folgender Fehler auf:

Code:
[04/04/2010|00:08:17] An IOException occured while writing to a client:
java.net.SocketException: Socket closed
    at java.net.SocketOutputStream.socketWrite(Unknown Source)
    at java.net.SocketOutputStream.write(Unknown Source)
    at java.io.ObjectOutputStream$BlockDataOutputStream.drain(Unknown Source)
    at java.io.ObjectOutputStream$BlockDataOutputStream.setBlockDataMode(Unknown Source)
    at java.io.ObjectOutputStream.writeNonProxyDesc(Unknown Source)
    at java.io.ObjectOutputStream.writeClassDesc(Unknown Source)
    at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.writeFatalException(Unknown Source)
    at java.io.ObjectOutputStream.writeObject(Unknown Source)
    at ***.net.daemon.ClientOutputThread.run(ClientOutputThread.java:54)
    at java.lang.Thread.run(Unknown Source)

Warum da "Socket closed" steht, kann ich mir nicht erklären.


Denn Verbindungsfehler sind ausgeschlossen, da alles über localhost läuft.

Warum diese Fehler auch nur ab und zu auftreten, ist mir ein Rätsel.
Beim Debuggen tritt das Problem komischerweise nie auf...

Kann mir jemand helfen?


mfg,
Martin
 
Zuletzt bearbeitet:
Ich weiß ja nicht wie dein Code zum lesen aussieht, aber wenn du liest bevor geschrieben wurde, ist im Stream noch nicht's drin und du bekommst die Exception. Entsprechend mußt vor dem lesen erst prüfen und warten bis etwas im Stream steht, bevor du liest.
 
Ich weiß ja nicht wie dein Code zum lesen aussieht, aber wenn du liest bevor geschrieben wurde, ist im Stream noch nicht's drin und du bekommst die Exception. Entsprechend mußt vor dem lesen erst prüfen und warten bis etwas im Stream steht, bevor du liest.

Hallo!

Wie meinst du das?

readObject() blockiert doch so lange bis daten verfügbar sind - es wird ein Object zurückgegeben.

Weiters blockiert bei mir die Erstellung des ObjectInputStreams beim Server so lange bis auf der anderen Seite ein ObjectOutputStream erstellt wurde.
Danach wird die blockierende Methode readObject() aufgerufen.

Das ganze läuft nach dem Muster:

Client öffnet Streams --> Client sendet Objekt --> Beim Server gibt die Methode readObject() ein Objekt zurück --> Auswertung des Objekts beim Server --> Senden der Antwort --> Die readObject() Methode liefert das Antwort Objekt bzw. null.

Nach diesem Schema funktioniert das ganze auch, jedoch kommt es ab und zu zu dem oben genannten Problem.
Total mysteriös das Ganze.

edit:

Hier ist der Code für die Serverlogik. Dieser muss ein Socket Objekt übergeben werden welches üblicherweise von ServerSocket.accept() zurückgegeben wird. (dabei wurde die Verarbeitungslogik für eingehende Objekte ausgelassen):

Java:
package ****.twcc2.net.daemon;

import java.io.BufferedInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
import java.net.SocketTimeoutException;

public class ClientHandler implements Runnable{

    private Socket clientSocket_;
    private int numClient_;
  
    private ClientOutputThread cot_;
    private Thread cotthread_;
  
    /**
     * Constructs a new ClientHandler with the given Socket and clientID.<br>
     * The {@link ClientOutputThread} class is beeing used for output
     * management.
     *
     * @param clientSocket The connection of the client represented by a
     *            {@link Socket}.
     * @param numClient The ID of the client used for thread naming.
     * @throws IOException If there was an error while contructing the
     *             {@link ClientOutputThread}.
     */
    public ClientHandler(Socket clientSocket, int numClient) throws IOException{
  
        clientSocket_ = clientSocket;
        numClient_ = numClient;

        cot_ = new ClientOutputThread(clientSocket);

        cotthread_ = new Thread(cot_);
        cotthread_.setName("ClientOutputThread-" + numClient_);
        cotthread_.start();
    }
  
    @Override
    public void run(){
  
        try{
      
            ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(clientSocket_.getInputStream()));
          
            while(true){
              
                Object newObject = null;

                try{
                    newObject = ois.readObject();
                }

                catch(EOFException e){
                    // Client closed connection?! End of Stream!?
                    break;
                }

                catch(ClassNotFoundException e){
                    // invalid class => invalid protocol => instant
                    // disconnection
                    break;
                }

                catch(SocketTimeoutException e){
                    break;
                }

                catch(IOException e){
                    break;
                }
              
                if(newObject != null){
                    // Handle object
                  
                    // Write answer
                  
                    byte[] array = {100,0,100,0,100}; // Generate some kind of object for demonstration purposes.
                    cot_.write(answer);
                }
                else{
                    break;
                }
            }
      
        }
        catch(Exception exception){
            // ToDo: Handle this.
        }
        finally{
            // Remove user from SessionManager

            // SessionManager.stopSession(currentUser_);

            cot_.stop();
            cotthread_.interrupt();

            // close connection
            try{
                clientSocket_.close();
                // Console.pushLine(
                //        "Client: " +
                //        clientSocket_.getInetAddress().getHostAddress()
                //        + ":" + clientSocket_.getPort() +
                //        " disconnected.");

                // Logger.logActivity(
                //        Time.getString() +
                //        "Client: " +
                //        clientSocket_.getInetAddress().getHostAddress()
                //        + ":" + clientSocket_.getPort() +
                //        " disconnected.");
            }

            catch(EOFException e){
                // ok
            }

            catch(IOException e){
                // Logger.logError(Time.getString() + "An IOException occured while waiting for client input data:" +
                //        System.getProperty("line.separator") +
                //        Utils.getExceptionStackTrace(e));
            }

            catch(Exception e){
                // Logger.logError(Time.getString() + "An Exception occured while waiting for client input data:" +
                //        System.getProperty("line.separator") +
                //        Utils.getExceptionStackTrace(e));
            }
        }
    }
}


Der Outputthread:

Java:
package ***.twcc2.net.daemon;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * This class is the outputmanager for a client.<br>
 * It manages an output queue which sends, once data is available, the objects one by one.
 *
 * @author mccae
 * @since 2.0
 */
public class ClientOutputThread implements Runnable{

    private ObjectOutputStream oos_;

    private Socket clientSocket_;

    private LinkedBlockingQueue<Object> queue_;
  
    private boolean stop = false;

    /**
     * Constructs a new outputmanager with the given client represented by a {@link Socket}.
     *
     * @param clientSocket The connection to the user represented by a Socket.
     * @throws IOException If there was an error while obtaining the outputstream.
     */
    public ClientOutputThread(Socket clientSocket) throws IOException{
        this.oos_ = new ObjectOutputStream(clientSocket.getOutputStream());
        this.clientSocket_ = clientSocket;

        queue_ = new LinkedBlockingQueue<Object>();
    }

    @Override
    public void run(){
        while(true){

            try{
                // Block and wait for input
                Object o = queue_.take();
              
                if(stop){
                    break;
                }
              
                oos_.writeObject(o);
                oos_.flush();
            }
            catch(IOException e){
                // Logger.logError(Time.getString()+"An IOException occured while writing to a client:"+
                //        System.getProperty("line.separator")+
                //        Utils.getExceptionStackTrace(e));

                try{
                    clientSocket_.close();
                }
                catch(IOException e1){
                }

                break;
            }
            catch(InterruptedException e){// If in a take() operation while beeing stopped.
                try{
                    clientSocket_.close();
                }
                catch(IOException e1){
                }

                break;
            }
        }
    }
  
    /**
     * Adds the given object to the queue and sends it later.<br>
     * The queue uses the First in First Out (FIFO) principle.<br>
     * The object may be sent immeadiately, but there is no guarantee for that, if there are more objects in the queue.
     *
     * @param object The object to write to the client.
     */
    public void write(Object object){
        try{
            queue_.put(object);
        }
        catch(InterruptedException e){
            //Logger.logError(Time.getString()+"An InterruptedException occured while adding an object to the output queue:"+
            //        System.getProperty("line.separator")+
            //        Utils.getExceptionStackTrace(e));
        }
    }
  
    /**
     * Stops the outputmanager.<p>
     * <i>Please note: The Thread executing the run method must be interrupted additionnally after calling this method!</i>
     */
    public void stop(){
        stop = true;
    }

}

Der Client selbst funktionert wie im ersten Post beschrieben, prozedual. (Zu Testzwecken).
Es wird abwechselnd geschrieben und gelesen. (Frage --> Antwort ; Noch eine Frage --> Noch eine Antwort; ....)

mfg,
Martin
 
Zuletzt bearbeitet:
OHNE jetzt mal die codes gelesen zu haben hört sich das für mich nach schlichten TIMEOUT's an ...
dürften in der regel grade auf LOCALHOST nicht passieren ...
aber die StackTraces lassen deutlich erkennen das es ein fehler auf der client-seite sein müsste da dieser ja ein EOF wirft ... den socket samt streams daraufhin killt und der server nun seine daten ins nirvana schicken würde was laut RFC von TCP/IP nicht passieren darf ... daraufhin quittiert auch der server seinen dienst und schiest die verbindung ab ...

ich würde also wie vorgeschlagen nicht dierekt die Object-streams nutzen sondern normale und dann auf beiden seiten jeweils mit ByteArray-streams arbeiten ...
das eigene blockieren von streams lässt sich mit nem while-loop ... 2 int-variablen und der methode InputStream.available() leicht zusammen basteln ...
dessweiteren solltest du auch *sofern nicht explizit gewünscht* auch auf der client-seite threads für input und output verwenden *vor allem wenn du vorhast später ne gui drüber zu legen ... weil wenn dann eine der socket-funktionen blockiert wird auch die gesamte gui eingefrohren und du hast das gefühl das die komplette app gecrashed ist nur weil auf daten gewartet wird bzw welche gesendet werden*
 
Hallo!

Ich habe soeben das Problem gefunden.

Die Ursache ist trivial, jedoch nicht auf den ersten, zweiten oder gar zehnten Blick zu erkennen:

Manchmal kommt es vor, dass der Server die Verbindung trennt, bevor der Outputthread fertig ist.
Deshalb kann es ab und zu vorkommen, dass eben dieser die Antwort nicht senden kann.

Beim Debuggen tritt der Fehler logischerweise nicht auf.

Ich habe jetzt einfach sichergestellt, dass auf das Beenden des OutputThreads gewartet wird, bevor die Verbindung getrennt wird.


Vielen Dank für die Bemühungen der Vorposter den Ursprung des Problems zu finden.

Mfg,
Martin
 
Zuletzt bearbeitet:
Hi,

ist zwar schon langer her, aber ich hab momentan das gleiche Problem. Wie kann ich sicherstellen, dass die Streams blockiert werden, solange noch nix drin steht?

Viele Grüße
Sascha
 

Neue Beiträge

Zurück