ObjectInputStream无法识别我的对象数据格式

时间:2016-03-21 06:27:05

标签: java sockets tcp objectinputstream

我从以下代码中获取EOFException

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 ");
}

我正在进行Socket编程,其中服务器以某种间隔向客户端发送连续数据。通过套接字从服务器传递到客户端的数据是我开发的CANDataInfo对象类型。在客户端,当我打印数据时,我得到例外。由于对象的读取始终为-1,因此我无法在某个文件上记录数据。

服务器端代码:

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);
    }
}

客户端代码 {不是一个干净的解决方案,请参阅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;
    }
}

异常堆栈:{解析之前}

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

2 个答案:

答案 0 :(得分:2)

在客户端

if (!(in.read() == -1))
{
    CANDataInfo canData = (CANDataInfo) in.readObject();
    System.out.println(canData.toString());
    bw.write(canData.toString());
}

第一行从输入流中读取一个字节。这实际上是服务器写入的对象的第一个字节。因此,流不再正确对齐,因此以下readObject()失败。

答案 1 :(得分:1)

您应该删除无意义和错误的read()调用,这会使您的对象流不同步。

在您访问它时,您还可以删除对isConnected()的所有冗余呼叫。他们什么都没做。你似乎有一种狂热来调用额外的方法,这些方法大多不做任何事情,或者试图预测未来。试着逐渐减少。

编辑根据要求,我不仅要批评您的客户,还要批评您的服务器代码。

服务器:

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

应该在构造函数中创建和配置ServerSocket

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

零是默认值。不要断言默认值。删除。

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

记录isConnected()是多余的。去掉。这将始终打印true。套接字连接。你刚刚接受了它。如果要记录有用的内容,请记录客户端套接字的远程地址。

        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)

不要抓住Exception。抓住IOException

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

您应该记录异常类,其消息和堆栈跟踪。 ""+ex没有实现这一点。

    }
}

客户端:

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())

客户端连接。您构建Socket时刚刚连接了它。如果通过一些奇迹它没有连接,调用getInputStream()已经失败了SocketException。删除此测试。一般来说,对代码中的错误或不可能错误的事情进行了太多测试。

                    {   
                        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");
                    }
                }

else块无法访问,日志消息'Client is trying to connect'不正确。删除整个块和else

                catch(Exception ex)

见上文。不要抓住Exception。捕获编译器告诉您捕获的异常:在本例中为IOException以及与DNS相关的异常。

                {   
                    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();
            }

您在这里(1)测试文件是否存在以及(2)创建新文件。

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

无论您在上面做了什么,操作系统都会创建一个新文件。因此exists()/createNewFile()部分完全浪费时间:两个系统调用完全没有任何结果。删除它们。

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

糟糕的做法。你应该让这个方法抛出IOException而不是在内部捕获它,或者返回null。目前,如果此方法失败,当您使用其返回值时,您将获得一个可引用的NullPointerException

    }
}