Java - 可通过套接字进行序列化和发送对象

时间:2011-02-04 13:09:39

标签: java serializable

我收到错误:

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对象..... 我尝试重新定义和序列化套接字对象,但没有办法解决问题.... 我哪里错了?

6 个答案:

答案 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方法,这些方法将用于序列化和反序列化。

查看this article on serialization

答案 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;

最干净的是将您的玩家状态与网络代码分开,从而导致只有Seri​​alizable成员的类。作为奖励,发送类不再包含无效的成员字段。