服务端判断客户端Java程序是否运行(在线)

155 阅读2分钟

jps命令封装:服务端执行jps命令获取运行中的java进程

  • 优点:java原生支持
  • 缺点:jps返回结果需要自己解析、判断,只支持服务端与客户端在同一台机器上
  • 服务端代码:
  • public void jpsTest() {
        Arguments arguments = null;
        try {
            arguments = new Arguments(new String[]{"-v"});
        } catch (IllegalArgumentException var20) {
            System.err.println(var20.getMessage());
            Arguments.printUsage(System.err);
            System.exit(1);
        }
    
        if (arguments.isHelp()) {
            Arguments.printUsage(System.err);
            System.exit(0);
        }
    
        try {
            HostIdentifier var1 = arguments.hostId();
            MonitoredHost var25 = MonitoredHost.getMonitoredHost(var1);
            Set var3 = var25.activeVms();
            Iterator var4 = var3.iterator();
    
            while (true) {
                while (var4.hasNext()) {
                    System.out.println("##########");
                    Integer var5 = (Integer) var4.next();
                    StringBuilder var6 = new StringBuilder();
                    Object var7 = null;
                    int var8 = var5;
                    var6.append(String.valueOf(var8));
                    if (arguments.isQuiet()) {
                        System.out.println(var6);
                    } else {
                        MonitoredVm var9 = null;
                        String var10 = "//" + var8 + "?mode=r";
                        String var11 = null;
    
                        try {
                            var11 = " -- process information unavailable";
                            VmIdentifier var12 = new VmIdentifier(var10);
                            var9 = var25.getMonitoredVm(var12, 0);
                            var11 = " -- main class information unavailable";
                            var6.append(" " + MonitoredVmUtil.mainClass(var9, arguments.showLongPaths()));
                            String var13;
                            if (arguments.showMainArgs()) {
                                var11 = " -- main args information unavailable";
                                var13 = MonitoredVmUtil.mainArgs(var9);
                                if (var13 != null && var13.length() > 0) {
                                    var6.append(" " + var13);
                                }
                            }
    
                            if (arguments.showVmArgs()) {
                                var11 = " -- jvm args information unavailable";
                                var13 = MonitoredVmUtil.jvmArgs(var9);
                                if (var13 != null && var13.length() > 0) {
                                    var6.append(" " + var13);
                                }
                            }
    
                            if (arguments.showVmFlags()) {
                                var11 = " -- jvm flags information unavailable";
                                var13 = MonitoredVmUtil.jvmFlags(var9);
                                if (var13 != null && var13.length() > 0) {
                                    var6.append(" " + var13);
                                }
                            }
    
                            var11 = " -- detach failed";
                            var25.detach(var9);
                            System.out.println(var6);
                            var11 = null;
                        } catch (URISyntaxException var21) {
                            var7 = var21;
    
                            assert false;
                        } catch (Exception var22) {
                            var7 = var22;
                        } finally {
                            if (var11 != null) {
                                var6.append(var11);
                                if (arguments.isDebug() && var7 != null && ((Throwable) var7).getMessage() != null) {
                                    var6.append("\n\t");
                                    var6.append(((Throwable) var7).getMessage());
                                }
    
                                System.out.println(var6);
                                if (arguments.printStackTrace()) {
                                    ((Throwable) var7).printStackTrace();
                                }
                                continue;
                            }
                        }
                    }
                }
                return;
            }
        } catch (MonitorException var24) {
            if (var24.getMessage() != null) {
                System.err.println(var24.getMessage());
            } else {
                Throwable var2 = var24.getCause();
                if (var2 != null && var2.getMessage() != null) {
                    System.err.println(var2.getMessage());
                } else {
                    var24.printStackTrace();
                }
            }
    
            System.exit(1);
        }
    }
    

心跳机制:客户端开启一个线程每隔一定时间向服务端发送心跳

  • 优点:实现简单,适用场景广泛
  • 缺点:可能存在心跳丢失情况导致误判,需要服务端编写接收心跳的逻辑
  • 客户端代码:
  • public class HeartBeat {
        private static HeartBeat instance = new HeartBeat();
        public static HeartBeat getInstance() {
            return instance;
        }
        private Thread monitorThread;
        private volatile boolean toStop = false;
        public void start() {
            monitorThread = new Thread(() -> {
                while (!toStop) {
                    try {
                        //TODO 向服务端发送心跳,可通过tcp、http、websocket等协议
    
                        TimeUnit.SECONDS.sleep(5000);
                    } catch (InterruptedException e) {
                    }
                }
            });
            monitorThread.setDaemon(true);
            monitorThread.setName("heart-beat");
            monitorThread.start();
        }
    
        public void toStop() {
            toStop = true;
            if (monitorThread == null) {
                return;
            }
            monitorThread.interrupt();
            try {
                monitorThread.join();
            } catch (InterruptedException e) {            
            }
        }
    }
    

RMI (Remote Method Invocation)RMI技术可以使一个JVM中的对象,调用另一个JVM中的对象方法并获取调用结果。这里的另一个JVM可以在同一台计算机也可以是远程计算机。

  • 优点:java原生支持

  • 缺点:客户端服务端均需要编写大量代码,客户端作为rmi服务提供者需要开启额外端口号

  • 客户端代码:

  • public interface HelloService extends Remote {
    
        int clientStatus()throws Exception;
    }
    
    public class HelloServiceImpl extends UnicastRemoteObject implements HelloService {
    
        protected HelloServiceImpl() throws RemoteException {
        }
    
        @Override
        public int clientStatus() throws RemoteException {
            return 1;
        }
    }
    
    public class RmiProvider {
    
        public static void main(String[] args) throws Exception {
            HelloService helloService = new HelloServiceImpl();
            LocateRegistry.createRegistry(1111);
            Naming.bind("rmi://localhost:1111/rmi",helloService);
            System.out.println("start rmi provider");
        }
    }
    
  • 服务端代码:

  • public class RmiConsumer {
    
        public static void main(String[] args) throws Exception{
            //不断轮询客户端接口,即可知道客户端在线状态
            HelloService helloService = (HelloService) Naming.lookup("rmi://localhost:1111/rmi");
            System.out.println(helloService.clientStatus());
        }
    }