4

我正在编写一个桌面 Java 应用程序,它基本上在系统托盘中运行。此应用程序可以接受命令行参数。如果有一个应用程序的实例正在运行并且另一个实例使用命令行参数调用,它只是将它传递给系统托盘中正在运行的进程。

我对如何实现这一点非常迷茫?我见过一些应用程序这样做,但我不记得名字了。我想传递的只是字符串参数,然后退出。

4

6 回答 6

2

实施此解决方案有两个部分:

  1. 检测是否已经有程序实例在运行
  2. 如果程序已经在运行,则将字符串参数传递给程序

使用 Sockets 可以同时完成 1 和 2。

你可以做的是让你的程序在你的程序启动时监听一个端口。当你启动另一个程序实例时,它会尝试监听同一个端口,如果该端口被占用,你可以假定已经有一个程序实例在运行。当然,您应该选择一个任何应用程序都不常用的端口。

然后,如果程序的实例已经启动,只需使用 Sockets 传递 String 参数。

于 2012-06-14T06:40:27.717 回答
2

换句话说,您希望您的应用程序是单例的。当用户尝试运行另一个应用程序实例时,它应该向已经存在的应用程序发送某种命令。

您可以按以下方式进行。

应用程序启动时应该打开服务器套接字到您选择的端口。如果成功,它应该开始。这是您的应用程序的第一个实例。如果失败,则表示该端口已经很忙,因此您的应用程序的其他实例正在侦听它。在这种情况下,连接到此套接字,发送命令并终止。

选择端口号时要小心。它应该足够高(> 10000)并且不应该被任何其他流行的应用程序使用。选择一些数字,然后尝试用谷歌搜索。

于 2012-06-14T06:41:10.100 回答
2

基本上这个想法是在启动时绑定一个本地端口,如果失败连接到它并发送参数。

public class StartOnce {

  public static void main(String args[]) throws IOException {
    SocketAddress addr = new InetSocketAddress("127.0.0.1", 9999);

    try {
        ServerSocket ss = new ServerSocket();
        // tries to bind to localhost:9999
        ss.bind(addr);
        // Ok, I'm the first instance, listen for other instances for update.
        while(true) {
            Socket s = ss.accept();
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            String line = null;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
            br.close();
            s.close();
        }
    } catch (BindException e) {
        // BindException, tries to send message to the first instance.
        System.out.println("Another instance is running. Say hi.");
        Socket s = new Socket();
        s.connect(addr);
        PrintWriter pw = new PrintWriter(s.getOutputStream());
        pw.println("Hello.");
        for (String arg : args) {
            pw.println(arg);
        }
        pw.close();
        s.close();
    }
  }
}
于 2012-06-14T06:53:40.860 回答
0

您需要执行某种进程间通信。有许多技术可以用来实现这一目标,包括:

  • 插座
  • 网页服务
  • Java 远程方法调用 (RMI)
  • 使用数据库
  • 写入文件

(写入文件对于 IPC 来说是一个糟糕的选择,除非您使用的是 POSIX 命名管道而不是普通文件)。

于 2012-06-14T06:40:23.107 回答
0

有多种方法可以实现这一目标。在 Java 中,您可以将JMS用于此类事情。如果您使用的是 Spring,则有此模板。这是一个关于如何开始使用 JMS的教程。

或者您可以使用套接字,甚至RMI在多个进程内交换数据。

于 2012-06-14T06:37:13.840 回答
0

另一种选择是使用在单独进程中运行的缓存。

于 2019-01-09T22:25:25.117 回答