D) Java-Anwendung nur einmal ausführen

Wenn Sie eine Applikation programmiert haben und diese produktiv einsetzten möchten, ist es oftmals nötig (aus welchen Gründen auch immer), dass dieses Programm nur ein einziges mal ausgeführt wird. Wenn in Java ein Programm allerdings zwei mal ausgeführt wird, starten beide Programme in einer unterschiedlichen Virtual Machine, weshalb mit gewöhnlichen Methoden nicht festgestellt werden kann, ob die Anwendung bereits läuft oder nicht. Dieses Kapitel beschreibt Ihnen einige Lösungsansätze für dieses Problem. Unter Umständen werden Sie die Lösungsverfahren (Firewall-Einstellungen, beschränkte Schreibrechte, …) im praktischen Einsatz aber noch auf Ihre individuellen Bedürfnisse anpassen müssen.

Eine Lock-Datei

Eine Möglichkeit wäre es, dass Ihr Programm beim Starten in einem Verzeichnis eine Datei anlegt. Beim Beenden des Programms wird diese Datei dann wieder gelöscht (siehe Code beim Beenden ausführen). Wird jetzt das Programm ein weiteres Mal gestartet, erkennt es (anhand der bereits vorhandenen Lock-Datei), dass das Programm bereits ausgeführt wird und kann darauf reagieren, indem sich die zweite Instanz selbst beendet.

package de.jbb.startonce;

import java.io.File;
import java.io.IOException;

public class FileLock {

  public static void main(String[] args) throws IOException {
    
    final File f = new File(System.getProperty("java.io.tmpdir") + "/FileLock.lock");
    if (f.exists()) {
      System.out.println("Wird schon ausgeführt ... Bye Bye");
      System.exit(0);
    }
    f.createNewFile();
    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
      public void run() {
        f.delete();
      }
    }));
    System.out.println("Erster!");
    try {
      Thread.sleep(10000);
    }
    catch (InterruptedException ie) {}
    System.out.println("Beendet");
  }
}

Um diese Methode zu testen, führen Sie das Programm einfach zweimal kurz hintereinander aus.

Die Vorteile liegen auf der Hand: Diese Methode ist sehr einfach zu implementieren und sollte auch fast überall (unabhängig von Randbedingungen wie z. B. Firewall-Einstellungen) laufen. Dafür fallen die Nachteile aber umso gravierender aus. Sollte Ihr Programm die Datei beim Beenden nicht mehr löschen können (Absturz der VM, Absturz des Betriebssystems, Stromausfall, …) kann Ihre Anwendung nicht mehr gestartet werden, bis die Lock-Datei manuell entfernt wurde. Auch ist keine Kommunikation zwischen den gestarteten Applikationen möglich.

Von dieser Methode ist also abzuraten.

Einen Port sperren

Eine weitere Möglichkeit wäre es einen Port über einen ServerSocket zu sperren. Versucht eine weitere Anwendung den Port für sich zu beanspruchen, wird eine Exception geworfen und die zweite Applikation weiß, dass das Programm bereits gestartet wurde. Dies hat den Vorteil gegenüber der vorhergehenden Methode, dass auch bei einem Absturz der Port wieder freigegeben wird. Die Anwendung kann also nicht versehentlich „für immer“ gesperrt werden. Eine mögliche Implementierung sieht so aus:

package de.jbb.startonce;

import java.io.IOException;
import java.net.ServerSocket;

public class SocketLock {

  public static void main(String[] args) {
    
    try {
      new ServerSocket(7238);
    } 
    catch (IOException e) {
      System.out.println("Programm läuft schon");
      System.exit(0);
    }
    System.out.println("Ich bin der Erste!");
    try {
      Thread.sleep(10000);
    }
    catch (InterruptedException ie) {}
    System.out.println("Und tschüss!");
  }
}

Zum Testen sollten Sie auch hier das Programm öfter kurz hintereinander ausführen.

Der Vorteil dieser Methode liegt (wie bereits erwähnt) ganz klar darin, dass es nicht passieren kann, dass sich Ihre Anwendung wegen eines Fehlers nur noch durch manuelles Eingreifen des Users starten lässt. Allerdings bleibt das Problem, dass die beiden Anwendungen auch hier nicht miteinander kommunizieren können – noch nicht! Viel schwerwiegender ist aber, dass sich zwei neue Probleme auftun. Was ist, wenn die lokale Firewall diesen Vorgang unterbindet oder zumindest (durch Warten auf eine User-Interaktion) stark verlangsamt? Oder eine andere Anwendung diesen Port bereits belegt?

Diese Methode ist also auch nicht optimal, meiner Meinung nach aber empfehlenswerter als unsere erste Idee.

Kommunikation zwischen beiden Anwendungen

Erweitern wir unsere Klasse SocketLock noch dahingehend, dass wir nicht einfach nur einen ServerSocket erstellen, sondern diesen auch an dessen Port lauschen, und falls der Port schon besetzt ist, eine Verbindung zu diesem Port aufbauen lassen. Damit ermöglichen wir einen Informationsaustausch zwischen den beiden Programmen. Dies ist z. B. dann nützlich, wenn der zweite Aufruf des Programms andere Parameter enthält als es der Erste tat, und das laufende Programm diese Parameter verarbeiten soll.

package de.jbb.startonce;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

public class SocketLock {

  public static void main(String[] args) {
    
    try {
      final ServerSocket ss = new ServerSocket(7238);
      new Thread(new Runnable() {
        public void run() {
          while (true) {
            try {
              Socket s = ss.accept();
              BufferedReader buffy = new BufferedReader(new InputStreamReader(s.getInputStream()));
              System.out.println("Zweite Anwendung sagt: " + buffy.readLine());
              buffy.close();
              s.close();
            } 
            catch (IOException e) {
              System.out.println("Verbindung beendet");
            }
          }
        }
      }).start();
    } 
    catch (IOException e) {
      try {
        Socket s = new Socket("localhost", 7238);
        s.getOutputStream().write("Oha, da bin ich wohl zu spät. Sorry!\n".getBytes());
        s.close();
      } 
      catch (UnknownHostException e1) {
        e1.printStackTrace();
      } 
      catch (IOException e1) {
        e1.printStackTrace();
      }
      System.exit(0);
    }
  }
}

Beachten Sie, dass sich das zuerst gestartete Programm nun nicht mehr selbst nach 10 Sekunden beendet, sondern manuell durch Sie abgebrochen werden muss (schließen der Konsole).

Dieses Methode löst zwar das Problem, dass die Anwendungen nicht miteinander kommunizieren können, unsere anderen Nachteile werden aber noch nicht beachtet. Zudem erhöht sich die Komplexität dieser Variante merklich.

Die Kombination macht’s

Beim Betrachten der Probleme der FileLock, und der SocketLock-Klasse fällt auf, dass beide Varianten andere Probleme haben. Daraus lässt sich schließen, dass beide Verfahren irgendwie miteinander verknüpft werden sollten, um eine optimale Lösung zu erzielen.

Nehmen wir die Klasse SocketLock als Basis. Um sicherzustellen, dass keine andere Applikation den gewählten Port verwendet, sollte der Port dynamisch ausgewählt werden. Z. B. so:

private int getFreeServerSocket() {

  for (int i = 2000; i < 10000; i++) {
    try {
      new ServerSocket(i);
      return i;
    }
    catch (IOException ignore) {}
  }
  return -1;
}

Natürlich stellt sich nun die Frage, wie dann andere Instanzen unserer Applikation den richtigen Port finden. Der Port muss also irgendwo hinterlegt werden. Hierzu bietet sich unsere Methode aus der Klasse FileLock an. Wir erstellen in einem beliebigen Verzeichnis eine neue Datei. Diese Datei enthält den gewählten Port. Das hat folgende Vorteile:

  • Ist die Datei nicht vorhanden, läuft die Applikation auf keinen Fall schon einmal.
  • Ist einmal ein Port gefunden, muss er meistens nicht jedes Mal neu gewählt werden.
  • Da der Lock nicht über die Datei, sondern über den Port geschieht, muss (bzw. soll) die Datei mit dem Port beim Beenden des Programms nicht gelöscht werden.
  • Kommunikation zwischen den einzelnen Instanzen ist über den gewählten Port möglich.
  • Kann keine Verbindung zum Port in der Datei aufgebaut werden, wurde die Anwendung noch nicht gestartet.

Doch was passiert, wenn eine andere Anwendung eine Verbindung zu dem Port aufbaut, an dem Ihre Anwendung bereits lauscht? Oder eine Anwendung sich „Ihren“ Port geschnappt hat und jetzt an selbigen horcht? In diesem Fall können die von Ihnen vorgeschriebenen Kommunikationsregeln (z. B. ein Austausch ausschließlich über Strings) gebrochen, und Ihr Programm im schlimmsten Fall zum Absturz gebracht werden. Deshalb sollten Sie bei jeder neuen Verbindung zu Ihrer laufenden Applikation eine Verifizierung durchführen. Dies dient auch zur Sicherstellung, dass es sich auch wirklich um Ihr Programm handelt, welches an diesem Port gebunden ist.

Eine solche Verifizierung kann bspw. über eine eigene Klasse, die einen eindeutigen Namen für Ihr Programm enthält, realisiert werden.

package de.jbb.sic;

import java.io.Serializable;

public class ClassCheck implements Serializable {

  private static final long serialVersionUID = 1L;

  private String className = null;

  public ClassCheck(String className) {
    setClassName(className);
  }

  public ClassCheck() {}

  public String toString() {
    return this.className;
  }

  public String getClassName() {
    return this.className;
  }

  public void setClassName(String className) {
    this.className = className;
  }
}

Diese Klasse sollte dann über einen ObjektOutputStream an die bereits laufende Applikation gesendet, über einen ObjektInputStream von der laufenden Anwendung gelesen, und entsprechend verarbeitet werden.

Ein standardisiertes Verfahren

Auf diesem Wissen lässt sich nun eine kleine Bibliothek aufbauen, die dieses Verfahren standardisiert und sich somit immer wieder in Ihre Anwendungen integrieren lässt. Hierzu benötigen Sie drei Komponenten:

  • Eine Klasse zu Verifizierung.
  • Ein Interface als Schnittstelle für Ihre Programme.
  • Eine Klasse, die die Logik implementiert.

Die Klasse zur Verifizierung kennen Sie bereits aus dem letzten Abschnitt – ClassCheck. Sehen wir uns als nächstes das Interface an. Es stellt drei Methoden bereit. Eine wird aufgerufen, falls das Programm noch mal gestartet wurde. Eine, falls sich ein anderes Programm zu diesem Port verbunden hat. Und eine letzte, falls eine andere Instanz Ihrer Applikation eine Nachricht an die bereits laufende Applikation geschickt hat.

package de.jbb.sic;

public interface ApplicationStartedListener {

  /**
   * Wird aufgerufen, wenn eine identische Anwendung gestartet wird, und sich auf den
   * Server connecten will.
   */
  void applicationStarted();
  
  /**
   * Wird aufgerufen, wenn eine andere Anwendung gestartet wurde, die sich dennoch
   * auf den selben Port verbinden wollte, auf welchem auch der Server laeuft.
   * 
   * @param name Name der Anwendung
   */
  void foreignApplicationStarted(String name);

  /**
   * Wird aufgerufen, wenn eine später gestartete, identische Anwendung eine Nachricht
   * schickt.
   * 
   * @param obj die Nachricht als Object
   */
  void messageArrived(Object obj);
}

Auf der nächsten Seite finden Sie die Implementierung der Logik.

30 Replies to “D) Java-Anwendung nur einmal ausführen”

  1. Illuvatar

    Eine kleine Anmerkung zur FileLock-Methode: Seit Java NIO gibt es die Möglichkeit, „echte“ File-Locks zu realisieren. Hierzu wird die Methode FileChannel#tryLock verwendet.

    Dadurch fallen ein Großteil der Nachteile weg. Eine Kommunikation ist allerdings immer noch nicht möglich. Solch ein FileLock wird aber eben automatisch aufgehoben sobald das Programm nicht mehr läuft. Das wichtige Kriterium wäre nicht mehr, ob die Datei existiert, sondern ob tryLock ein FileLock oder null zurückgibt. Ob die Datei noch existiert, kann dafür als Kriterium verwendet werden, ob das Programm sauber beendet wurde.

  2. Stefan Kiesel

    Hallo Illuvatar,

    vielen Dank für deinen Beitrag. Ich habe die tryLock Methode der Klasse FileChannel nicht angesprochen, da das Verhalten von FileLock sehr systemspezifisch ist, und eine Kommunikation zwischen den beiden Applikationen nicht mehr möglich wird.

    Bei Gelegenheit werde ich dieses Verfahren als kleinen Zusatz aber ergänzen.

    Gruß
    Stefan

  3. Stefan

    SingleInstanceController.this.client.getInetAddress().getCanonicalHostName()
    liefert bei mir „127.0.0.1“ statt „localhost“. Damit akzeptiert der Server den Client nicht und die Sache geht schief.

    Scheint eine Eigenheit von MS-Vista zu sein? Hab‘ verschiedene JDKs probiert.

  4. Stefan Kiesel

    Hi Stefan,

    ein solches Problem ist mir nicht bekannt. Ich habe den Quellcode aber einmal ausgebessert. Anstatt von getCanonicalHostName().equals("localhost") wird jetzt einfach isLoopbackAddress() geschrieben.

    Über eine Rückmeldung, ob es jetzt funktioniert oder nicht, würde ich mich freuen.

    Gruß
    Stefan

  5. Stefan Kiesel

    Hallo Stefan,

    ich kann leider gerade nicht nachvollziehen, wovon Sie reden. Das System.exit(0); in der Example Klasse kann auch ohne Probleme weggelassen werden.

    Grüße
    Stefan

  6. Stefan

    Nicht in der Klasse sondern im main() muss ich
    exit-en sonst hängt das Programm.

    public static void main(String[] args) {
    new Example();
    System.exit();
    }

    Passiert auf Ubuntu Java Version 1.6.0_14
    Ich denke der exit bricht den Thread ab. Sonst wartet die JVM bis sich der Thread selbst beendet (was er nicht tut).

  7. Stefan Kiesel

    Kann ich leider nicht nachvollziehen, hab auch leider keine installierte Ubuntu-Version. Nur damit es zu keinen Missverständnissen kommt: Das zuerst gestartete Programm soll bis zu einem manuellen Abbruch durchlaufen. Alle weiteren Instanzen beenden sich sofort nach dem Start und dem Austausch der Nachrichten selbst.

    Grüße
    Stefan

  8. Klaus Brokmann

    Hallo,
    ich benutze auch die Logik mittels ServerSocket, wie zu Beginn unter „Einen Port sperren“ beschrieben!
    Seltsamerweise wird die Exception (bei mir ist es übrigens keine IOException, sondern eine BindException – ich fange aber alle ab) nicht auf allen Rechner in der Firma geworfen (auf ca. 10% nicht).
    Hat jemand eine Idee, woher das kommen kann ???
    Danke und Gruß
    Klaus

  9. Stefan Kiesel

    Hallo Herr Brokmann,

    vermutlich läuft unter dem gewählten Port auf bestimmten Rechnern in der Firma bereits eine andere Anwendung. Entweder müssen Sie diese Anwendung(en) identifizieren und beenden, oder – was die vermutlich leichtere Lösung ist – einen anderen Port wählen.

    Gruß
    Stefan

  10. Klaus Brokmann

    Guten Morgen Herr Kiesel,
    Danke für die schnelle Antwort!
    Ich bemerke gerade, dass ich mich vlt. etwas unglücklich ausgedrückt habe …
    Auch ich möchte mittels des Code prüfen, ob bereits eine Instanz der betroffenen Applikation läuft. Dazu lege ich genau so wie oben beschrieben, zu Beginn eine neue Socketvariable an und fange dann ggf. die Exception ab, um dabei dann ggf. die Applikation zu beenden!
    Dies klappt wie gesagt auf den meisten PCs sehr gut, nur auf einigen wird die Exception leider nicht geworfen, und dann wird die Anwendung ein zweites Mal gestartet!

    Hier mal der relevante Code, den ich eigentlich für fehlerfrei halte :

    static ServerSocket listenerSocket = null;
    // ...
    try 
    {
        listenerSocket = new ServerSocket( nMutexServerport );
    }
    catch( Exception ex ) 
    {
        ex.printStackTrace( );
        JOptionPane.showMessageDialog( this,
                                        "Es ist bereits ein Worker auf diesem System aktiv.\n" +
                                        "Sollte dies nicht der Fall sein, bitte den Rechner neu starten !",
                                        "Fehler", JOptionPane.ERROR_MESSAGE, null );
        System.exit( -2 );
    }

    Freundliche Grüße
    Klaus Brokmann

  11. Stefan Kiesel

    Ihr Code ist soweit fehlerfrei. Sind Sie sicher, dass beide Applikationen zu der Zeile „listenerSocket = new ServerSocket(nMutexServerport);“ gelangen und nicht vorher abgebrochen werden oder einen anderen Weg (if-Abfrage) wählen können? Können Sie sicherstellen, dass nMutexServerport für beide Anwendungen exakt identisch ist? Können Sie sicherstellen, dass beide Anwendungen noch laufen?

    Ansonsten versuchen Sie es doch mal primitiv mit einer einfachen Main-Klasse, die Sie zweimal hintereinander ausführen:

    public class Main {
    
      public static void main(String[] args) throws Exception {
        new ServerSocket(5892).accept();
      }
    }

    Wenn ich mich nicht vertippt habe (gerade alles aus dem Kopf und ohne Compiler und IDE) sollte dann beim zweiten Ausführen eine Fehlermeldung erscheinen. Passiert das bei Ihnen (wovon ich einmal stark ausgehe), dann ist der Fehler nicht in dem von Ihnen geposteten Codeausschnitt zu suchen.

    Grüße
    Stefan

  12. Klaus Brokmann

    Guten Morgen,
    ja, alle Aufrufe erreichen zwangsläufig die Stelle (ist zentral zu Beginn der main-Funktion); das habe ich auch im Debugger überprüft.

    Der Port ist ebenfalls zentral so deklariert:
    // Mutexserverport zur Instanzenkontrolle
    public static final int nMutexServerport = 62987;

    Der Aufruf mit „.accept()“ klappt hier nicht, da dieser genannte Port vermutlich nicht in der Firewall resp. im Proxy freigegeben ist (die Anwendung wartet dann ‚ewig‘ auf . Ich möchte ja auch nicht damit arbeiten, sondern ihn nur zu Instanzenkontrolle nutzen

    Mir fiel eben noch auf, dass mit dem von Ihnen oben beschriebene Aufruf
    new ServerSocket(nMutexServerport );
    KEINE Exception bei mir auslöst !

    Nur für den Fall
    listenerSocket = new ServerSocket( nMutexServerport );
    tritt (beim zweiten Aufruf) die Bind-Exception auf und das „listenerSocket“-Objekt ist dann null.

    Ist schon alles sehr seltsam … 🙁

    Freundliche Grüße
    Klaus

  13. Stefan Kiesel

    Hallo Herr Brokmann,

    das accept() ist schon so beabsichtigt. So wartet Ihr Programm, bis sich jemand zu diesem ServerSocket verbindet. Da dies nicht geschehen wird, wartet das Programm ewig (bzw. bis Sie es abbrechen). Hierdurch wird wiederum gewährleistet, dass das erste Programm (die erste Ausführung) noch läuft und auch noch den ServerSocket gebunden hat, wenn Sie das Programm ein zweites Mal ausführen, so dass es zu einem Fehler kommt.

    Bitte versuchen Sie es noch einmal auf die von mir beschriebene Art und Weise.

    Grüße
    Stefan Kiesel

  14. Klaus Brokmann

    Hallo Herr Kiesel,
    damit wartet dann aber auch die erste Anwendung ewig – und ich komme dort nicht mal bis zum Anmeldedialog, geschweige denn, dass ich arbeiten kann !!
    Ich möchte ja nur beim zweiten Aufruf die Exception bekommen, um den zweiten Aufruf zu canceln !
    Freundliche Grüße
    Klaus Brokmann

  15. Stefan Kiesel

    Natürlich wartet so die erste Anwendung ewig. Sie sollen das ja auch nicht in Ihre Anwendung einbauen, sondern nur so wie es ist (ohne auch nur eine Zeile Code zu verändern) ausführen und testen 😉 . Dieses kleine Programm soll Ihnen lediglich beweisen, dass der Fehler nicht an dem von Ihnen geposteten Codeschnipsel liegt. Und diesen Beweis bringt es, wenn Sie das Programm genau in dieser Form kompilieren, zweimal ausführen und beim zweiten Mal ausführen eine Exception geworfen wird.

    Um auf mögliche Fehlerursachen Ihres eigentlichen Problems zurück zu kommen:

    Genaues kann man natürlich nur sagen, wenn man einen aussagekräftigeren Teil Ihres Codes zu Gesicht bekommt, da der Fehler (wie gesagt) in Ihrem uns zur Verfügung gestellten Teil garantiert nicht liegt. Natürlich versteh ich auch, wenn Sie nicht einfach Code Ihrer Firma hier veröffentlichen können. Deshalb ein paar allgemeine Tipps:

    1.) Könnte evtl. irgendwo eine unabgefangene Exception geworfen werden, die das schließen des Sockets bewirkt?
    2.) Sie wissen wie der GarbageCollector in Java arbeitet? Wenn Ihr Objekt nirgends mehr referenziert wird und der GarbageCollector das feststellt, wird Ihr Objekt irgendwann aufgeräumt.
    3.) Aus Ihrem letzten Kommentar schließe ich, dass Sie eine GUI verwenden. Eine Swing-GUI läuft in Java in einem separierten Thread. Nach Abarbeitung Ihrer Main-Methode wird der Thread, in welchem die Main-Methode gestartet wurde, beendet. Es läuft folglich nur noch der GUI-Thread. Könnte evtl. hier im Bezug auf die Erzeugung des ServerSockets das Problem liegen?

    Nach Ihrer Aussage

    // Zitat
    new ServerSocket(nMutexServerport );
    KEINE Exception bei mir auslöst !

    Nur für den Fall
    listenerSocket = new ServerSocket( nMutexServerport );
    tritt (beim zweiten Aufruf) die Bind-Exception auf und das “listenerSocket”-Objekt ist dann null.
    // Zitat Ende

    sollten Sie insbesondere die Punkte 2 und 3 in Betracht ziehen.

    Grüße
    Stefan

  16. Klaus Brokmann

    Hallo Stefan,

    ah, die Punkte 2 und 3 habe ich so noch nicht ernsthafter in Betracht bezogen …
    Ok, ich werde mal versuchen, die Anwendung dahingehend zu testen! Referenziert wird die Variable sicherlich nirgendwo mehr – das könnte in der Tat vlt. ein Knackpunkt sein …

    Ich melde mich, sobald ich weitere Ergebnisse habe!
    Zuerst nochmals vielen Dank für die Unterstützung!
    Freundliche Grüße
    Klaus

  17. Maik Jäkel

    Hallo Herr Kiesel,

    gibt es einen speziellen Grund dafür, dass sie das FileLock per ShutDown-Hook-Thread löschen? Ich hätte spontan einfach die deleteOnExit()-Methode des Files verwendet. Gibt es hierbei einen Unterschied, den ich noch nicht kenne?

    Viele Grüße
    Maik Jäkel

  18. Stefan Kiesel

    Hallo Herr Jäkel,

    ja, den gibt es. Ich zitiere die API-Doc für deleteOnExit:

    „Deletion will be attempted only for normal termination of the virtual machine, as defined by the Java Language Specification.“ und „Note: this method should not be used for file-locking, as the resulting protocol cannot be made to work reliably“

    Ein Shutdown-Hook hingegen wird auch dann ausgeführt, wenn die VM auf abnormalem Wege terminiert.

    Grüße
    Stefan

  19. Richard Rüegg

    Guten Tag
    ist es Möglich, dass diese Klasse nur auf Windows basierten System funktioniert?
    Auf dem Win-PC funktioniert es wunderbar… (wurde auch auf diesem Programmiert)
    Auf dem lubuntu Notebook kommt es, wenn ich die Klasse einbinde, schon beim Aufruf derselben zu Problemen.

    Ich habe ein Loginfenster als Hauptformular und wenn ok sollte sich das Hauptmenü der Anwendung öffnen.
    Auf Windof klappt das ja, aber auf lubuntu nicht. Auf Win bringt er mir sogar die zuvor gestartete Anwendung in den Vordergrund, was ja super ist.

    Auf lubuntu kommt nach ok klicken nichts mehr, selbst wenn ich die Anwendung das ERSTE mal starte.
    Binde ich aber Die Klasse NICHT ein, läuft es wie es muss, nur ich kann die Anwendung beliebig oft starten.

    für Hilfe wäre ich sehr Dankbar, und sorry, wenn ich den alten Theard wieder ausgrabe.
    Mit freundlichen Grüssen
    Richi

  20. Richard Rüegg

    Sorry, ich korrigiere mich…

    Das Programm funktioniert auch auf lubuntu wie es sollte… nur ich kann dort die Anwendung trotzdem beliebig oft starten.

    Da ich blutiger Java-Anfänger bin, verstehe ich nicht wie ich die Ports in lubuntu anspreche.
    Vielleicht ein Tip?
    Vielen Dank
    Richi

  21. Stefan Kiesel

    Da Java plattformunabhängig ist, sollte man die Ports auch auf lubuntu genau so ansprechen können wie auf Windows. Ich habe leider keine Lubuntu-Version zum Testen. Aber überprüfen Sie doch einmal mit dem Debugger ob der Code korrekt ausgeführt wird bzw. nach dem ersten Start der Anwendung ob die Datei korrekt gelockt und der Port belegt wurde.

    Grüße
    Stefan

  22. Richard Rüegg

    Nochmals ich…
    Jetzt habe ich das Ganze über Export in ein *.jar, als ausführbare Anwendung gemacht.
    Nun habe ich auch auf dem Windows-System das Problem, dass nach dem Login-Formular NICHTS mehr kommt.
    Ich habe vesucht per Debug alles nach zu vollziehen. Ich komme nich dahinter, warum es nur in eclipse funktioniert, aber nicht als Ausführbare Datei. Weder auf Windows, noch auf Linux und schon gar nicht im MAC.

    Was mache ich falsch. Es muss doch möglich sein, die Anwendung nur eimanl zu starten. Obwohl ich MS-VB überhaupt nicht mag, aber dort kann ich sagen dass die Anwendung nur einmal auf dem gleichen PC gestartet werden darf. Aber ich möchte mich von MS verabschieden und dazu möchte ich meine Anwendungen, die ich bis anhin programmiert habe auf Java neu erstellen.

    Ich habe auch das Offline-Banking (CChanel) auf Java nachprogrammiert und es funktioniert sogar (up-, und down-load inkl.) nur wenn ich diese Anwendung ZWEIMAL starte, muss ich nachher die Bank anrufen, sie soll mein Online-Vertrag entsperren. DARUM bräuchte ich DRINGEND Hilfe, wie ich eine Anwendung NICHT zweimal starten kann.

    Sorry, ich bin vielleicht Mühsam… , aber ich bin seit Tagen am Pröbeln.
    Vielen Dank an den der mir helfen kann…

    Mit freundlichen Grüssen
    Richi

  23. Stefan Kiesel

    Führen Sie die .jar-Datei doch einmal über java -jar IhreDatei.jar in der Kommandozeile aus. Dann sollten Sie eine Fehlermeldung sehen, die Ihnen bei der weiteren Diagnose des Problems weiter hilft.

    Wenn Sie DRINGEND Hilfe benötigen, sollten Sie jemanden bezahlen, der sich Ihr Problem ansieht und Ihnen weiter hilft.

    Grüße
    Stefan

  24. Richard Rüegg

    Danke Herr Kiesel
    Der Tip mit der Konsole hat mir tatsächlich weitergeholfen.

    Habe schon einen Java-Spezialisten bezahlt…. CHF 2’500.00
    Doch der hatte KEINE Ahnung wie man eine EXE-Datei öffnet und sie in ein Java umschreibt….
    Geld ist weg… weiter war ich bis anhin noch nicht.

    Wie gesagt ich bin noch nicht in Linux daheim. Aber Ihr Tip hat geholfen. (Vor lauter Bäumen den Wald nicht mehr gesehen, Danke)
    Mit freundlichen Grüssen
    Richi

  25. Stefan Kiesel

    Freut mich, wenn ich Ihnen helfen konnte und tut mir Leid um Ihr Geld.

    Ich möchte den Kollegen, der keine Ahnung hat, wie man eine exe-Datei „öffnet“ und sie in Java umschreibt, aber an dieser Stelle in Schutz nehmen. Eine .exe liegt in einer Maschinensprache vor und kann so erst einmal nicht weiter verarbeitet werden. Um eine .exe in eine Java-Anwendung umzuschreiben, benötigt man den Quellcode der .exe-Datei, und den kann man nicht so einfach aus einer .exe-Datei extrahieren. Und selbst wenn der Quellcode vorliegt, kann man nicht einfach einen Knopf drücken und der Sourcecode wird in Java übersetzt. Zumindest wenn es sich um etwas komplexeren Code handelt ist hier in jedem Fall Handarbeit gefragt.

    Grüße
    Stefan

  26. Richard Rüegg

    Genau,
    den EXE Umwandler habe ich Ihm mitgeliefert… (OLLYDBG.EXE -> mit dem konnte ich [z.T im Binärcode] das gewünschte Programm öffnen, (meine Tochter ist Mathematikerin und hat mir den Binä-Code umgerechnet))

    Es gieng ja nur darum, dass die Anwendung auf *.jar NICHT zweimal geöffnet werden kann, da sonst Oben genannte Probleme auftreten. Und Ihr Tip hat geholfen. Wenn ich schon CHF 2.500.00 bezahle, hätte ich von dem Experten schon etwas mehr erwartet. Wenn Sie mir den Tip nicht gegeben hätten, hätten Sie auch noch ein Sümmchen verdienen können. Es gibt noch etliche Programme die ich Uschreiben muss.

    Aber wie gesagt, der Typ der sich Spezialist nennt, hätte auch darauf kommen dürfen, nachdem der den offennen Quellcode von mir präsentiert bekommen hatte.

    Aber Ihnen VIELEN Dank.
    Gruss Richi

  27. Stefan Kiesel

    Auch wenn das hier eigentlich Offtopic ist:
    – Ollydbg wandelt nicht wirklich Maschinencode in Sourcecode um
    – Binärcode „umrechnen“ und daraus dann Sourcecode gewinnen, hört sich nicht wirklich sinnvoll an
    – OK, dann verlange ich bei Ihrer nächsten Frage eine monetäre Gegenleistung 😉

    Weitere OT-Diskussionen bitte via Mail.

    Grüße
    Stefan

Schreibe einen Kommentar

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.