1

I have a problem using an ObjectInputStream and I have been struggling with it for 2 days now. I tried to search for a solution but unfortunately found no fitting answer.

I am trying to write a client/server application in which the client sends objects (in this case a configuration class) to the server. The idea is that connection keeps alive after sending the object so it is possible to send a new object if necessary.

Here are the important parts of my client code:

mSocket = new Socket("192.168.43.56", 1234);

mObjectIn = new ObjectInputStream(mSocket.getInputStream());
mObjectOut = new ObjectOutputStream(mSocket.getOutputStream());

mObjectOut.writeObject(stubConfig);
mObjectOut.flush();

In the above code, I left out some try/catch blocks to keep the code readable for you.

The server side looks as follows:

mHostServer = new ServerSocket(port);
mSocket = mHostServer.accept();

// create streams in reverse oreder
mObjectOut = new ObjectOutputStream(mConnection.getOutputStream());
mObjectOut.flush();
mObjectIn = new ObjectInputStream(mConnection.getInputStream());

while (mIsSocketConnected)
{
    StubConfig = (StubConfiguration)mObjectIn.readObject(); 
}

What I want to achieve is that as long at the socketconnection is alive, the server is listening for incoming config objects.

When I run my program however, I got an EOFException in the while loop at server side. I receive the first config object without any problems in the first iteration of the while loop but after that I get an EOFException every time readObject() is called.

I am looking for a way to solve this. Can anyone put me in the good direction?

EDIT: What I read about the EOFException is that it is thrown when you want to read from a stream when the end of it is reached. That means that for some reason the stream ended after the object has been send. Is there a way to reinitialize the streams or so??

Marvin Lasut
  • 21
  • 2
  • 6
  • You have an EOF at the second iteration because the client writes once (without while) while the server reads in a loop. So replace while by if to read once –  May 01 '15 at 17:40

4 Answers4

1

try using this

Server side
1.Server running on a separate thread

public class ServeurPresence implements Runnable {

public final static int PORT = 20000 ;
public final static String HOSTNAME = "localhost" ;
public static enum Action {CONNEXION, MSG, DECONNEXION,USER, FINCLASSEMENT};

ServerSocket serveur ;
static List<String> names ;

 */
public ServeurPresence() 
{

    System.out.println("Start Server...");
    try 
    {
        serveur = new ServerSocket(PORT) ;
        new Thread(this).start();
        //javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() {   createAndShowGUI();}    }   );
    } 
    catch (IOException e)
    {
        e.printStackTrace();
    }
}
/**
 * @param args
 */
public static void main(String[] args)
{
    new ServeurPresence();

}
@Override
public void run() 
{
    System.out.println("server runs");

        while(true)
        {
            try {

                Socket sock = serveur.accept();
                ServiceClientsThread thread= new ServiceClientsThread(sock);
                thread.start();

            }
            catch (IOException e) 
            {
                System.out.println("Error with  socket");
                e.printStackTrace();        
            }
        }

}

}


2. A Thread to handle each Client:ServiceClientThread

    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.net.Socket;
    import java.util.ArrayList;
    import java.util.List;


 public class ServiceClientsThread extends Thread{
    private Socket sock ;
ServiceClientsThread(Socket sock)
{
        //super();
        this.sock=sock;
}

@Override
public void run() 
{
    DataInputStream is ;
    DataOutputStream os ;
    String name =null ;

    try {

        is = new DataInputStream(sock.getInputStream()) ;
        os = new DataOutputStream(sock.getOutputStream()) ;
        ServeurPresence.Action act ;

        do {
            // read Action              
            act = ServeurPresence.Action.valueOf(is.readUTF()) ; // read string -> enum
            System.out.println("action :"+act);
            switch (act) {

            case CONNEXION :
                name = is.readUTF(); //read client name
                System.out.println("Name :"+name);
                os.writeUTF("Hi");//send welcome msg
                break ;
            case MSG :
                String msg = is.readUTF();
                 os.writeUTF("OK");//response
                break ;
            case DECONNEXION :
                System.out.println(name+" is logged out");
                break ;
            }

        } while (act!=ServeurPresence.Action.DECONNEXION) ;

        // the end
        is.close();
        os.close();
        sock.close();

    } catch (IOException e) 
    {
        System.out.println("Error with "+name+" socket");
        e.printStackTrace();        
    }
}

}


3. Client side

    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.net.InetAddress;
    import java.net.Socket;
    import java.net.UnknownHostException;


public class Client {
/**
 * 
 */
Client(String name)
{
    System.out.println("Start Client...");

    try {

        Socket sock = new Socket(ServeurPresence.HOSTNAME,ServeurPresence.PORT) ;
        DataOutputStream os = new DataOutputStream(sock.getOutputStream()) ;
        DataInputStream is = new DataInputStream(sock.getInputStream()) ;

                    System.out.println("Send "+name+" to server");

        // CONNECTION : Action then value
        os.writeUTF(ServeurPresence.Action.CONNEXION.name()) ; // send action : write enum -> String
        os.writeUTF(name) ; // send the name

                    //read server welcome msg
        String msg = is.readUTF();
                    System.out.println("Welcome msg: "+msg);

        /*  Your actions here : see example below */
        try 
        {
            Thread.currentThread().sleep(4000);
            os.writeUTF(ServeurPresence.Action.MSG.name()) ; // send action : write enum -> String
            os.writeUTF("My message here") ; // send msg
            Thread.currentThread().sleep(4000);
            msg = is.readUTF();//server response message
        } 
        catch (InterruptedException e) 
        {
            e.printStackTrace();
        }
        /************************************************/

        //CLOSE
        os.writeUTF(ServeurPresence.Action.DECONNEXION.name()) ; // send action
        System.out.println("Log out");
        os.close();
        sock.close();

    }
    catch (UnknownHostException e) 
    {
        System.out.println(ServeurPresence.HOSTNAME+ " unknown");
        e.printStackTrace();
    } 
    catch (IOException e)
    {
        System.out.println("Impossible to connect to "+ServeurPresence.HOSTNAME+ ":"+ServeurPresence.PORT);
        e.printStackTrace();
    } 
}

}


4. In your case use readObject()/writeObject() instead of readUTF()/writeUTF() to write your config objects

  • Try it why? How does this answer the question? – user207421 Apr 30 '15 at 12:07
  • Hi DAO, thanks for your reaction. Unfortunately, it hasn't helped. Can you explain to me what you think is the problem here and why your solution could help to fix it? – Marvin Lasut Apr 30 '15 at 12:24
  • @MarvinLasut If it hasn't helped why have you marked this answer as correct? – user207421 Apr 30 '15 at 19:45
  • @DAO Changing to data input/output streams and adding more datatypes to transmit doesn't actually address the question, and isn't an improvement of any kind over the original code. It's just ten times more complex for the same result. It's not even good code. The sleeps are literally a waste of time, and `Thread.sleep()` is a static method, so calling `currentThread()` is also pointless. (4) cannot possibly apply if you remove the Object streams. – user207421 May 01 '15 at 04:12
  • I gave an example of how to synchronize reading and writing on both side because in his code, he is trying to read many objects while there is only one writen object (from client). That's why i suggested an enumeration of action in case the client sends another object later or wants to log out. –  May 01 '15 at 17:45
  • All he needs is `readObject() and `writeObject().` None of this. The major issue appears to be that he just isn't writing a second object. – user207421 May 01 '15 at 19:44
1

EOFException is thrown by readObject() when the peer has closed the connection. There can never be more data afterwards. Ergo you can't have written multiple objects at all: you closed the connection instead.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • That sounds indeed like the problem. I haven't said that I've send multiple objects, I only said that I am reading them in a while loop and that only the first iteration is succesfull. Is there a way to keep the connection open after sending the object. I didn't manually close it so I think it is done automatically – Marvin Lasut Apr 30 '15 at 12:30
  • It is not done automatically. You closed it. Closing either the input or output stream of a socket closes the other stream and the socket. – user207421 Apr 30 '15 at 18:42
0

Try this and let me know how it goes:

while (1==1)
{
    StubConfig = (StubConfiguration)mObjectIn.readObject();
    Thread.sleep(100); //Saves CPU usage
}
Vasco Lameiras
  • 344
  • 3
  • 15
0

Very late answer, but just for future reference. I have been having problems sending Objects via sockets because the method flush() is not working properly.

I solved this problem just by switching flush() to reset().

Jesus
  • 655
  • 1
  • 7
  • 21
  • The method `flush()` does indeed work properly, and if you solved your problem by calling `reset()` you had a different problem, not this one. – user207421 Jun 04 '17 at 12:47