【问题标题】:Communication between two separate Java desktop applications两个独立的 Java 桌面应用程序之间的通信
【发布时间】:2010-12-13 10:43:08
【问题描述】:

我正在寻找开发两个独立(但相关)的 Java 桌面应用程序。

我希望一个应用程序能够触发另一个应用程序,传入可以编辑和传回的数据,即通信将是两种方式。如果其他应用程序已经在运行,我希望它们只进行通信,即我不想只通过命令行传递参数等。

一般来说,为了实现这一目标,我应该考虑哪些策略/技术?

【问题讨论】:

  • 好问题。你有没有实现过这个?
  • 还没有......这是对即将到来的项目的一些非常初步的研究:)
  • 投票重新开放的人能表达他们的理由吗?
  • 我处于同样的情况,实际上在想,为什么不只是 CLI?有什么问题?

标签: java ipc


【解决方案1】:

要展示让两个应用程序相互通信是多么容易,请查看这个使用 JGroups 的网络剪贴板演示。只需启动两个实例并开始将文件放入其中一个。第二个实例将立即显示相同的文件。

import java.io.Serializable;
import java.awt.*;
import java.awt.datatransfer.*;
import javax.swing.*;
import org.jgroups.*;

public class JGroupsTest {

    public static void main(String[] args) throws Exception {
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        frame.setSize(500, 300);
        final DefaultListModel listModel = new DefaultListModel();
        final JList panel = new JList(listModel);
        panel.setBackground(new Color(128, 0, 40));
        panel.setForeground(new Color(240, 240, 240));
        frame.add(panel);
        System.setProperty("java.net.preferIPv4Stack", "true");
        final JChannel channel = new JChannel("udp.xml");
        channel.connect("networkclipboard");
        channel.setReceiver(new ReceiverAdapter() {
            @Override
            public void viewAccepted(View newView) {
                frame.setTitle("Network Clipboard - " + channel.getLocalAddress());
            }

            @Override
            public void receive(Message msg) {
                listModel.addElement(msg.getObject());
            }
        });

        panel.setTransferHandler(new TransferHandler() {
            @Override
            public boolean importData(JComponent comp, Transferable t) {
                DataFlavor[] transferDataFlavors = t.getTransferDataFlavors();
                for (DataFlavor flavor : transferDataFlavors) {
                    try {
                        Object data = t.getTransferData(flavor);
                        if (data instanceof Serializable) {
                            Serializable serializable = (Serializable) data;
                            Message msg = new Message();
                            msg.setObject(serializable);
                            channel.send(msg);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return super.importData(comp, t);
            }

            @Override
            public boolean canImport(TransferSupport support) {
                return true;
            }

            @Override
            public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
                return true;
            }

        });
    }

}

【讨论】:

  • 嗨@mhaller 我想知道您在main 方法中使用throws 是否有任何具体原因,因为main 方法是我们用try catch 围绕它的特定方法。请详细说明。
  • @Vishrant - 我只是懒惰。允许使用 throws 作为 main 方法,没有区别。我也经常为单元测试声明throws Exception,所以我不必单独处理所有检查的异常。
  • 感谢回复,我主要使用throws关键字,当有像struts这样的容器但我在我的应用程序中编写main方法时(这是一个特定的方法不是常用的方法)我使用try catch 块以我自己的方式处理Exception。是的,在main 方法中使用throws 会有所不同,如果在main 方法中出现任何Exception,它将被抛出到JVM 并且您的程序将停止,JVM 也会以自己的方式抛出Exception大大地。 throwsre-throwing Exception 的概念,在Common Methods 中使用(许多类使用的方法)。
【解决方案2】:

这取决于您希望如何传达这两个程序:

  • 如果您只需要进程间信号量,请在 /tmp 中的某处创建一个文件并将其锁定。

  • 如果只需要进程间同步消息(远程过程调用),RMI 应该是最简单的。

  • 如果您需要异步进程间消息传递,JMS 应该是最简单的。

  • 如果需要进程间共享内存,请使用映射文件。

  • 如果您需要以上所有内容,Terracotta (http://www.terracotta.org/ ) 是最简单的方法:同一台甚至不同计算机上不同 JVM 上的 Java 程序可以互相查看,就好像它们是在一台机器上的一个 JVM 内执行。将一个程序分成几个甚至不需要任何代码更改 - 编写一个 XML 配置文件就足够了。

【讨论】:

    【解决方案3】:

    他们每个人都可以在Socket 上收听。 This tutorial 是很好的开始。

    【讨论】:

    • 这是通常的做法还是 RMI ?或者更确切地说,有什么区别?
    • @Pacerier - 套接字是一种将字节流式传输到网络堆栈的方法。 RMI 允许调用存在于不同 JVM 中的对象的方法,数据交换对 RMI 是不透明的,但仍然可以在下面使用套接字。
    • Ic,所以套接字是最好的,因为它简单快速
    【解决方案4】:

    您还应该考虑好的 ol' 经典 RMI。

    【讨论】:

    • 当我想要有两个不同的进程时,这通常是这种方法吗?
    • 这是在 JVM(通常作为不同的进程)之间来回传递 Java 对象的基本方式。您还可以共享对象引用以作用于其他 JVM 中的远程对象。当然,整个 EJB 事物和框架都未能尝试抽象出 RMI,但它是共享多 JVM 共享对象的真正方法。公平地说,它是一种调用远程方法的方式,但大多数方法无论如何都会返回或传递对象。
    【解决方案5】:

    看看JavaGroups,它会解决你的沟通问题,还可以帮助你检测其他应用程序是否正在运行。如果应用程序没有运行,您必须使用 java.lang.Runtime.exec() 为它启动一个新的 JVM...

    【讨论】:

    • +1 为 JGroups,我喜欢它。仅供参考,您知道此页面已有 10 年历史,并且 JBoss 多年来一直采用相同的代码吗?参见 jgroups.org
    【解决方案6】:

    尝试与 SocketCommunication 通信,即使应用程序在同一台机器上。

    这里可以找到有关how to do it 的更多信息(Sun/Java 文档)。

    【讨论】:

      【解决方案7】:
      • “企业”的方式是在 Java EE 服务器或至少在 Spring 框架中运行这些应用程序。这也可能是大为矫枉过正。

      • 如果需要传递一堆数据,那么 RMI 会做。

      • 如果您不害怕破解自己的协议、数据结构和错误处理,您可以设置服务器和客户端套接字并通过它们进行通信。

      • 我认为通过公共目录中的文件(设置您自己的协议,确定谁在何时写入或删除文件)或通过共享数据库进行通信的替代方案具有一定的粗略吸引力。技术含量低,速度不是很快,但非常简单可靠。而且从外部监控“通信”相当容易。

      【讨论】:

        【解决方案8】:

        为了简单起见,为什么不使用普通的 TCP 套接字?

        【讨论】:

        • 普通 TCP 套接字不定义协议、序列化对象或提供任何错误恢复等。你必须自己照顾一切。当然,并不是说 RMI 更好!
        • 但是,如果数据很简单,处理这个问题并没有什么大不了的,而且您不必费心额外配置诸如 RMI 注册表之类的东西。
        • @Mark 还有哪些低级替代方案?还是 tcp/ip 是同一台机器中两个程序之间传输数据的唯一方式?
        • @Pacerier - 同一台机器打开大量选项,如共享内存、本地消息队列、文件、域套接字。 &c &c。将协议置于网络堆栈之上(例如 TCP 或 UDP)可以让您轻松扩展操作系统实例的范围。
        【解决方案9】:

        我第二个Socket通信和RMI。 RMI 涉及更多一点,但对程序员来说更直观。这取决于您发送的信息类型。将原始字节推送到另一台机器可能比运行 RMI 服务器并处理所有爵士乐更有意义......

        【讨论】:

          【解决方案10】:

          这取决于您想在这 2 个应用程序之间进行哪种通信。例如,如果您使用套接字或 RMI,则两个应用程序都需要启动才能进行通信。如果您想要进行的通信类型可以更加异步,那么您可以使用更多基于消息传递的方法。

          例如,ZooKeeper 允许您在非常简单但功能强大的原语之上实现几乎任何您想要的东西。此页面 (http://hadoop.apache.org/zookeeper/docs/current/recipes.html) 解释了如何使用 ZooKeeper 构建更高级别的构造。

          缺点是您需要另一个系统。例如,如果您使用 JGroups,则不需要。

          希望对你有帮助

          【讨论】:

            【解决方案11】:

            根据您正在寻找的通信方式(高延迟、大量数据等)以及该系统是否可以扩展到超过 2 个 Java 系统,可能是使用中间件解决方案的消息传递系统例如 Tibco SmartSockets。

            有关您的设置和期望的更多信息会有所帮助。

            【讨论】:

              【解决方案12】:

              最简单的方法是在没有独立 rmiregistry 的情况下使用 RMI。

              服务器创建本地注册表:

              ServerImpl extends UnicastRemoteObject implements Server
              
              rmiRegistry = LocateRegistry.createRegistry(2020);
              rmiRegistry.bind("server", aServerImpl);
              

              客户端使用 rmi url 查找它(类似于 corbaloc:)

              String url = "rmi://localhost:2020/server";
              Server server = (Server) Naming.lookup(url);
              

              我在 500 毫秒内通过同一个开放连接在一个循环中接到了 1000 个呼叫。是的,就是毫秒。

              来自这里的想法和示例:https://www.censhare.com/us/resources/blog/article/file-streaming-using-java-rmi

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2012-07-21
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-04-03
                • 1970-01-01
                相关资源
                最近更新 更多