【问题标题】:In Java, must non-serializable Sockets prevent use of a client-server Observer pattern?在 Java 中,不可序列化的套接字是否必须阻止使用客户端-服务器观察者模式?
【发布时间】:2012-04-28 13:54:09
【问题描述】:

在我的 Java Sockets 程序中,我实现了客户端-服务器观察者模式。也就是说,服务器主体将其服务器事件发布给已订阅服务器的客户端观察者。这就是理论。

实际上,我无法通过套接字发送客户端观察者来订阅服务器。出现的错误是:“java.io.NotSerializableException:java.net.Socket。”我认为这意味着 Java 抱怨客户端观察者包含一个 Socket,众所周知,它不是可序列化的。

但是,Socket 是客户端和服务器之间的通信手段!

当客户端似乎包含不可序列化的障碍时,我如何实现客户端-服务器观察者模式?

下面是代码概览,让您了解正在发生的事情:

服务器

public class Server implements ServerSocketPublisher {

    // traditional Observer publisher methods implemented here, such as register, 
    // deregister, notifySubscribers

    // ServerSocket implemented here. Waiting on accept()

}

客户

public class Client implements ClientSocketSubscriber, Serializable {

    // traditional Observer subscriber methods implemented here, i.e. updateClient

    Socket connectingSocket = null; //I SUSPECT THIS VARIABLE IS THE PROBLEM

    try {
         connectingSocket = new Socket();
         // set SocketAddress and timeout
         connectingSocket.connect(sockAddr, timeout)
         if (connectingSocket.isConnected()) {
             ObjectOutputStream oos = new ObjectOutputStream     
                  (connectingSocket.getOutputStream());
             oos.writeObject(this); // THIS LINE THROWS THE ERROR in STACKTRACES
             oos.flush();
             oos.close();
         }
    } catch (/*various exceptions*/) {
    }
    // close connectingSocket
}

【问题讨论】:

  • 这对我来说毫无意义。序列化套接字?
  • 是的。令您惊讶的是,Observer 显然不是 Java 中套接字的好模式。很抱歉浪费了大家的时间。
  • 不要误会我的意思,我不是客户端服务器方面的专家,所以不要把我的怀疑当作福音,但这看起来很奇怪。
  • 有趣的问题和讨论,1+
  • 为了使用Sockets 实现这一点,您必须轮询套接字以接收观察者事件。这对我来说似乎是矛盾的:观察者模式的重点是避免轮询。

标签: java sockets serialization client-server


【解决方案1】:

你有几种方法可以解决这个问题:

  1. 将您的套接字标记为瞬态

    transient Socket 连接Socket = null;

  2. 不要实现Serializable,而是实现Externalizable,然后在你的读写对象实现中忽略Socket。

除此之外,您还应该阅读

关于瞬态:

  1. Post on SO

关于外部化:

  1. Javabeat

【讨论】:

  • 就像我说的,让专家来说话。 1+ 我不确定为什么@Guillaume 删除了他的答案。
【解决方案2】:

您不能将客户端写入输出流套接字,因为它包含一个套接字。如果你序列化客户端,你会序列化其中的所有非瞬态变量,这就是你得到异常的时候。

但是,服务器端已经有套接字,因此您不需要发送它和客户端。如果一旦连接发生,所有客户端都是观察者,那么您几乎可以在此时开始等待来自客户端套接字的数据。服务器需要保留一个准备广播的套接字列表,当它收到要发送的事件时,循环遍历所有套接字并发送注册、注销、通知订阅者消息

或者,如果您希望将客户端视为服务器端的对象并在其上调用方法(看起来您可能正在尝试这样做),也许您需要查看 RMI - 服务器保存存根客户端并调用存根向客户端发送消息。

【讨论】:

  • +1,感谢您花时间提出一些有趣的想法。我会考虑尝试实施您的想法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多