Search code examples
javasocketstcpobjectinputstream

ObjectInputStream is not able to recognize my Object Data format


I am getting EOFException from the following code:

if (!(in.read() == -1))
{
    CANDataInfo canData = (CANDataInfo) in.readObject();
    System.out.println(canData.toString());
    bw.write(canData.toString());
}
else
{
    System.out.println("in.read() == -1 "+in.readObject());
    jLab0x28.setText("No more bytes to read ");
}

I am doing an Socket programming where server is sending continuos data to client at some interval. The Data whichis passed from server to client in via socket is of type CANDataInfo object which i have developed. At client side while i am printing the data i am getting exception. Since object's read is always -1 i am not able to log the data on some file.

Server Side Code:

private ServerSocket server = null;
private Socket client = null;
private ObjectOutputStream out;
public static final String TAG = "APP1";

private void structureData(CANDataInfo canDataInfo)
{
    try 
    { 
        if(server == null) 
        {   
            server = new ServerSocket(38301);
            server.setSoTimeout(0);
        }
        client = server.accept();
        Log.e("Server ", ""+client.isConnected());
        Log.e("Data ", ""+canDataInfo.toString());

        if(!client.isConnected())
        {   
            Log.e("Server ", "client.isConnected() "+client.isConnected());
            server.close();
        }

        out = new ObjectOutputStream(client.getOutputStream());
        out.writeObject(canDataInfo);

        out.close();
    }
    catch (Exception ex)
    {
        Log.e(CANManagerSetUp.TAG, "" + ex);
    }
}

Client Side Code {Not a clean solution, Refer Answer from EJP}

   package com.cnh.socket.client;

import java.io.BufferedWriter;
import java.io.EOFException;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;

import javax.swing.JLabel;

import cantest.setup.CANDataInfo;


public class ThreadListener
{   
    Socket client = null;
    ObjectInputStream in = null;
    ListenFor0X28 runnableListenFor0X28 = null;
    boolean continueMe;


    public class ListenFor0X28 implements Runnable 
    {   
        JLabel jLab0x28; 

        public ListenFor0X28(){}

        public ListenFor0X28(boolean stop, JLabel jLab0x28) 
        {
            continueMe = stop;
            this.jLab0x28 = jLab0x28;
        }

        public void run() 
        {   

            while(continueMe)
            {
                try
                {
                    client = new Socket("localhost", 38301);
                    in = new ObjectInputStream(client.getInputStream());
                    if(client.isConnected())
                    {   
                        jLab0x28.setText("Connected to Server");
                        appendFile(continueMe, jLab0x28, client);

                    }
                    else
                    {   
                        System.out.println("Client is trying to connect");
                        jLab0x28.setText("Client is trying to connect");
                    }
                }
                catch(Exception ex)
                {   
                    ex.printStackTrace();
                    System.err.println("Before Append "+ex.toString());
                }
            }
        }
    }
    BufferedWriter file = getFile("C:\\ISSUE124_Resolved.txt");
    private void appendFile(boolean continueMe, JLabel jLab0x28, Socket client)
    {   
        try
        {   
            if(!client.isClosed())
            {   
                try
                {   
                    CANDataInfo canData = (CANDataInfo) in.readObject();
                    System.out.println(canData.toString());
                    file.write(canData.toString());
                    file.flush();

                }
                catch (EOFException exp)
                {   
                    continueMe = true;
                    System.out.println("A Stream has finished "+exp.toString()+"\n");
                }
                catch (ClassNotFoundException exp) 
                {
                    exp.printStackTrace();
                    System.err.println(exp.toString());
                    continueMe = false;
                }
            }

            if(!continueMe)
            {
                file.close();
                client.close();
                in.close();
                jLab0x28.setText("Socket is closed "+client.isClosed());
            }

        }
        catch(IOException exp)
        {
            exp.printStackTrace();
            System.err.println("Exception "+exp.toString());
            jLab0x28.setText(exp.getMessage());
            continueMe = false;
        }
    }

    public BufferedWriter getFile(String path) 
    {
        try 
        {
            File file = new File(path);
            if (!file.exists()) 
            {
                file.createNewFile();
            }
            FileWriter fw = new FileWriter(file.getAbsoluteFile());
            return new BufferedWriter(fw);
        }
        catch (IOException e) 
        {
            e.printStackTrace();
        }
        return null;
    }
}

Exception Stack: {Before Resolving}

java.io.EOFException
    at java.io.ObjectInputStream$BlockDataInputStream.peekByte(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at com.cnh.socket.client.ThreadListener.appendFile(ThreadListener.java:73)
    at com.cnh.socket.client.ThreadListener.access$0(ThreadListener.java:65)
    at com.cnh.socket.client.ThreadListener$ListenFor0X28.run(ThreadListener.java:48)
    at java.lang.Thread.run(Unknown Source)
Data received in unknown format java.io.EOFException

Solution

  • You should remove the pointless and erroneous read() call, which is getting your object streams out of sync.

    While you're at it, you can also remove all the redundant calls to isConnected(). They aren't doing anything. You seem to have a mania for calling extra methods which mostly don't do anything, or which try to predict the future. Try to taper off.

    EDIT As requested I am critiquing not only your client but your server code.

    Server:

    private void structureData(CANDataInfo canDataInfo)
    {
        try 
        { 
            if(server == null)
    

    The ServerSocket should have been created and configured in the constructor.

            {   
                server = new ServerSocket(38301);
                server.setSoTimeout(0);
    

    Zero is the default. Don't assert defaults. Remove.

            }
            client = server.accept();
            Log.e("Server ", ""+client.isConnected());
    

    Logging isConnected() is redundant. Remove. This will always print true. The socket is connected. You just accepted it. If you want to log something useful, log the client socket's remote address.

            Log.e("Data ", ""+canDataInfo.toString());
    

    How can there be any data when you haven't read any yet? If this is invariant server-side data, why log it on every accept?

            if(!client.isConnected())
            {   
                Log.e("Server ", "client.isConnected() "+client.isConnected());
                server.close();
            }
    

    This test can never pass, and the code block can never be entered, and if by some miracle it was entered, closing the server socket is a ridiculous response. Remove all this.

            out = new ObjectOutputStream(client.getOutputStream());
            out.writeObject(canDataInfo);
    
            out.close();
        }
        catch (Exception ex)
    

    Don't catch Exception. Catch IOException.

        {
            Log.e(CANManagerSetUp.TAG, "" + ex);
    

    You should log the exception class, its message, and the stack trace. ""+ex does not accomplish that.

        }
    }
    

    Client:

    public class ThreadListener
    {   
        Socket client = null;
        ObjectInputStream in = null;
        ListenFor0X28 runnableListenFor0X28 = null;
        boolean continueMe;
    
    
        public class ListenFor0X28 implements Runnable 
        {   
            JLabel jLab0x28; 
    
            public ListenFor0X28(){}
    
            public ListenFor0X28(boolean stop, JLabel jLab0x28) 
            {
                continueMe = stop;
                this.jLab0x28 = jLab0x28;
            }
    
            public void run() 
            {   
    
                while(continueMe)
                {
                    try
                    {
                        client = new Socket("localhost", 38301);
                        in = new ObjectInputStream(client.getInputStream());
                        if(client.isConnected())
    

    The client is connected. You just connected it, when you constructed the Socket. And if by some miracle it wasn't connected, calling getInputStream() would already have failed with a SocketException. Remove this test. In general there is far too much testing of things that can't be true or can't be false in your code.

                        {   
                            jLab0x28.setText("Connected to Server");
                            appendFile(continueMe, jLab0x28, client);
                        }
                        else
                        {   
                            System.out.println("Client is trying to connect");
                            jLab0x28.setText("Client is trying to connect");
                        }
                    }
    

    The else block is unreachable, and the log message 'Client is trying to connect' is incorrect. Remove the entire block and the else.

                    catch(Exception ex)
    

    See above. Don't catch Exception. Catch the exceptions the compiler tells you to catch: in this case IOException and the DNS-related ones.

                    {   
                        ex.printStackTrace();
                        System.err.println("Before Append "+ex.toString());
    

    See above about how to log exceptions.

                    }
                }
            }
        }
        BufferedWriter file = getFile("C:\\ISSUE124_Resolved.txt");
    
        private void appendFile(boolean continueMe, JLabel jLab0x28, Socket client)
        {   
            try
            {   
                if(!client.isClosed())
                {   
                    try
                    {   
                        CANDataInfo canData = (CANDataInfo) in.readObject();
                        System.out.println(canData.toString());
                        file.write(canData.toString());
                        file.flush();
                    }
                    catch (EOFException exp)
                    {   
                        continueMe = true;
                        System.out.println("A Stream has finished "+exp.toString()+"\n");
                    }
                    catch (ClassNotFoundException exp) 
                    {
                        exp.printStackTrace();
                        System.err.println(exp.toString());
                        continueMe = false;
                    }
                }
    
                if(!continueMe)
                {
                    file.close();
                    client.close();
                    in.close();
    

    You don't need to close both the input stream and the socket. Either will do. General practice is to close the outermost writer/output stream if there is one, otherwise the input stream.

                    jLab0x28.setText("Socket is closed "+client.isClosed());
                }
    
            }
            catch(IOException exp)
            {
                exp.printStackTrace();
                System.err.println("Exception "+exp.toString());
                jLab0x28.setText(exp.getMessage());
                continueMe = false;
            }
        }
    
        public BufferedWriter getFile(String path) 
        {
            try 
            {
                File file = new File(path);
                if (!file.exists()) 
                {
                    file.createNewFile();
                }
    

    Here you are (1) testing for file existence and (2) creating a new file.

                FileWriter fw = new FileWriter(file.getAbsoluteFile());
    

    Here the operating system will create a new file regardless of what you did above. The exists()/createNewFile() part is therefore a complete waste of time: two system calls that accomplish precisely nothing. Remove them.

                return new BufferedWriter(fw);
            }
            catch (IOException e) 
            {
                e.printStackTrace();
            }
            return null;
    

    Poor practice. You should let this method throw IOException and not catch it internally, or return null. At present, if this method fails, you will get an instrutable NullPointerException when you go to use its return value.

        }
    }