Frederick Álvarez
Frederick Álvarez

Reputation: 582

Unexpected behavior sending object through socket in java

I'm sending a POJO through a socket in Java using ObjectOutputStream the POJO is below

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

I have a Server and Client classes, the idea is to create an instance of the Game class in the server and send it to the client, then perform changes in the data variable and send it again back and forth between the Server and the Client.

The object is being sent but its content is not the expected.

Server Output

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

Expected Output (Client)

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

Actual Output (Client)

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

Server class

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

Client class

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

Question

Why if the matrix is being modified in the server when it is sent to the client the client receives the non-modified matrix?

Thanks

Upvotes: 1

Views: 169

Answers (1)

Tom Hawtin - tackline
Tom Hawtin - tackline

Reputation: 147124

Java Serialization can handle cycles all sorts of object graph. It does this by sending back references instead of serialising the object twice.

The second time you are sending the object, you are just sending a reference. You need to either call ObjectOutputStream.reset the stream, close that stream replacing with another or, best, use immutable value objects. Or either of the first two and last of these - in order to be able to use the back reference the ObjectOutputStream keeps a reference to all objects sent, and ObjectInputStream likewise for all objects received.

(You can use ObjectOutputStream.writeUnshared but that gets even more confusing because the component objects will be shared.)

Stndard warning: Don't use Java Serialization.

Upvotes: 1

Related Questions