Отправка объектов через потоки сокетов - PullRequest
0 голосов
/ 19 ноября 2018

Попытка написать программу, которая позволит клиентам отправлять объект друг другу. В настоящее время я использую 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 Попытка чтения и записи объекта через сокеты с использованием объекта Stream (выход / вход) Stream. Когда я это делаю, я получаю NotSerializableException, хотя я реализовал интерфейс Serializable в классе, который записывался и читался из потока.

Вся помощь приветствуется!

(редактировать: 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 голосов
/ 19 ноября 2018

Теперь, когда вы предоставили трассировку стека .... Я вижу проблему!

Вы создали Event как внутренний класс Computer. Это означает, что Event имеет неявную ссылку на включающий экземпляр Computer ..., который будет сериализован вместе с экземпляром Event.

Но Computer не Serializable.

(возможно, неверное) решение было бы заставить Computer реализовать Serializable Но это означает, что вы отправили бы экземпляр Computer с каждым отдельно сериализованным Event ..., поэтому, вероятно, это неправильно.

Лучшим решением было бы объявить Event как static, чтобы не не содержало ссылку на включающий Computer. Насколько я вижу, это не должен быть «внутренний» класс. Это может быть просто «вложенный» класс или даже класс верхнего уровня.

Совет: Когда вы используете вложенные и внутренние классы, убедитесь, что вы правильно сделали отступ для них ... чтобы другим людям было легче определить, что происходит.

...