Неожиданное поведение отправки объекта через сокет в Java - PullRequest
0 голосов
/ 11 декабря 2018

Я отправляю POJO через сокет в Java, используя ObjectOutputStream POJO ниже

import java.io.Serializable;

public class Game implements Serializable {
    private static final long serialVersionUID = 4367518221873521320L;
    private int[][] data = new int[3][3];

    Game() {
        for (int x = 0; x < 3; x++) {
            for (int y = 0; y < 3; y++) {
                data[x][y] = 0;
            }
        }
    }

    int[][] getData() {
        return data;
    }

    public void setData(int[][] data) {
        this.data = data;
    }

    void printMatrix() {
        for (int x = 0; x < 3; x++) {
            for (int y = 0; y < 3; y++) {
                System.out.print(data[x][y] + " ");
            }
            System.out.println();
        }
    }
}

У меня есть классы Server и Client, идея в том, чтобы создать экземпляркласса Game на сервере и отправьте его клиенту, затем внесите изменения в переменную data и отправьте его снова и снова между Server и Client.

.объект отправляется, но его содержимое не является ожидаемым.

Вывод на сервер

Waiting
Connected server
0 0 0 
0 0 0 
0 0 0 
Writing
0 0 0 
0 1 0 
0 0 0 

Ожидаемый вывод (клиент)

Connecting...
Connected client
Reading
0 0 0 
0 0 0 
0 0 0 
Reading
0 0 0 
0 1 0 
0 0 0

Фактический вывод (клиент)

Connecting...
Connected client
Reading
0 0 0 
0 0 0 
0 0 0 
Reading
0 0 0 
0 0 0 #<-- there is no 1
0 0 0

Класс сервера

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    void start(int port) throws IOException {
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("Waiting");
        Socket socket = serverSocket.accept();
        System.out.println("Connected server");

        Game game = new Game();
        game.printMatrix();

        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
        ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());

        System.out.println("Writing");
        oos.writeObject(game);

        game.getData()[1][1] = 1;
        game.printMatrix();
        oos.writeObject(game);
    }

    public static void main(String[] args) throws Exception {
        new Server().start(8082);
    }
}

Класс клиента

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

public class Client {
    public void connect(String host, int port) throws Exception {
        System.out.println("Connecting...");
        Socket socket = new Socket(host, port);
        System.out.println("Connected client");

        ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());

        System.out.println("Reading");
        Game game1 = (Game) ois.readObject();
        game1.printMatrix();
        System.out.println("Reading");
        Game game2 = (Game) ois.readObject();
        game2.printMatrix();

    }

    public static void main(String[] args) throws Exception {
        new Client().connect("localhost", 8082);
    }
}

Вопрос

Почему, если матрица изменяется всервер при отправке клиенту клиент получает неизмененную матрицу?

спасибо

1 Ответ

0 голосов
/ 11 декабря 2018

Сериализация Java может обрабатывать циклы всех видов графов объектов.Это делается путем отправки обратных ссылок вместо сериализации объекта дважды.

Во второй раз, когда вы отправляете объект, вы просто отправляете ссылку.Вам нужно либо вызвать ObjectOutputStream.reset поток, закрыть этот поток, заменив его другим, либо, что лучше, использовать объекты с неизменяемыми значениями.Или любой из первых двух и последнего из них - чтобы иметь возможность использовать обратную ссылку, ObjectOutputStream сохраняет ссылку на все отправленные объекты и ObjectInputStream аналогично для всех полученных объектов.

(Вы можете использовать ObjectOutputStream.writeUnshared, но это становится еще более запутанным, потому что объекты компонентов будут совместно использоваться.)

Стандартное предупреждение: не используйте сериализацию Java.

...