繁体   English   中英

两个独立的 Java 桌面应用程序之间的通信

[英]Communication between two separate Java desktop applications

我希望开发两个独立(但相关)的 Java 桌面应用程序。

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

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

为了展示让两个应用程序相互通信是多么容易,请查看这个使用 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;
            }

        });
    }

}

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

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

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

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

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

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

他们每个人都可以监听一个Socket 本教程非常适合入门。

您还应该考虑使用经典的 RMI。

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

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

这里可以找到有关如何操作的更多信息(Sun/Java 文档)。

  • “企业”的方式是在 Java EE 服务器或至少在 Spring 框架中运行这些应用程序。 这也可能太过分了。

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

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

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

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

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

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

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

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

希望这可以帮助

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

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

最简单的方法是在没有独立 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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM