仅当由服务器发送到客户端时才能反序列化类,反之亦然

发布于 2025-01-12 03:20:50 字数 10464 浏览 4 评论 0原文

流过去可以工作,但两天前突然停止了,我无法修复它。

客户端创建并成功发送一个 User 对象和一个 Message 对象(由客户端序列化并由服务器反序列化)。当客户端收到两个类中的任何一个(由服务器序列化并由客户端反序列化)时,我会遇到异常,主要是:

java.io.UTFDataFormatException
    at java.base/java.io.ObjectInputStream$BlockDataInputStream.readUTFSpan(ObjectInputStream.java:3704)
    at java.base/java.io.ObjectInputStream$BlockDataInputStream.readUTFBody(ObjectInputStream.java:3658)
    at java.base/java.io.ObjectInputStream$BlockDataInputStream.readUTF(ObjectInputStream.java:3458)
    at java.base/java.io.ObjectInputStream.readUTF(ObjectInputStream.java:1239)
    at java.base/java.io.ObjectStreamClass.readNonProxy(ObjectStreamClass.java:804)
    at java.base/java.io.ObjectInputStream.readClassDescriptor(ObjectInputStream.java:988)
    at java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2032)
    at java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1907)
    at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2209)
    at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1742)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:514)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:472)
    at Model.MessageClient$1.run(MessageClient.java:69)
    at java.base/java.lang.Thread.run(Thread.java:833)

每隔一段时间,我会得到:

java.io.InvalidClassException: Model.Message; class invalid for deserialization
    at java.base/java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(ObjectStreamClass.java:174)
    at java.base/java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:921)
    at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2210)
    at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1742)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:514)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:472)

客户端 - 流

public MessageClient(String ip, int port, String usernameStr, ImageIcon icon, Controller controller) {
    this.user = new User(usernameStr, icon);
    this.controller = controller;
    this.port = port;
    this.ip = ip;
    this.messageBuffer = new Buffer<>();
    this.contacts = new ArrayList<>(); //(ArrayList<Model.User>) readObjectFromFile("files/contacts");
    setUpStreams();
    setUpThreads();
}

public void setUpStreams(){
    try {
        s = new Socket(ip, port);
        try {
            ois = new ObjectInputStream(s.getInputStream());
            oos = new ObjectOutputStream(s.getOutputStream());
            oos.writeObject(user);
            oos.flush();
            users = new ArrayList<>();
            setUpThreads();
        } catch (IOException e) {
            e.printStackTrace();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public void setUpThreads(){
    t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            while (!Thread.interrupted()) {
                try {
                    Object o = ois.readObject();
                    if (o.getClass().isAssignableFrom(Message.class)) {
                        receiveMessage((Message) o);
                    }
                    if (o.getClass().isAssignableFrom(ArrayList.class)) {
                        updateUsers((ArrayList<Model.User>) o);
                    }
                } catch(EOFException e){
                    System.out.println("stopped");
                    t2.stop();
                    t1.stop();
                } catch(IOException | ClassNotFoundException e){
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                    e.printStackTrace();
                }
            }
        }
    });
    t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            while (!Thread.interrupted()) {
                try {
                    Message currMessage = messageBuffer.get();
                    oos.writeObject(currMessage);
                    oos.flush();
                } catch(IOException | InterruptedException e){
                    e.printStackTrace();
                }

            }
        }
    });
    t1.start();
    t2.start();
}

服务器端流

@Override
public synchronized void run() {

    while (socket.isConnected() && !socket.isClosed()) {
            try {
                Object o = ois.readObject();
                ih.addToBuffer((Model.Message) o);
            } catch (EOFException e) {
                try {
                    socket.close();
                    t2.stop();
                    t1.stop();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            } catch (IOException | ClassNotFoundException e) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }

    }
    chm.put(user, null);
    clients.remove(this);
    sendAll(new Message(user.getUsername() + " has disconnected", null));

}

private class InputHandler implements Runnable{
    private Buffer<Model.Message> inputBuffer;

    public InputHandler(){
        inputBuffer = new Buffer<>();
    }

    public void addToBuffer(Message msg){
        inputBuffer.put(msg);
    }

    @Override
    public synchronized void run() {
        Object o = null;
        while (!Thread.interrupted()) {
            Message temp = null;
            Message sendable = null;
            try {
                temp = inputBuffer.get();
                sendable = new Message(temp.getText(), temp.getIcon(), temp.getRecipients(), temp.getSender());
                sendable.setCurrID();
                sendable.setUploaded(new Timestamp(System.currentTimeMillis()));
                sendSelect(sendable ,sendable.getSender());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}
public void sendSelect(Message msg, User selectedUser){
        Client currClient;
        if(!chm.containsKey(selectedUser)) {
            try {
                oos.writeObject(new Message(selectedUser.getUsername() + "not found", null));
                oos.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else if ((currClient = chm.get(selectedUser)) != null) {
            try {
                currClient.oos.writeObject((Model.Message) msg);
                currClient.oos.flush();
                msg.setDownloaded(new Timestamp(System.currentTimeMillis()));
                callback.downloadTimestamp(msg);
            } catch (IOException e) {
                e.printStackTrace();
            }

        } else {
            addUnsent(selectedUser, msg);
        }
}

我序列化的类复制并粘贴。

类路径是相同的,所有字段都是可序列化的并且具有无参数构造函数。我还确保两个编码都设置为 UTF-8

Message

package Model;

import javax.swing.*;
import java.io.*;
import java.sql.Timestamp;
import java.util.LinkedList;

public class Message implements Serializable{
    @Serial
    private static final long serialVersionUID = -3930131856060689940L;

    private static int nextID = 0;
    private int currID;

    private final String text;
    private final ImageIcon icon;

    private Timestamp uploaded;
    private Timestamp downloaded;

    private final User sender;
    private final LinkedList<User> recipients;

    public Message(){
        currID = nextID;
        nextID++;
        this.text = null;
        this.icon = null;
        sender = null;
        recipients = null;
    }
    public Message(String text, User sender){
        currID = nextID;
        nextID++;
        this.text = text;
        this.icon = null;
        this.sender = sender;
        this.recipients = null;

    }
    public Message(String text, ImageIcon icon, User sender) {
        currID = nextID;
        nextID++;
        this.text = text;
        this.icon = icon;
        this.sender = sender;
        this.recipients = null;

    }
    public Message(String text, ImageIcon icon, LinkedList<User> recipients, User sender) {
        currID = nextID;
        nextID++;
        this.text = text;
        this.icon = icon;
        this.sender = sender;
        this.recipients = recipients;

    }

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof Message){
            if( ((Message) obj).getCurrID() == this.currID ){
                return true;
            }
        }
        return false;
    }
    public String getText() {
        return text;
    }
    public ImageIcon getIcon() {
        return icon;
    }
    public Timestamp getUploaded() {
        return uploaded;
    }
    public Timestamp getDownloaded() {
        return downloaded;
    }
    public Model.User getSender(){return sender;}
    public int getCurrID(){return currID;}
    public void setCurrID(){currID = nextID; nextID++;}
    public LinkedList<User> getRecipients(){
        return recipients;
    }
    public void setUploaded(Timestamp uploaded) {
        this.uploaded = uploaded;
    }
    public void setDownloaded(Timestamp downloaded) {
        this.downloaded = downloaded;
    }
}

User

package Model;

import javax.swing.*;
import java.io.Serial;
import java.io.Serializable;

public class User implements Serializable{
    @Serial
    private static final long serialVersionUID = -5886308724572898536L;

    private String username;
    private ImageIcon image;

    public User(String username, ImageIcon image){
        this.username = username;
        this.image = image;
    }

    public int hashCode() {
        return username.hashCode();
    }

    public boolean equals(Object obj) {
        if(obj!=null && obj instanceof User)
            return username.equals(((User)obj).getUsername());
        return false;
    }

    public String getUsername() {
        return username;
    }

    @Override
    public String toString(){
        return username;
    }
}

The streams used to work, but suddenly just stopped two days ago, and I can't get it fixed.

The client creates and successfully sends a User object and a Message object (serialize by the client and deserialize by the server). When the clients receives any of the two classes (serialized by the server and deserialized by the client), I get exceptions, mainly:

java.io.UTFDataFormatException
    at java.base/java.io.ObjectInputStream$BlockDataInputStream.readUTFSpan(ObjectInputStream.java:3704)
    at java.base/java.io.ObjectInputStream$BlockDataInputStream.readUTFBody(ObjectInputStream.java:3658)
    at java.base/java.io.ObjectInputStream$BlockDataInputStream.readUTF(ObjectInputStream.java:3458)
    at java.base/java.io.ObjectInputStream.readUTF(ObjectInputStream.java:1239)
    at java.base/java.io.ObjectStreamClass.readNonProxy(ObjectStreamClass.java:804)
    at java.base/java.io.ObjectInputStream.readClassDescriptor(ObjectInputStream.java:988)
    at java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2032)
    at java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1907)
    at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2209)
    at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1742)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:514)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:472)
    at Model.MessageClient$1.run(MessageClient.java:69)
    at java.base/java.lang.Thread.run(Thread.java:833)

Every so often, I get:

java.io.InvalidClassException: Model.Message; class invalid for deserialization
    at java.base/java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(ObjectStreamClass.java:174)
    at java.base/java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:921)
    at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2210)
    at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1742)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:514)
    at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:472)

Client side - streams

public MessageClient(String ip, int port, String usernameStr, ImageIcon icon, Controller controller) {
    this.user = new User(usernameStr, icon);
    this.controller = controller;
    this.port = port;
    this.ip = ip;
    this.messageBuffer = new Buffer<>();
    this.contacts = new ArrayList<>(); //(ArrayList<Model.User>) readObjectFromFile("files/contacts");
    setUpStreams();
    setUpThreads();
}

public void setUpStreams(){
    try {
        s = new Socket(ip, port);
        try {
            ois = new ObjectInputStream(s.getInputStream());
            oos = new ObjectOutputStream(s.getOutputStream());
            oos.writeObject(user);
            oos.flush();
            users = new ArrayList<>();
            setUpThreads();
        } catch (IOException e) {
            e.printStackTrace();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public void setUpThreads(){
    t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            while (!Thread.interrupted()) {
                try {
                    Object o = ois.readObject();
                    if (o.getClass().isAssignableFrom(Message.class)) {
                        receiveMessage((Message) o);
                    }
                    if (o.getClass().isAssignableFrom(ArrayList.class)) {
                        updateUsers((ArrayList<Model.User>) o);
                    }
                } catch(EOFException e){
                    System.out.println("stopped");
                    t2.stop();
                    t1.stop();
                } catch(IOException | ClassNotFoundException e){
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                    e.printStackTrace();
                }
            }
        }
    });
    t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            while (!Thread.interrupted()) {
                try {
                    Message currMessage = messageBuffer.get();
                    oos.writeObject(currMessage);
                    oos.flush();
                } catch(IOException | InterruptedException e){
                    e.printStackTrace();
                }

            }
        }
    });
    t1.start();
    t2.start();
}

Server-side streams

@Override
public synchronized void run() {

    while (socket.isConnected() && !socket.isClosed()) {
            try {
                Object o = ois.readObject();
                ih.addToBuffer((Model.Message) o);
            } catch (EOFException e) {
                try {
                    socket.close();
                    t2.stop();
                    t1.stop();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            } catch (IOException | ClassNotFoundException e) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }

    }
    chm.put(user, null);
    clients.remove(this);
    sendAll(new Message(user.getUsername() + " has disconnected", null));

}

private class InputHandler implements Runnable{
    private Buffer<Model.Message> inputBuffer;

    public InputHandler(){
        inputBuffer = new Buffer<>();
    }

    public void addToBuffer(Message msg){
        inputBuffer.put(msg);
    }

    @Override
    public synchronized void run() {
        Object o = null;
        while (!Thread.interrupted()) {
            Message temp = null;
            Message sendable = null;
            try {
                temp = inputBuffer.get();
                sendable = new Message(temp.getText(), temp.getIcon(), temp.getRecipients(), temp.getSender());
                sendable.setCurrID();
                sendable.setUploaded(new Timestamp(System.currentTimeMillis()));
                sendSelect(sendable ,sendable.getSender());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}
public void sendSelect(Message msg, User selectedUser){
        Client currClient;
        if(!chm.containsKey(selectedUser)) {
            try {
                oos.writeObject(new Message(selectedUser.getUsername() + "not found", null));
                oos.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else if ((currClient = chm.get(selectedUser)) != null) {
            try {
                currClient.oos.writeObject((Model.Message) msg);
                currClient.oos.flush();
                msg.setDownloaded(new Timestamp(System.currentTimeMillis()));
                callback.downloadTimestamp(msg);
            } catch (IOException e) {
                e.printStackTrace();
            }

        } else {
            addUnsent(selectedUser, msg);
        }
}

The classes I serialized copy and pasted.

The classpath is the same, all fields are serializable and the have no-arg constructors. I also made sure both encoding on are set to UTF-8

Message

package Model;

import javax.swing.*;
import java.io.*;
import java.sql.Timestamp;
import java.util.LinkedList;

public class Message implements Serializable{
    @Serial
    private static final long serialVersionUID = -3930131856060689940L;

    private static int nextID = 0;
    private int currID;

    private final String text;
    private final ImageIcon icon;

    private Timestamp uploaded;
    private Timestamp downloaded;

    private final User sender;
    private final LinkedList<User> recipients;

    public Message(){
        currID = nextID;
        nextID++;
        this.text = null;
        this.icon = null;
        sender = null;
        recipients = null;
    }
    public Message(String text, User sender){
        currID = nextID;
        nextID++;
        this.text = text;
        this.icon = null;
        this.sender = sender;
        this.recipients = null;

    }
    public Message(String text, ImageIcon icon, User sender) {
        currID = nextID;
        nextID++;
        this.text = text;
        this.icon = icon;
        this.sender = sender;
        this.recipients = null;

    }
    public Message(String text, ImageIcon icon, LinkedList<User> recipients, User sender) {
        currID = nextID;
        nextID++;
        this.text = text;
        this.icon = icon;
        this.sender = sender;
        this.recipients = recipients;

    }

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof Message){
            if( ((Message) obj).getCurrID() == this.currID ){
                return true;
            }
        }
        return false;
    }
    public String getText() {
        return text;
    }
    public ImageIcon getIcon() {
        return icon;
    }
    public Timestamp getUploaded() {
        return uploaded;
    }
    public Timestamp getDownloaded() {
        return downloaded;
    }
    public Model.User getSender(){return sender;}
    public int getCurrID(){return currID;}
    public void setCurrID(){currID = nextID; nextID++;}
    public LinkedList<User> getRecipients(){
        return recipients;
    }
    public void setUploaded(Timestamp uploaded) {
        this.uploaded = uploaded;
    }
    public void setDownloaded(Timestamp downloaded) {
        this.downloaded = downloaded;
    }
}

User

package Model;

import javax.swing.*;
import java.io.Serial;
import java.io.Serializable;

public class User implements Serializable{
    @Serial
    private static final long serialVersionUID = -5886308724572898536L;

    private String username;
    private ImageIcon image;

    public User(String username, ImageIcon image){
        this.username = username;
        this.image = image;
    }

    public int hashCode() {
        return username.hashCode();
    }

    public boolean equals(Object obj) {
        if(obj!=null && obj instanceof User)
            return username.equals(((User)obj).getUsername());
        return false;
    }

    public String getUsername() {
        return username;
    }

    @Override
    public String toString(){
        return username;
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

云雾 2025-01-19 03:20:50

问题是我调用了 setUpThread() 两次,弄乱了输入流。因此,如果遇到此类问题,请确保不要多次初始化线程(从套接字读取输入流)。

The issue was I called setUpThread() twice, messing with the input stream. So if you get this kind of problem, make sure you don't initialize your threads (that are reading input stream from the sockets) more than once.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文