3

我收到一个错误:

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

4

6 回答 6

4

您不能序列化 Socket 对象,因此您应该使套接字字段瞬态。如果您需要一些套接字属性,您可以在 Player 中添加额外的字段来表示这些字段。

于 2011-02-04T13:13:41.027 回答
3

这意味着 Socket 类不可序列化。

您必须将 Socket 成员设置为瞬态,然后它不会被序列化。

请务必在私有 readObject(ObjectInputStream) 方法中重新创建 Socket 对象,否则可能会遇到空指针异常。

于 2011-02-04T13:13:10.093 回答
1

编辑回答评论

尝试transient像在

private transient Socket socket;

这将阻止序列化机制尝试发送socket. 请注意,您不能将持有值的对象有意义地发送到另一个进程,这些值代表 OS 资源(如套接字句柄)。在最好的情况下,任何在接收端使用此类对象的尝试都会导致抛出异常。在最坏的情况下,这样的尝试可能会引入细微的错误(数据被发送给错误的用户)。出于这个原因,这样的对象永远不能序列化(除非有人犯了错误)。

考虑以下(简化的)示例:在 UNIX 上,套接字由一个整数(所谓的文件描述符)表示,该整数在创建套接字时由操作系统返回。如果将此值发送到另一个进程,则无法保证该数字实际上是指在接收进程中打开的有效文件句柄。更糟糕的是,如果接收进程中存在具有相同数值的文件句柄,则几乎不可能引用发送进程中打开的同一个套接字。因此,如果在发送数据时该数字实际上用作接收过程中的文件描述符,那么它几乎肯定会到达预期目的地之外的任何地方。

如果发送和接收进程在同一台机器上,有办法将“套接字”从一个进程传输到另一个进程。但我怀疑是否有简单的方法可以从 Java 访问这些操作系统调用。

于 2011-02-04T13:13:56.557 回答
1

implements Serializable本身并不使对象可序列化。对象本身中的任何和所有序列化字段都必须是可序列化的(以及它们包含的任何和所有字段)。

由于套接字不可序列化,因此您不应尝试通过线路发送它。您可以通过将其声明为transient来将其从序列化中排除。反序列化的对象当然没有套接字,因此您可能还需要检查对象中将用于序列化和反序列化的可选 readObject 和 writeObject 方法。

查看这篇关于序列化的文章。

于 2011-02-04T13:16:07.457 回答
1

套接字不可序列化,因为它与正在执行的机器、操作系统等相关联。要可序列化,对象的类必须实现可序列化,并且必须包含所有可递归地序列化的对象。

因此,要序列化您的播放器,您必须从序列化中排除其套接字属性。您可以通过声明属性 transient 来做到这一点:

private transient Socket mySocket;

当播放器将被反序列化时,它的套接字将因此为空,并且很有可能无法正常工作。您可能应该检查您的设计,因为序列化需要套接字才能工作的对象可能没有意义。

于 2011-02-04T13:19:08.257 回答
1

有几种方法可以解决这个问题,最快的方法是标记你的 Socket 成员transient。这确保了 java 的默认序列化将忽略 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;

最干净的方法是将您的 Players 状态与您的网络代码分开,从而产生一个只有 Serializable 成员的类。作为奖励,发送类不再包含无效的成员字段。

于 2011-02-04T13:27:01.833 回答