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

ObjectInputStream is not able to recognize my Object Data format

我从以下代码中得到 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 ");
}

我正在做一个套接字编程,其中服务器在某个时间间隔向客户端发送连续数据。通过套接字从服务器传递到客户端的数据是我开发的 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[=13=](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

在客户端

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

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

您应该删除毫无意义且错误的 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);

您应该记录异常 class、它的消息和堆栈跟踪。 ""+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();

您不需要同时关闭输入流和套接字。两者都行。一般做法是关闭最外层的 writer/output 流(如果有的话),否则关闭输入流。

                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 而不是在内部捕获它,或者 return null。目前如果这个方法失败了,你去使用它的return值的时候会得到一个instrutableNullPointerException

    }
}