我收到错误:
IOException on socket listen: java.io.NotSerializableException: java.net.Socket
我尝试使用以下代码通过套接字发送对象:
ObjectOutputStream outObjects = new ObjectOutputStream(socket.getOutputStream());
outObjects.writeObject(currentPlayer);
output.flush();
第二行给出错误....但我已经序列化(实现Serializable)类Player(currentPlayer对象的类) 但Player类的成员之一是Socket对象..... 我尝试重新定义和序列化套接字对象,但没有办法解决问题.... 我哪里错了?
答案 0 :(得分:4)
您无法序列化Socket对象,因此您应该使套接字字段瞬态化。如果您需要某些套接字属性,可以将额外的字段添加到Player以表示这些字段。
答案 1 :(得分:3)
这意味着Socket类不可序列化。
您必须将Socket成员设置为transient,然后才会序列化。
确保在私有readObject(ObjectInputStream)方法中重新创建Socket对象,否则可能会遇到空指针异常。
答案 2 :(得分:1)
(编辑回答评论)
尝试将套接字成员声明为transient
,如
private transient Socket socket;
这将阻止序列化机制尝试发送socket
的值。请注意,您无法有意义地将包含值(表示操作系统资源,如套接字句柄)的值的对象发送到另一个进程。在最好的情况下,任何在接收方使用此类对象的尝试都将导致抛出异常。在最坏的情况下,这种尝试可能会引入细微的错误(数据被发送给错误的用户)。出于这个原因,这些对象永远不可序列化(除非有人犯了错误)。
考虑以下(简化)示例:在UNIX上,套接字由整数表示(所谓的文件描述符),在创建套接字时由OS返回。如果将此值发送到另一个进程,则无法保证该数字实际上是指在接收进程中打开的有效文件句柄。更糟糕的是,如果在接收过程中存在具有相同数值的文件句柄,则几乎不可能在发送过程中引用相同的套接字打开。因此,如果在发送数据时该数字实际上在接收过程中用作文件描述符,那么它几乎肯定会在预定的目的地之外的任何地方。
如果发送和接收进程在同一台计算机上,则 方式将“套接字”从一个进程转移到另一个进程。但我怀疑,有一些简单的方法可以从Java访问这些OS调用。
答案 3 :(得分:1)
implements Serializable
本身并不能使对象可序列化。对象本身中的任何和所有序列化字段必须是可序列化的(以及它们包含的任何和所有字段)。
由于套接字不可序列化,因此不应尝试通过线路发送它。您可以通过将其声明为 transient 将其排除在序列化之外。然后,反序列化的对象当然没有套接字,因此您可能还需要检查对象中可选的readObject和writeObject方法,这些方法将用于序列化和反序列化。
答案 4 :(得分:1)
套接字不可序列化,因为它与正在执行的机器,操作系统等相关联。要可序列化,对象的类必须实现Serializable,并且必须包含所有可序列化的递归对象。
因此,要序列化播放器,必须从序列化中排除其socket属性。您可以通过声明属性transient来执行此操作:
private transient Socket mySocket;
当播放器被反序列化时,它的套接字将因此为空,并且它很可能无法正常工作。您应该检查一下您的设计,因为序列化需要套接字工作的对象可能没有意义。
答案 5 :(得分:1)
有几种方法可以解决这个问题,最快的方法就是标记你的Socket成员transient
。这可以确保javas默认序列化将忽略Socket,并且您的副本应该包含null。
private transient Socket sock;
或者您可以提供自己的序列化方法,这要求您自己编写和阅读所有成员。您可以使用Serializable中定义的方法(参见下文)或实现Externalizable。
private void writeObject(java.io.ObjectOutputStream out)
throws IOException
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException;
最干净的是将您的玩家状态与网络代码分开,从而导致只有Serializable成员的类。作为奖励,发送类不再包含无效的成员字段。