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 :

Plantage au bout d'un moment


Sujet :

Java

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 45
    Par défaut Plantage au bout d'un moment
    Bonjour,

    J'ai un problème dans le cadre d'une application qui sert de serveur de tchat.
    En gros il y a deux class principales RomuServer et AquaClientThread.

    RomuServer contient le main, un serverSocket, et un Vector de la liste des clients.
    Le serverSocket écoute et lorsqu'une connexion est acceptée, un nouveau AquaClientThread est créé et le stocke dans le :
    static Vector clientList= new Vector(); de la class RomuServer.

    Le problème est que le programme "plante", à certain un moment.
    C'est très aléatoire, il peut tenir 2 heures comme 2 jours avec 10 connectés ou 60.

    Donc j'ai essai de savoir d'où venait le problème en faisant des println partout à chaque début et fin de fonction et même plus.
    Et j'ai reussi à voir que le problème se créait dans cette fonction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
        static synchronized void sendToAllClients(String message) {
     
            AquaClientThread foo;
            Iterator client_it = clientList.iterator();
            try {
                while(client_it.hasNext()) {
                    foo = (AquaClientThread)client_it.next();
                    if (foo!=null) {
    	  	    // dernier println possible lorsque le problème survient
                        foo.send(message,"MESSAGE");
                    }
                }
            } catch(Exception ex) { echo("plantage sendToAllClients "+ex); }
        }
    Donc cette fonction est dans la class principale RomuServer, et parcoure le Vector pour envoyer à tous les clients un message.
    Elle fonctionne la plus part du temps correctement, mais parfois la class RomuServer "freeze", le programme continue de tourner et les threads font encore leur boulot.
    Quand cela arrive, plus rien ne se passe sur RomuServer, et la dernièr action qu'il arrive à faire est un println juste avant le food.send().
    La fonction send ne se lance pas d'ailleurs dans le thread concerné, quand le problème survient.

    Je rappelle que la plupart du temps que la fonction sendToAllClients fonctionne correctement, mais qu'au bout d'un certain temps, très aléatoire, et à un certain moment dans la boucle, un foo.send fait freezer RomuServer, et je suis obligé d'arrêter le programme et de le relancer.

    Merci de m'aider, ou de donner des pistes s'il vous plait.

  2. #2
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,


    Et à quoi correspond cette méthode send() ???

    a++

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 45
    Par défaut
    Comme son nom l'indique elle sert à envoyer un message :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    	public void send(String message, String appelle){
                    // n'apparait pas lors que RomuServer freeze
    		out.println(message+'\u0000');
    		out.flush();
    	}
    Si je fait un screenOut.println juste au début de la fonction, il n'apparait pas, quand le problème survient bien sûr. Ça ne vient pas de send.

  4. #4
    Modérateur
    Avatar de dinobogan
    Homme Profil pro
    ingénieur
    Inscrit en
    Juin 2007
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Activité : ingénieur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 4 073
    Par défaut
    Donne le code de la méthode qui appelle "sendToAllClients".
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java
    Que la force de la puissance soit avec le courage de ta sagesse.

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 45
    Par défaut
    sendToAllClients est appelé dans pas mal d'endroit :
    - Une fois dans une fonction de AquaClientThread qui interprète les messages reçu. Si c'est un message texte qu'il faut envoyer à tout le monde : RomuServer.sendToAllClients(Pseudo+" : "+Msg);
    - Puis à plusieurs endroit dans RomuServer pour certaine requête spécial.

    Edit : J'ai fait beaucoup de teste, et je ne pense pas que ça dépende de la fonction qui appel sendToAllClients, mais là je vais tester une version qui me permet de savoir qu'elle est la fonction qui a appelé sendToAllClients au moment ou ça plante. J'ai plus qu'à attendre que ça plante.

  6. #6
    Membre Expert
    Avatar de gifffftane
    Profil pro
    Inscrit en
    Février 2007
    Messages
    2 354
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Février 2007
    Messages : 2 354
    Par défaut
    Bon heu... freezer ça veut dire quoi ?

    Je subodore qu'il s'agiréssasse d'un blocage du programme qui ne ferait plus rien : pas de stack trace, pas de fin de programme, plus même de println - la galère -, rien.

    Je pense que cela vient de threads qui attendent un déblocage de synchronized qui ne vient jamais. Il faudrait que tu nous établisses une sorte de schéma de tes synchronized ; quelles sont les variables partagées, quelles sont les portions de code verrouillées, etc.

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 45
    Par défaut
    Désolé pour le temps de réponse, je pensais arriver à réussir à le debuger tout seul mais rien à faire, j'ai du tester plus de 50 versions différentes, et toujours le même problème.

    Citation Envoyé par gifffftane Voir le message
    Je subodore qu'il s'agiréssasse d'un blocage du programme qui ne ferait plus rien : pas de stack trace, pas de fin de programme, plus même de println - la galère -, rien.
    Ouais c'est à peu prés ça.

    Bon voila le Main :
    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
     
     
    import java.net.*;
    import java.io.*;
    import java.util.Vector;
    import java.util.Date;
    import java.util.Iterator;
     
    public class RomuServer {
     
        static Vector clientList= new Vector(); // La liste des Threads Client
        static PrintWriter screenOut = new PrintWriter(System.out, true);
        static ServerSocket serverSocket = null;
        static Date tempoXmlList = new Date();
     
        public static void main(String[] args) throws IOException {
     
            boolean listening = true;
            AquaClientThread tempClient;
     
            echo("Started on : "+new Date().toString());
     
                Integer  tempPort = new Integer(2001);
     
                try{
                    serverSocket = new ServerSocket(tempPort.intValue());
                }
                catch(IOException e){
                    echo("Could not listen on port: "+tempPort);
                    System.exit(-1);
                }
     
                echo("Server started and listening on port "+tempPort+"\n");
     
                try {
                    while (listening) {
                        Socket socket = serverSocket.accept();
                        try {
                            tempClient = new AquaClientThread(socket);
                        } 
                        catch (IOException e) {
                        	echo("CLIENT SOCKET PROBLEM : "+e.getMessage());
                            socket.close();
                        }
                    }
                }
                finally {
                	echo("ERREUR:01");
                    serverSocket.close();
                }
                echo("ERREUR:02");
                serverSocket.close();
        }
     
        static void echo(String message) {
                screenOut.println(new Date().toString()+":"+message);
        }
     
    // Appelé dans RomuServer.listClientsXml et par les AquaClientThread à la réception de message
        static synchronized void sendToAllClients(String message) { 
            AquaClientThread foo;
            Iterator client_it = clientList.iterator();
            try {
                while(client_it.hasNext()) {
                    foo = (AquaClientThread)client_it.next();
                    if (foo!=null) {
                        //"Freeze" Ici
                        foo.send(message);
                    }
                }
            } catch(Exception ex) { echo("plantage sendToAllClients"+ex); }
        }
     
    // Appelé par deleteClient et addClient seulement
    // Sert à envoyer sous forme XML la liste des joueur
        static void listClientsXml(){
     
        	StringBuffer sb = new StringBuffer();
        	int i=0;
            AquaClientThread foo;
            Iterator client_it = clientList.iterator();
            try {
                while(client_it.hasNext()) { 
                    foo = (AquaClientThread)client_it.next();
                    sb.append(foo.xmlView(i+1));
                    i++;
                }
            } catch (Exception e) {
                echo("pbm listclientsxml"+e);
            }
            sb.append("</m>");
     
            tempoXmlList = new Date();
            sendToAllClients(sb.toString());
        }
     
    // Appelé par AquaClientThread quand le run finit
        static synchronized void deleteClient(AquaClientThread deadClient){
            try {
                clientList.remove(deadClient);
                deadClient.inServerlist=false;
                listClientsXml();
            } catch (Exception e) {
                echo("pbm deleteClient "+e);
            }
     
        }
     
    // Appelé par AquaClientThread quand un client est correctement connecté
        static synchronized void addClient(AquaClientThread newClient){
            try {
            	clientList.add(newClient);
            	newClient.inServerlist=true;
            	listClientsXml();
            } catch (Exception e) {
            	echo("pbm newClient "+e);
            }
     
        }
     
    }
    La seule fois où j'ai réussi, c'est lorsque j'ai désactivé l'envoi de la liste des connectés, le tchat ne plantait plus (enfin du moins il a tenu 6 jours, j'ai donc considéré que c'était bon et j'ai fait d'autres tests qui eux n'ont jamais tenu plus de 2 jours)

    Merci de m'aider !

  8. #8
    Membre Expert
    Avatar de gifffftane
    Profil pro
    Inscrit en
    Février 2007
    Messages
    2 354
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Février 2007
    Messages : 2 354
    Par défaut
    Déjà, peut être, essaie une version simpliofiée, avec juste le déclenchement des traitements de chaque client.

    Ce qui m'étonne dans ce code est le tempClient = new AquaClientThread(socket) ; je présume que c'est un thread, mais je ne vois nulle part le start, et la variable tempClient ne semble ré-utilisée nulle part ?

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 45
    Par défaut
    Citation Envoyé par gifffftane Voir le message
    Déjà, peut être, essaie une version simpliofiée, avec juste le déclenchement des traitements de chaque client.
    J'ai déjà fait justement, j'ai remarqué que le bug se produisait lorsque je rajoutais la fonction listClientsXml pour envoyer la liste des connectés.


    Citation Envoyé par gifffftane Voir le message
    Ce qui m'étonne dans ce code est le tempClient = new AquaClientThread(socket) ; je présume que c'est un thread, mais je ne vois nulle part le start, et la variable tempClient ne semble ré-utilisée nulle part ?
    - Oui c'est ici qu'est crée le Thread lorsqu'un client se connecte.
    - Le start est appelé dans le constructeur de AquaClientThread.
    - Dans ce tempClient, quand le client est bien identifié et connecté, le Thread appel RomuServer.addClient(this). Et c'est ainsi qu'est constitué la liste des clients qui sert à l'envoi de message. Liste qui est renvoyée à chaque connexion et déconnexion de client à tout les connectés.

  10. #10
    Membre Expert
    Avatar de gifffftane
    Profil pro
    Inscrit en
    Février 2007
    Messages
    2 354
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Février 2007
    Messages : 2 354
    Par défaut
    Attention que à faire le start dans un constructeur, il se peut que des objets, et notamment des objets d'appui pour la synchronisation, ne soient pas encore constitués.

    De toutes façons il est difficile de régler par l'essai ces problèmes de syncrhonisation. Pour cela je connais que la réflexion théorique, avec quelques tests pour vérifier.

    Je te conseille :
    • faire la liste des objets verrous ; se limiter à ce qui est réellement utile les synchronisations, et notamment le nombre d'objets verrous ; 1 seul suffit normalement, et placer cet objet en final (pour être sûr ou presque qu'il ne change pas dans un morceau de code oublié).
    • relever tous les objets en accès concurrentiel ; de les limiter au max, evidemment.
    • faire la liste des accés concurentiels, et vérifier que TOUS leur accès sont protégés par un synchronized, et sur quel objet.

    Peux-tu nous donner le résultat de tout ça ?

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 45
    Par défaut
    Aie, c'est du vocabulaire assez technique tout ça.
    J'ai très peu d'expérience en java, c'est d'ailleurs le premier programme en java que je touche, j'ai vraiment appris sur le tas.

    Je vais quand même essayer de te répondre, j'ai que trois méthodes en synchronized qui sont dans RomuServer:
    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
        public final static synchronized void sendToAllClients(String message) {
            echo("sendToAllClients +");
            AquaClientThread foo;
            Iterator client_it = clientList.iterator();
            try {
                while(client_it.hasNext()) {
                    foo = (AquaClientThread)client_it.next();
                    if (foo!=null) {
                        //"Freeze ici"
                        foo.send(message);
                    }
                }
            } catch(Exception ex) { echo("plantage sendtoall "+ex); }
            echo("sendToAllClients -");
        }
     
        public final static synchronized void deleteClient(AquaClientThread deadClient){
             echo("deleteClient + "+deadClient.Pseudo);
            try {
                clientList.remove(deadClient);
                listClientsXml();
            } catch (Exception e) {
                echo("pbm deleteClient "+e);
            }    
     
        echo("deleteClient -");
        }
     
        public final static synchronized void addClient(AquaClientThread newClient){
            echo("newClient + "+newClient.Pseudo);
            try {
            	clientList.add(newClient);
            	listClientsXml();
            } catch (Exception e) {
            	echo("pbm newClient "+e);
            }
     
        echo("newClient -");
        }
    Si j'enlève les deux appels de listClientsXml() dans addClient() et deleteClient(), la liste des connectés n'est plus envoyée et il ne reste alors plus que l'envoi de simple message. Dans ce cas là, le problème ne se produit plus.

    Le problème apparait lorsque justement je réactive l'envoi de la liste des connectés, (liste que je renvoie à chaque connexion (addClient) et déconnexion (deleteClient) de client).

    J'ai aussi remarqué que si je renvoie la liste des connectés seulement lorsque de nouveaux clients se connectent, le problème ne se produit plus.

    Je peux peut-être vous faire un schémas avec les méthodes et leurs liens entre elles ?

  12. #12
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Par défaut
    salut,

    ta classe AquaClientThread et plus particulièrement ta méthode send() est-elle synchronisée ? Que fait-elle exactement (code) ?

    D'une façon générale, il nous faudrait le code de AquaClientThread aussi je pense.

    Je peux peut-être vous faire un schémas avec les méthodes et leurs liens entre elles ?
    C'est certainement la meilleure chose à faire.
    N'oublie pas:
    - de faire une liste pour chacune des méthodes les autres méthodes et bouts de code qui l'appellent
    - de faire un check des classes Java de base que tu utilises pour voir s'il n'y en aurait pas en 'synchronized'.

  13. #13
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Par défaut
    Citation Envoyé par nouknouk
    de faire un check des classes Java de base que tu utilises pour voir s'il n'y en aurait pas en 'synchronized'.
    Je viens d'ailleur de tomber là dessus dans la javadoc:
    As of the Java 2 platform v1.2, this class was retrofitted to implement the List interface, making it a member of the Java Collections Framework. Unlike the new collection implementations, Vector is synchronized.
    Le souci pourrait donc venir de là. Essaie avec une LinkedList (qui n'est pas synchronisée) à la place de ton Vector pour voir.
    Un truc du genre le thread du ServerSocket qui cherche à taper dans la liste de clients pour en ajouter un, pendant que la liste doit être itérée par un autre thread qui utilise sendToAllClients().

    A creuser, mais je sens le coup fourré dans ce coin là

  14. #14
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 45
    Par défaut
    Aucune fonction n'est synchronisée dans le Thread

    Code de la fonction send du Thread :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        public void send(String message){
            out.println(message+'\u0000');
            out.flush();
        }
    Voila pour le petit schèmas : http://thixomag.free.fr/envoi/schemas.jpg

    Pour "check des classes Java de base que tu utilises pour voir s'il n'y en aurait pas en 'synchronized'", hum je sais pas si ça peut vous aidez mais je peux vous donner tout mes imports ? (Par contre faut je fasse le trie vu tout ce que j'ai enlevé comme fonction pour trouver le problème)

    Ok pour LinkedList, je teste cette version du programme en ce moment.

  15. #15
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 45
    Par défaut
    Le problème est toujours la avec LinkedList, je test avec ArrayList voir.

    Edit: avec ArrayList ça plante aussi

  16. #16
    Membre averti
    Profil pro
    Architecte technique
    Inscrit en
    Juillet 2008
    Messages
    13
    Détails du profil
    Informations personnelles :
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Architecte technique

    Informations forums :
    Inscription : Juillet 2008
    Messages : 13
    Par défaut
    Bonjour,

    Le problème pourrait survenir dans le cas où la méthode xmlView() est appelée sur un AquaClientThread en train d'être supprimé de ta clientList. Ceci pourrait arriver dans le cas où les méthodes addClient() et deleteClient() sont appelées au même moment.
    Quoique, tout dépend de la manière dont tu effectues l'appel à la méthode xmlView() dans listClientsXml(). Car, je ne sais pas si le fait que ta clientList soit synchronisée implique que les objets qu'elle contient le soient.

    Au fait, quelle est le type de l'exception générée quand ça plante ? Ca peut aussi aider à la résolution de ton problème.

  17. #17
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 45
    Par défaut
    Citation Envoyé par mr.mams Voir le message
    Le problème pourrait survenir dans le cas où la méthode xmlView() est appelée sur un AquaClientThread en train d'être supprimé de ta clientList.
    Ce problème n'est encore jamais survenu, le plantage arrive au moment ou j'envoie la liste des connectée (qui elle est déjà crée) a tout les autres clients.

    En résumé :
    - Appel de addClient() OU deleteClient()
    -> Ajoute OU Supprime le client dans clientList
    - Appel de listClientsXml()
    -> Parcoure clientList et appel sur chaque élément xmlView() pour constituer la liste des connectés
    - Envoi de la liste : Appel de sendToAllClients(listeDesConnectes)
    -> Parcoure clientList pour envoyer à tout le monde, plantage à certain moment dans la boucle

  18. #18
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Par défaut
    salut,

    et avec ton IDE favori, n'aurais-tu pas moyen de lancer le programme en mode 'debug'.

    Car si interblocage il y a, j'imagine que l'IDE pourra te donner l'état de la pile d'exécution de chacun des threads. Et il serait plus aisé de voir quel thread en particulier bloque avec quel autre et à quel endroit.

  19. #19
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 45
    Par défaut
    J'ai fait quelques tests avec le débugeur de Eclipse.
    Quand le problème survient, tout les threads fonctionnent correctement y comprit le main.

    Le problème que j'ai est vraiment très bizarre.

    Là j'ai tenté de faire un truc, j'ai essai de regrouper toutes les fonctions qui gèrent la clientList en une seul fonction synchronized. Comme ça je suis sur que les actions ce font bien les une à la suite des autres.

    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
     
    import java.lang.management.ManagementFactory;
    import java.lang.management.MemoryMXBean;
    import java.net.*;
    import java.io.*;
    import java.util.Date;
    import java.util.Iterator;
    import java.util.LinkedList;
     
    public class RomuServer {
     
        private final LinkedList<AquaClientThread> clientList= new LinkedList<AquaClientThread>();
        private PrintWriter screenOut = new PrintWriter(System.out, true);
        private ServerSocket serverSocket = null;
        private StringBuffer sb = null;
        private Date date = null;
        private int lastId=0;
     
        public static void main(String[] args) throws IOException {
        	new RomuServer();
        }
     
        public RomuServer() throws IOException{
     
                date = new Date();
                Integer tempPort = new Integer(2001);
     
                try{
                    serverSocket = new ServerSocket(tempPort.intValue());
                }
                catch(IOException e){
                    echo("Could not listen on port: "+tempPort);
                    System.exit(-1);
                }
     
                echo("Server started and listening on port "+tempPort+"\n");
     
                AquaClientThread tempClient;
                try {
                    while (true) {
                        Socket socket = serverSocket.accept();
                        try {
                        	lastId++;
                            tempClient = new AquaClientThread(socket,this,lastId);
                            tempClient.start();
                        } 
                        catch (IOException e) {
                        	echo("CLIENT SOCKET PROBLEM : "+e.getMessage());
                            socket.close();
                        }
                    }
                }
                finally {
                	echo("serverSocket PROBLEM : CLOSE");
                    serverSocket.close();
                }
        }
     
        private void echo(String message) {
     
        	MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
        	date = new Date();
        	screenOut.println(date.toString()+" | T:"+Thread.currentThread().getName()+" | "+message);
        }
     
        public synchronized void doAction(String action, AquaClientThread client, String message){
            echo("");
     
        	if(action=="add" || action=="remove" )
            {
    	        try {
    	        	if(action=="add")
    	        	{
    	        		echo("doAction ADD : "+client.Pseudo);
    	        		clientList.add(client);
    		        	client.inServerlist=true;
    	        	}
    	        	else if(action=="remove")
    	        	{
    	        		echo("doAction REMOVE : "+client.Pseudo);
    	        		clientList.remove(client);
    	                        client.inServerlist=false;
    	        	}
     
     
    	            echo("listClientsXml +");
     
    		            int i=0;
    		            this.sb = new StringBuffer();
     
    		            sb.append("<m>");
    	        	    AquaClientThread foo;
    		            Iterator<AquaClientThread> client_it = clientList.iterator();
    		            try {
    		                while(client_it.hasNext()) {
    		                    foo = (AquaClientThread)client_it.next();
    		                    sb.append(foo.xmlView(i+1)); // fonction du thread
    		                    i++;
    			                }
    		            } catch (Exception e) {
    		                echo("pbm listclientsxml"+e);
    		            }
    		            sb.append("</m>");
     
    	            echo("listClientsXml -");
     
    	            action="message";
    	            message=sb.toString();
     
    	        } catch (Exception e) {
    	        	echo("pbm modListClient "+e);
    	        }
            }
     
            if(action=="message")
            {
                echo("sendToAllClients + ");
     
    	            AquaClientThread foo;
    	            Iterator<AquaClientThread> client_it = clientList.iterator();
    	            try {
    	                while(client_it.hasNext()) {
      	                  foo = (AquaClientThread)client_it.next();
                        		echo("SEND etat:"+foo.getState()+" sur:"+foo.getName()+" lastId:"+lastId);
                        	        foo.send(message);
                                    echo("SEND fin");
    	                }
    	            }
    	            catch(Exception ex) {
    	                echo("plantage sendtoall "+ex);
    	            }
     
                echo("sendToAllClients - ");
            }
     
            echo("");
        }
    Voila ce que j'obtiens par exemple lorsque le tchat fonction :
    Wed Apr 29 10:38:01 GMT 2009:News AquaClientThread : 24 ip:82.247.1.4
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 |
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | doAction ADD : ROMARIO
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | listClientsXml +
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | listClientsXml -
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | sendToAllClients +
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 2 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 9 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 10 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 11 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 12 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 13 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 14 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 16 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 17 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 18 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 19 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 20 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 21 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 23 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 24 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | sendToAllClients -
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 |
    Et voila ce que je peux par exemple obtenir au moment où le problème survient :
    Wed Apr 29 10:38:01 GMT 2009:News AquaClientThread : 24 ip:82.247.1.4
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 |
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | doAction ADD : ROMARIO
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | listClientsXml +
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | listClientsXml -
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | sendToAllClients +
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 2 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 9 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 10 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 11 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 12 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 13 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 14 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 16 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 17 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 18 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 19 lastId:24
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND fin
    Wed Apr 29 10:38:01 GMT 2009 | T:AquaClientThread : 24 | SEND etat:RUNNABLE sur:AquaClientThread : 20 lastId:24
    Le pire dans tout ça c'est que la boucle infinie dans RomuServer, fonctionne toujours et si un nouveau client se connecte, un nouveau AquaClientThread est bien créé.

  20. #20
    Modérateur
    Avatar de nouknouk
    Homme Profil pro
    Inscrit en
    Décembre 2006
    Messages
    1 655
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 1 655
    Par défaut
    re,

    je me trompe peut-être mais il me paraît normal que tous les thread soient en RUNNABLE dans ton log puisque le log représente ce qui se passe avant le bloquage.

    Tu devrais plutôt voir pour implémenter un thread séparé qui vérifiera périodiquement (toutes les secondes par exemple) l'état de chaque AquaClientThread et s'il n'est pas à RUNNABLE, affichersa stackTrace:

    On peut par exemple utiliser le thread de swing (EDT) pour faire ça avec un timer:
    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
     
            // ta liste telle que définie ailleurs.
            LinkedList<AquaClientThread> clientList = new LinkedList<AquaClientThread>();
            // --------------------------
     
            final LinkedList<AquaClientThread> listToCheck = clientList;
            javax.swing.Timer timer = new javax.swing.Timer(1000, new java.awt.event.ActionListener() {
     
                public void actionPerformed(ActionEvent e) {
                    synchronized(System.class) { // pour éviter les ConcurrentModificationException 
                        for (AquaClientThread t : listToCheck) {
                            if (t.getState().equals(Thread.State.BLOCKED))
                                System.out.println("thread "+t+" found in state "+t.getState());
                                t.dumpStack();
                        }
                    }
                }
            });
            timer.setRepeats(true);
            timer.start();
    A noter que pour éviter d'avoir une ConcurrentModificationException parce que l'EDT itère sur la liste pendant que tu fais un 'add' ou 'remove', encadre les deux lignes clientList.add(client); et clientList.remove(client); par un synchronized(System.class) { /*...*/ }.

    Tiens nous au courant

Discussions similaires

  1. Réponses: 3
    Dernier message: 01/06/2009, 17h49
  2. Firefox et OnBlur ne fonctionne plus au bout d'un moment
    Par Zoizoi dans le forum Général JavaScript
    Réponses: 0
    Dernier message: 23/03/2009, 20h31
  3. plantage au bout de 2 boucles
    Par lecknaat dans le forum VB.NET
    Réponses: 3
    Dernier message: 09/06/2007, 15h54
  4. Les objets disparaissent au bout d'un certain moment
    Par restricteur dans le forum Servlets/JSP
    Réponses: 6
    Dernier message: 17/05/2007, 19h03

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