通过套接字流发送对象

Sending objects through socket streams

正在尝试编写一个允许客户端相互发送对象的程序。我目前正在使用 ObjectOuptutStream 跨套接字发送它,每当我尝试从对象流读取或写入对象时,它都会给出异常:java.io.NotSerializableException。我在网上搜索了有关此异常的信息,我得到的解决方案主要是在您正在发送或从流中读取的对象上实现 Serializable 接口。我这样做了,但仍然收到此异常。

这是对象 class:

public class Event implements Serializable {

    private static final long serialVersionUID = 1L;

    Integer from;
    Vector<Integer> timestamp;

    public Event(int identifier, Vector<Integer> timestamp) {
        this.from = identifier;
        this.timestamp = timestamp;
    }

    int getFromID() {
        return from;
    }

    Vector<Integer> getTimestamp() {
        return timestamp;
    }

}

这是客户端 class 正在写入其他套接字的部分

    Random rand = new Random();

    int temp;
    while (eventCount < 100) {
        System.out.println("Generating Event");
        int choice = rand.nextInt(5);
        if (choice == 0) {
            temp = timestamp.get(identifier);
            ++temp;
            timestamp.set(identifier, temp);
        } else {
            int randC = rand.nextInt(outputClients.size());
            ClientSocket cc = outputClients.get(randC);
            cc.out.writeObject(new Event(identifier, timestamp));
        }
        System.out.println("Done Generating Event");
    }

这是读取对象的线程

public class ClientConnection extends Thread {
    Socket socket;
    ObjectOutputStream out;
    ObjectInputStream in;
    Random rand = new Random();
    public ClientConnection(Socket s) {
        this.socket = s;
        try {
            out = new ObjectOutputStream (socket.getOutputStream());
            in = new ObjectInputStream (socket.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // execute the event
    private void executeEvent(int from, Vector<Integer> x) {
        int temp;
        synchronized (timestamp) {
            for (int i = 0; i < timestamp.size(); ++i) {
                if (x.get(i) > timestamp.get(i)) {
                    timestamp.set(i, x.get(i));
                }
            }
            temp = timestamp.get(from);
            ++temp;
            timestamp.set(from, temp);
        }
    }

    @Override
    public void run () {
        while (true) {
            System.out.println("Reading events");
            if (!isAlive) { 
                break;
            }
            try {
                Event event = (Event) in.readObject();
                executeEvent(event.getFromID(), event.getTimestamp());
            } catch (ClassNotFoundException e) {

            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println(timestamp);
        }
    }
}

这里是完整上下文的客户端 class(假设导入了所有适当的包)

public class Computer {

static final int MAX_SYSTEMS = 2;                   // MAX SYSTEMS
static Vector<Integer> timestamp = new Vector<Integer>();
static int[] timestamp1 = new int[MAX_SYSTEMS];     // Time-stamp
static int identifier;                              // Computer ID
static int eventCount = 0;                          // Event Counts
static boolean isAlive = true;                      // Check if the computer is alive

Socket sockToServer;
PrintWriter outputToServer;
BufferedReader inputFromServer;
String textFromServer;

ServerSocket ss;

static ArrayList<ClientSocket> outputClients = new ArrayList<ClientSocket>();
static ArrayList<ClientConnection> inputClients = new ArrayList<ClientConnection>();

Log log;

public static void main(String[] args) throws IOException {
    new Computer("127.0.0.1", 8000);
}

public Computer(String hostname, int port) throws IOException {
    // Instantiate server socket
    int socketPort = port + identifier + 1;
    System.out.println(socketPort);
    ss = new ServerSocket(socketPort);

    System.out.println("Server Socket Instantiated");

    // Creating sockets (with streams) to write to stream
    for (int i = 0; i < MAX_SYSTEMS; ++i) {
        if (i != identifier) {
            Socket thing1 = new Socket(hostname, port + i + 1);
            ClientSocket cs = new ClientSocket (thing1);
            outputClients.add(cs);
        }
    }

    log.write("Client Sockets Instantiated\n");

    // Create threads for reading objects and updating timestamp
    for (int i = 0; i < MAX_SYSTEMS - 1; ++i) {
        ClientConnection clientConn = new ClientConnection(ss.accept());
        clientConn.start();
        inputClients.add(clientConn);
    }

    log.write("Server connected to clients");

    Random rand = new Random();

    // Writing Events

    int temp;
    while (eventCount < 100) {
        System.out.println("Generating Event");
        int choice = rand.nextInt(5);
        if (choice == 0) {
            temp = timestamp.get(identifier);
            ++temp;
            timestamp.set(identifier, temp);
        } else {
            int randC = rand.nextInt(outputClients.size());
            ClientSocket cc = outputClients.get(randC);
            cc.out.writeObject(new Event(identifier, timestamp));
        }
        System.out.println("Done Generating Event");
    }

    log.write("Computer finished generating events. Continue listening...\n");

    outputToServer.println("Finish");

    // Wait for Tear Down Message
    while (true) {
        try {
            textFromServer = inputFromServer.readLine();
            if (textFromServer.equals("Tear Down")) {
                isAlive = false;
                break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    log.write("Computer shutting off....");

    for (int i = 0; i < outputClients.size(); ++i) {
        ClientSocket sc = outputClients.get(i);
        sc.socket.close();
    }

    sockToServer.close();

}

// client socket class (organizing)
public class ClientSocket {
    Socket socket;
    ObjectOutputStream out;
    ObjectInputStream in;

    public ClientSocket(Socket s) {
        try {
            this.socket = s;
            this.out = new ObjectOutputStream(socket.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("Client Socket Created");
    }
}

public class Event implements Serializable {

    private static final long serialVersionUID = 1L;

    Integer from;
    Vector<Integer> timestamp;

    public Event(int identifier, Vector<Integer> timestamp) {
        this.from = identifier;
        this.timestamp = timestamp;
    }

    int getFromID() {
        return from;
    }

    Vector<Integer> getTimestamp() {
        return timestamp;
    }

}

// send event thread
public class ClientConnection extends Thread {
    Socket socket;
    ObjectOutputStream out;
    ObjectInputStream in;
    Random rand = new Random();
    public ClientConnection(Socket s) {
        this.socket = s;
        try {
            out = new ObjectOutputStream (socket.getOutputStream());
            in = new ObjectInputStream (socket.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // execute the event
    private void executeEvent(int from, Vector<Integer> x) {
        int temp;
        synchronized (timestamp) {
            for (int i = 0; i < timestamp.size(); ++i) {
                if (x.get(i) > timestamp.get(i)) {
                    timestamp.set(i, x.get(i));
                }
            }
            temp = timestamp.get(from);
            ++temp;
            timestamp.set(from, temp);
        }
    }

    @Override
    public void run () {
        while (true) {
            System.out.println("Reading events");
            if (!isAlive) { 
                break;
            }
            try {
                Event event = (Event) in.readObject();
                executeEvent(event.getFromID(), event.getTimestamp());
            } catch (ClassNotFoundException e) {

            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println(timestamp);
        }
    }
}   
}

TL;DR 尝试使用 Object(Output/Input)Stream 对象通过套接字读写对象。当我这样做时,我得到了 NotSerializableException,即使我在正在写入和从流中读取的 class 中实现了 Serializable 接口。

感谢所有帮助!

(编辑:堆栈跟踪)

java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: timetableexchange.Computer
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
    at java.io.ObjectInputStream.readSerialData(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at timetableexchange.Computer$ClientConnection.run(Computer.java:239)
Caused by: java.io.NotSerializableException: timetableexchange.Computer
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
    at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.writeObject(Unknown Source)
    at timetableexchange.Computer.<init>(Computer.java:128)
    at timetableexchange.Computer.main(Computer.java:39)
java.io.NotSerializableException: timetableexchange.Computer
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
    at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.writeObject(Unknown Source)
    at timetableexchange.Computer.<init>(Computer.java:128)
    at timetableexchange.Computer.main(Computer.java:39)

现在你已经提供了堆栈跟踪....我明白了问题!

您已将 Event 创建为 Computer 的内部 class。这意味着 Event 对封闭的 Computer 实例有一个隐含的 link ...它将与 Event 实例一起序列化。

但是 Computer 不是 Serializable

一个(可能不正确的)解决方案是使 Computer 实现 Serializable。但这意味着您将发送一个 Computer 的实例,每个单独序列化 Event ...这就是为什么它可能是错误的。

更好的解决方案是将 Event 声明为 static,这样它 就不会 引用封闭的 Computer .据我所知,它不需要是 "inner" class。它可能只是 "nested" class,甚至是顶级 class.

建议:当您使用嵌套和内部 classes 时,请确保正确缩进它们...以便其他人更容易发现正在发生的事情。