通过套接字流发送对象

时间:2018-11-18 21:52:04

标签: java sockets serializable objectinputstream objectoutputstream

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

这是对象类:

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

}

这是Client类中正在写入其他套接字的部分

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

这是用于完整上下文的Client类(假设已导入所有适当的包)

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对象通过套接字读取和写入对象。当我这样做时,即使我在要从流中读写的类中实现了Serializable接口,也得到了NotSerializableException。

感谢所有帮助!

(编辑:stacktrace)

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)

1 个答案:

答案 0 :(得分:1)

现在您已经提供了stacktrace...。我看到了问题!

您已创建Event作为Computer的内部类。这意味着Event有一个隐含的链接到封闭的Computer实例...,它将与Event实例一起序列化。

但是Computer不是Serializable

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

一个更好的解决方案是将Event声明为static,这样它不会引用封闭的Computer。据我所知,它不必是“内部”类。它可能只是一个“嵌套”类,甚至是一个顶级类。

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