在 java 中通过套接字发送对象的意外行为
Unexpected behavior sending object through socket in java
我正在使用 ObjectOutputStream
通过 Java 中的套接字发送 POJO,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
classes,想法是在服务器中创建一个Game
class的实例并发送它发送给客户端,然后在 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
服务器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);
}
}
客户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);
}
}
问题
为什么当矩阵被发送到客户端时在服务器中被修改,而客户端收到的是未修改的矩阵?
谢谢
Java 序列化可以循环处理各种对象图。它通过发回引用而不是将对象序列化两次来实现。
第二次发送对象时,您只是发送一个引用。您需要调用 ObjectOutputStream.reset
流,关闭该流以替换为另一个流,或者最好使用不可变值对象。或者前两个和最后一个 - 为了能够使用反向引用,ObjectOutputStream
保留对所有发送的对象的引用,并且 ObjectInputStream
同样对所有接收的对象。
(您可以使用 ObjectOutputStream.writeUnshared
但这会变得更加混乱,因为组件对象将被共享。)
标准警告:不要使用 Java 序列化。
我正在使用 ObjectOutputStream
通过 Java 中的套接字发送 POJO,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
classes,想法是在服务器中创建一个Game
class的实例并发送它发送给客户端,然后在 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
服务器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);
}
}
客户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);
}
}
问题
为什么当矩阵被发送到客户端时在服务器中被修改,而客户端收到的是未修改的矩阵?
谢谢
Java 序列化可以循环处理各种对象图。它通过发回引用而不是将对象序列化两次来实现。
第二次发送对象时,您只是发送一个引用。您需要调用 ObjectOutputStream.reset
流,关闭该流以替换为另一个流,或者最好使用不可变值对象。或者前两个和最后一个 - 为了能够使用反向引用,ObjectOutputStream
保留对所有发送的对象的引用,并且 ObjectInputStream
同样对所有接收的对象。
(您可以使用 ObjectOutputStream.writeUnshared
但这会变得更加混乱,因为组件对象将被共享。)
标准警告:不要使用 Java 序列化。