IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Java Discussion :

Une seule instance d'un même programme java [FAQ]


Sujet :

Java

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 17
    Points : 18
    Points
    18
    Par défaut Une seule instance d'un même programme java
    Je voudrais savoir si il est possible d'empêcher l'utilisateur de lancer plusieurs fois le même .jar.
    En bref il lance une première fois le programme, si il le lance une deuxième fois alors que celui ci tourne encore, le programme ne se lance pas de nouveau.

    Merci d'avance

  2. #2
    Membre éclairé

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2002
    Messages
    346
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Juillet 2002
    Messages : 346
    Points : 737
    Points
    737
    Par défaut
    Une solution classique est de mettre un conteur static au niveau de ta classe principal et d'incrémenter ce compteur. Etant static, il est partagé par toutes les instances de la classe. Tu peut donc savoir combien de fois ta classe est lancée

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class principal
    {
    private static cpt = 0;
     
    public static void main (String [] arg)
    {
      cpt++;
      if(cpt > 1)
      {
         System.exit(0);
      }
    }

  3. #3
    Membre chevronné
    Avatar de Deadpool
    Homme Profil pro
    Inscrit en
    Novembre 2005
    Messages
    1 312
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2005
    Messages : 1 312
    Points : 2 011
    Points
    2 011
    Par défaut
    Citation Envoyé par woodwai
    Une solution classique est de mettre un conteur static au niveau de ta classe principal et d'incrémenter ce compteur. Etant static, il est partagé par toutes les instances de la classe. Tu peut donc savoir combien de fois ta classe est lancée

    public class principal
    {
    private static cpt = 0;

    public static void main (String [] arg)
    {
    cpt++;
    if(cpt > 1)
    {
    System.exit(0);
    }
    }
    Désolé mais pour ce cas cette solution ne peut pas marcher.
    Chaque jar est lancé par une instance de JVM différente. Or chaque instance de JVM est indépendante et donc ne peut pas avoir accès aux classes instanciées au sein d'autres instances de JVM.
    Bobo59, pour une solution possible pour ton problème, va voir la FAQ.

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 17
    Points : 18
    Points
    18
    Par défaut
    Merci pour ta reponse, pour une fois où je n'ai pas été voir la FAQ...
    ...promis je ne recommencerai pas

  5. #5
    Membre éclairé

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2002
    Messages
    346
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Juillet 2002
    Messages : 346
    Points : 737
    Points
    737
    Par défaut
    Normalement Descent, si on utilise le même JAR on est dans la mêm JVM et donc celà marche (je croit bien que c'est le cas de Bobo59).
    J'ai déjà mis en place ce type de sécurité pour une appli swing que je ne voulait pas que l'on puisse lancer deux fois du même PC.

    Dans le cas de deux JVM différentes, il y a aussi l'utilisation d'un fichier (comme ce que font beaucoup de programmes) :
    - tu écrit dans un répertoire de ton appli - ou un répertoire temporaire - un fichier par expemple .pid que tu supprimera au destroy de ton application.
    - au démarrage, avant d'écrire ton fichier, tu vérifie sa présence, si il est là tu arrête car celà veut dire que l'application s'est lancée deux fois.

    Le problème de ce système est que si le destroy de l'application se passe mal, le fichier reste et l'application refusera de se relancer (j'ai déjà eu le cas avec postgresSQL qui utilise/utilisait ce type de sécurité).
    Mais au moins ça évite d'ouvrire une socket pour rien!

  6. #6
    Membre éclairé

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2002
    Messages
    346
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Juillet 2002
    Messages : 346
    Points : 737
    Points
    737
    Par défaut
    Citation Envoyé par Descent
    Chaque jar est lancé par une instance de JVM différente.
    Je ne suis pas du tout d'accord avec toi, en effet, dans une même application, tout les JAR sont lancé par la même JVM (sinon ils ne pourraient pas accéder les uns aux autres).

    Par contre, différentes application utilisent différentes JVM/instances de JVM, ce qui n'est pas du tout la même chose.

  7. #7
    Membre chevronné
    Avatar de Deadpool
    Homme Profil pro
    Inscrit en
    Novembre 2005
    Messages
    1 312
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2005
    Messages : 1 312
    Points : 2 011
    Points
    2 011
    Par défaut
    Le cas de Bobo59 c'est qu'il veut empêcher plusieurs lancements d'un même jar.

    Fais le test. Lance un jar deux fois de suite et controle les processus lancés dans le gestionnaire de tâches.

    Tu y verra deux processus javaw preuve qu'il y a bien 2 instances différentes de la JVM qui sont lancés.

    Sinon, c'est vrai que la solution de la FAQ n'est peut être pas la plus immédiate et que la solution du fichier temporaire peut être une alternative.

    D'ailleurs, je trouve que ce serait pas mal de rajouter la solution du fichier temporaire dans la FAQ

  8. #8
    Membre chevronné
    Avatar de Deadpool
    Homme Profil pro
    Inscrit en
    Novembre 2005
    Messages
    1 312
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2005
    Messages : 1 312
    Points : 2 011
    Points
    2 011
    Par défaut
    Citation Envoyé par woodwai
    Je ne suis pas du tout d'accord avec toi, en effet, dans une même application, tout les JAR sont lancé par la même JVM (sinon ils ne pourraient pas accéder les uns aux autres).

    Par contre, différentes application utilisent différentes JVM/instances de JVM, ce qui n'est pas du tout la même chose.
    Je me suis mal exprimé sur ce coup là.

    Je parlais des jars exécutables.

  9. #9
    Membre habitué
    Inscrit en
    Avril 2003
    Messages
    141
    Détails du profil
    Informations forums :
    Inscription : Avril 2003
    Messages : 141
    Points : 128
    Points
    128
    Par défaut
    La solution du fichier temporaire est pour moi a proscrire car si l'appli plante tu es obligé de détruire le fichier a la main pour pouvoir relancer ton application...
    Avec les sockets c'est bien plus propre !

  10. #10
    Membre éclairé

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2002
    Messages
    346
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Consultant informatique

    Informations forums :
    Inscription : Juillet 2002
    Messages : 346
    Points : 737
    Points
    737
    Par défaut
    Effectivement, c'est ce que j'avais précisé. Je pense que chaque solution a ses avantages et ses inconvénient. Je ne connaissait pas celle du socket qui est sympa - mais qui ouvre une socket réseaux pour rien et ça je n'aime pas trop ... mais bon, rien n'est parfait.

    Bobo59, si tu nous écoute encore, ce serait sympa de nous donner celle que tu as choisie ... juste pour info.

  11. #11
    Rédacteur
    Avatar de Giovanny Temgoua
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2003
    Messages
    3 830
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2003
    Messages : 3 830
    Points : 4 006
    Points
    4 006
    Par défaut
    Citation Envoyé par woodwai
    Bobo59, si tu nous écoute encore, ce serait sympa de nous donner celle que tu as choisie ... juste pour info.
    +1

    Je suis également interessé par une autre solution si elle existe.

  12. #12
    Membre expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Points : 3 080
    Points
    3 080
    Par défaut
    Personellement, j'ai choisi une solution basé sur une socket...
    En gros l'appli lance une serversocket lors du démarrage, et écoute sur un port défini...
    Lorsqu'une nouvelle instance de l'appli se lance, elle essaye de lancer une serversocket, qui échoue car le port est déjà utilisé... Elle se connecte donc en client pour demander au "server" (l'appli déjà lancée) de passer au premier plan

  13. #13
    Membre éclairé Avatar de Pollux
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    706
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : Suisse

    Informations forums :
    Inscription : Avril 2005
    Messages : 706
    Points : 680
    Points
    680
    Par défaut
    Citation Envoyé par ®om
    Personellement, j'ai choisi une solution basé sur une socket...
    En gros l'appli lance une serversocket lors du démarrage, et écoute sur un port défini...
    Lorsqu'une nouvelle instance de l'appli se lance, elle essaye de lancer une serversocket, qui échoue car le port est déjà utilisé... Elle se connecte donc en client pour demander au "server" (l'appli déjà lancée) de passer au premier plan
    Ingénieux!

  14. #14
    Membre expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Points : 3 080
    Points
    3 080
    Par défaut
    Et voici le code qui permet de le faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    package org.myfreetv.view;
     
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.Scanner;
    import java.util.logging.Logger;
     
    import javax.swing.SwingUtilities;
     
    /**
     * Cette classe permet d'assurer l'unicité de l'instance de MyFreeTV. Deux applications MyFreeTV ne peuvent pas être
     * lancées simultanéement.
     * 
     * @author rom1v
     */
    final class UniqueInstanceTester {
     
        /** Pour utilisé pour l'unique instance de MyFreeTV. */
        private static final int PORT = 27321;
     
        /** Interdiction d'instancier. */
        private UniqueInstanceTester() {}
     
        /**
         * Donne le focus à l'éventuelle application MyFreeTV déjà lancée.
         * 
         * @return {@code true} si aucune autre instance de MyFreeTV n'existe.
         */
        public static boolean launch() {
     
            /* Indique si l'instance de MyFreeTV est unique. */
            boolean unique;
     
            try {
                /* On crée une socket sur le port défini. */
                final ServerSocket server = new ServerSocket(PORT);
     
                /* Si la création de la socket réussi, c'est que l'instance de MyFreeTV est unique, aucune autre n'existe. */
                unique = true;
     
                /* On lance un Thread d'écoute sur ce port. */
                Thread portListenerThread = new Thread() {
     
                    @Override public void run() {
                        /* Tant que l'application MyFreeTV est lancée... */
                        while(true) {
                            try {
                                /* On attend qu'une socket se connecte sur le serveur. */
                                final Socket socket = server.accept();
     
                                /* Si une socket est connectée, on écoute le message envoyé dans un nouveau Thrad. */
                                new Thread() {
     
                                    @Override public void run() {
                                        receive(socket);
                                    }
                                }.start();
                            } catch(IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                };
     
                /* Le Thread d'écoute de port est démon. */
                portListenerThread.setDaemon(true);
     
                /* On démarre le Thread. */
                portListenerThread.start();
            } catch(IOException e) {
                /* Si la création de la socket échoue, c'est que l'instance de MyFreeTV n'est unique, une autre n'existe. */
                unique = false;
     
                /* Dans ce cas, on envoie un message à l'autre application pour lui demander d'avoir le focus. */
                send();
            }
            return unique;
        }
     
        /**
         * Envoie un message à l'instance de l'application déjà ouverte.
         */
        private static void send() {
            PrintWriter pw = null;
            try {
                /* On se connecte sur l'ip locale. */
                Socket socket = new Socket("localhost", PORT);
     
                /* On définit un PrintWriter pour écrire sur la sortie de la socket. */
                pw = new PrintWriter(socket.getOutputStream());
     
                /* On écrit "myfreetv" sur la socket. */
                pw.write("myfreetv");
            } catch(IOException e) {
                Logger.getLogger("MyFreeTV").warning("Écriture sur flux de sortie de la socket échoué.");
            } finally {
                if(pw != null)
                    pw.close();
            }
        }
     
        /**
         * Reçoit un message d'une socket s'étant connectée au serveur d'écoute. Si ce message est "{@code myfreetv}",
         * l'application demande le focus.
         * 
         * @param socket
         *            Socket connecté au serveur d'écoute.
         */
        private static void receive(Socket socket) {
            Scanner sc = null;
     
            try {
                /* On n'écoute que 5 secondes, si aucun message n'est reçu, tant pis... */
                socket.setSoTimeout(5000);
     
                /* On définit un Scanner pour lire sur l'entrée de la socket. */
                sc = new Scanner(socket.getInputStream());
     
                /* On ne lit qu'une ligne. */
                String s = sc.nextLine();
     
                /* Si cette ligne est "myfreetv"... */
                if("myfreetv".equals(s)) {
     
                    /* On demande le focus dans l'EDT. */
                    SwingUtilities.invokeLater(new Runnable() {
     
                        public void run() {
                            /* On récupère la fenêtre principale de l'application. */
                            MainFrame mainFrame = MyFreeTV.getMyFreeTV().getMainFrame();
     
                            /*
                             * La fenêtre peut ne pas être encore ouverte (très peu probable), par exemple au tout début du
                             * démarrage de l'application.
                             */
                            if(mainFrame != null) {
                                /* Si elle n'est pas visible (uniquement dans le systray par exemple), on la rend visible. */
                                if(!mainFrame.isVisible())
                                    mainFrame.setVisible(true);
                                /* On demande à la mettre au premier plan. */
                                mainFrame.toFront();
                            }
                        }
                    });
                }
            } catch(IOException e) {
                Logger.getLogger("MyFreeTV").warning("Lecture du flux d'entrée de la socket échoué.");
            } finally {
                if(sc != null)
                    sc.close();
            }
        }
     
    }
    Pour plus de facilité de lecture: UniqueInstanceTester

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Ne démarrer qu'une seule instance du programme
    Par gilweb dans le forum VB.NET
    Réponses: 9
    Dernier message: 17/04/2014, 10h19
  2. Une seule instance partagée avec plusieurs programmes
    Par CZVF_RS dans le forum Langages
    Réponses: 4
    Dernier message: 29/05/2013, 22h53
  3. Une seule instance du programme Win 2003 Serveur
    Par Erakis dans le forum Windows Forms
    Réponses: 5
    Dernier message: 20/11/2007, 14h57
  4. [FAQ] une seule instance de mon programme
    Par kacedda dans le forum C#
    Réponses: 6
    Dernier message: 01/02/2007, 13h37

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo