我正在编写一个桌面 Java 应用程序,它基本上在系统托盘中运行。此应用程序可以接受命令行参数。如果有一个应用程序的实例正在运行并且另一个实例使用命令行参数调用,它只是将它传递给系统托盘中正在运行的进程。
我对如何实现这一点非常迷茫?我见过一些应用程序这样做,但我不记得名字了。我想传递的只是字符串参数,然后退出。
我正在编写一个桌面 Java 应用程序,它基本上在系统托盘中运行。此应用程序可以接受命令行参数。如果有一个应用程序的实例正在运行并且另一个实例使用命令行参数调用,它只是将它传递给系统托盘中正在运行的进程。
我对如何实现这一点非常迷茫?我见过一些应用程序这样做,但我不记得名字了。我想传递的只是字符串参数,然后退出。
实施此解决方案有两个部分:
使用 Sockets 可以同时完成 1 和 2。
你可以做的是让你的程序在你的程序启动时监听一个端口。当你启动另一个程序实例时,它会尝试监听同一个端口,如果该端口被占用,你可以假定已经有一个程序实例在运行。当然,您应该选择一个任何应用程序都不常用的端口。
然后,如果程序的实例已经启动,只需使用 Sockets 传递 String 参数。
换句话说,您希望您的应用程序是单例的。当用户尝试运行另一个应用程序实例时,它应该向已经存在的应用程序发送某种命令。
您可以按以下方式进行。
应用程序启动时应该打开服务器套接字到您选择的端口。如果成功,它应该开始。这是您的应用程序的第一个实例。如果失败,则表示该端口已经很忙,因此您的应用程序的其他实例正在侦听它。在这种情况下,连接到此套接字,发送命令并终止。
选择端口号时要小心。它应该足够高(> 10000)并且不应该被任何其他流行的应用程序使用。选择一些数字,然后尝试用谷歌搜索。
基本上这个想法是在启动时绑定一个本地端口,如果失败连接到它并发送参数。
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();
}
}
}
您需要执行某种进程间通信。有许多技术可以用来实现这一目标,包括:
(写入文件对于 IPC 来说是一个糟糕的选择,除非您使用的是 POSIX 命名管道而不是普通文件)。
另一种选择是使用在单独进程中运行的缓存。