通过套接字流发送对象
Posted
技术标签:
【中文标题】通过套接字流发送对象【英文标题】:Sending objects through socket streams 【发布时间】:2019-04-21 07:01:35 【问题描述】:试图编写一个允许客户端相互发送对象的程序。我目前正在使用 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;
这是客户端类中写入其他套接字的部分
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 对象通过套接字读取和写入对象。当我这样做时,我得到了 NotSerializableException,即使我在从流中写入和读取的类中实现了 Serializable 接口。
感谢所有帮助!
(编辑:堆栈跟踪)
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)
【问题讨论】:
包括完整的堆栈跟踪。 您是否尝试过实现“readObject”和“writeObject”方法? @StephenC 抱歉。在原始帖子中包含堆栈跟踪。 @JasonArmstrong 我不明白你的意思。我添加了 readobject 和 writeobject 来分别读取和写入对象。你的意思是它们需要通过 Serializable 接口来实现吗? 我没有看到它们在上面的 Event 类中实现。另外,要考虑的另一件事是 Externalizable 接口。 【参考方案1】:现在您已经提供了堆栈跟踪...。我看到了问题!
您已将Event
创建为Computer
的内部类。这意味着Event
具有到封闭Computer
实例的隐式链接......它将与Event
实例一起序列化。
但是Computer
不是Serializable
。
一个(可能不正确的)解决方案是让Computer
实现Serializable
。但这意味着您将发送一个 Computer
的实例以及每个单独序列化的 Event
...这就是为什么它可能是错误的。
更好的解决方案是将Event
声明为static
,以便它不引用封闭的Computer
。据我所知,它不需要是“内部”类。它可能只是一个“嵌套”类,甚至是***类。
建议:当您使用嵌套类和内部类时,请确保正确缩进它们...以便其他人更容易发现发生了什么。
【讨论】:
你完全正确!太感谢了!这是有道理的,因为事件类是计算机类的一部分,计算机类可能需要实现 Serializable 接口。现在我将 Event Class 移到了***别,它起作用了!非常感谢!以上是关于通过套接字流发送对象的主要内容,如果未能解决你的问题,请参考以下文章
通过套接字接收数组列表时出现 NullPointerException