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

Développement Web en Java Discussion :

Serveur multithread - Exception : java.util.ConcurrentModificationException


Sujet :

Développement Web en Java

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2007
    Messages : 165
    Points : 73
    Points
    73
    Par défaut Serveur multithread - Exception : java.util.ConcurrentModificationException
    Bonjour,

    Je suis entrain de faire un jeu de carte online, c'est la première fois que je me lance dans un programme en réseau avec multithread un peu plus pousser que de simple chat, etc...

    Il y a une application client et une serveur.

    Voici ce que je veux faire en ce moment :
    1) Le client entre son login
    2) La connection au serveur s'établie
    3) Le client envoie les données pour le login et le mot de passe
    4) Le serveur reçoit et va checker dans la base de donnée
    5) Si c'est bon il renvoie une confirmation positive au client sinon un rejet.
    6) Le client reçoit et affiche un message.

    De 1 à 4 tout va bien, mais quand le server doit aller envoyer la donnée de confirmation quelque chose de spécial se passe : le serveur recoit une nouvelle connexion de mon client et puisque je lui fait checker s'il est pas déjà connecté il va tout rejetter, ce qu'il ne devrait pas faire. Et ensuite il crash (le serveur)
    Citation Envoyé par Console serveur
    New connection !
    Number of thread : 2
    Packet receive : uno.Data@89ae9e
    class uno.Player
    New connection !
    Server has refused connection : 192.168.1.34 - Already connect
    Exception in thread "Thread-0" java.util.ConcurrentModificationException
    It didn't work! - Software caused connection abort: socket write error
    at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
    at java.util.AbstractList$Itr.next(AbstractList.java:343)
    at unoserver.Server$DaemonThread.run(Server.java:65)
    java.net.SocketException: Software caused connection abort: socket write error
    at java.net.SocketOutputStream.socketWrite0(Native Method)
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)
    at java.net.SocketOutputStream.write(SocketOutputStream.java:136)
    at java.io.ObjectOutputStream$BlockDataOutputStream.drain(ObjectOutputStream.java:1838)
    at java.io.ObjectOutputStream$BlockDataOutputStream.setBlockDataMode(ObjectOutputStream.java:1747)
    at java.io.ObjectOutputStream.writeNonProxyDesc(ObjectOutputStream.java:1249)
    at java.io.ObjectOutputStream.writeClassDesc(ObjectOutputStream.java:1203)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1387)
    thread interrupted
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1150)
    at java.io.ObjectOutputStream.writeFatalException(ObjectOutputStream.java:1538)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:329)
    at unoserver.Network.writeObject(Network.java:24)
    at unoserver.cmdToServer.acceptedConnect(cmdToServer.java:183)
    at unoserver.cmdToServer.getPlayerConnectServer(cmdToServer.java:172)
    at unoserver.cmdToServer.analyse(cmdToServer.java:75)
    at unoserver.Server$ServerData.run(Server.java:109)
    at java.lang.Thread.run(Thread.java:619)
    J'ai trouvé que cette erreur arrive si l'on n'utilise pas d'iterator pour parcourir une liste, donc c'est ce que j'ai fait mais l'erreur persiste.

    J'ai cherché pourquoi le serveur croit recevoir une nouvelle demande de connexion et je n'ai pas trouvé pourquoi. Le client ne se connecte qu'une seul fois je l'ai bien vérifié.

    Voici le code du serveur où il gère les threads :

    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
    /*
     * To change this template, choose Tools | Templates
     * and open the template in the editor.
     */
     
    package unoserver;
     
    import java.io.IOException;
    import java.net.InetAddress;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.security.NoSuchAlgorithmException;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    import java.util.logging.Level;
    import java.util.logging.Logger;
     
    /**
     *
     * @author rxp
     */
    public class Server {
     
        // list of the inetaddress connected
    private List <InetAddress> address;
    // port of teh application
    private int port = 1991;
     
        public Server() throws IOException{
            //init
            address = new ArrayList<InetAddress>();
            Thread t = new DaemonThread();
     
      }
     
        class DaemonThread extends Thread{
            public DaemonThread(){
                //start the main thread
            start();
            }
     
            @Override
            public void run(){
     
            Socket skt = null;
            ServerSocket srvr = null;
                try {
                    //open the port
                    srvr = new ServerSocket(port);
                } catch (IOException ex) {
                    Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                }
     
            while(true){
                 try{
                     //accept the connections
                     skt = srvr.accept();
                     System.out.print("New connection ! \n");
                     //create an iterator of address
                     Iterator it = address.iterator();
                     //check in address if the client is already connected
                     while(it.hasNext()){
                         InetAddress add = (InetAddress) it.next();
                         if(skt.getInetAddress().equals(add)){
                             System.out.print("Server has refused connection : "+add.getHostAddress()+" - Already connect \n");
                             closeConnection(skt, false);
                         }else{
                         }
                     }
                     //error
                }catch(IOException ioe){
                     System.out.print("It didn't work! - "+ioe.getMessage()+"\n");
                     ioe.printStackTrace();
                     closeConnection(skt, false);
                }
                 //if no error :
                     // add the inetaddress to address
                 address.add(skt.getInetAddress());
                    // create the thread
                 Thread t = new Thread(new ServerData(skt));
                    // start the thread
                 t.start();
            }
     
            }
        }
     
     
      class ServerData implements Runnable{
          private Socket skt;
          Network network;
          cmdToServer cts = new cmdToServer();
          public ServerData(Socket skt){
              //init
              this.skt = skt;
              network = new Network();
              // number of thread
              System.out.println("Number of thread : "+Thread.activeCount());
          }
     
          public void run(){
     
          try{
                    try {
                        try {
                            //analyse the packet juste receive
                            cts.analyse((Object) network.readObject(skt), skt.getInetAddress());
                        } catch (SQLException ex) {
                            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                        } catch (NoSuchAlgorithmException ex) {
                            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    } catch (ClassNotFoundException ex) {
                        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                    }
             }catch(IOException ioe){
                 //if error :
                 //close the connection
                System.out.print("It didn't work! - "+ioe.getMessage()+"\n");
                ioe.printStackTrace();
                    closeConnection(skt, true);
             }
          }
     
      }
     
      public void closeConnection(Socket skt, boolean thread){
        try {
            //remove address from address
                address.remove(skt.getInetAddress());
                //close the socket
                skt.close();
            } catch (IOException ex) {
                Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
            }
            if(thread == true){
                //if want to :
                System.out.println("thread interrupted");
                //kill the thread
                Thread.currentThread().interrupt();
            }
     
      }
    La ligne erronée est sois-disant celle-ci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    InetAddress add = (InetAddress) it.next();

  2. #2
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    Citation Envoyé par rXpCH Voir le message

    J'ai trouvé que cette erreur arrive si l'on n'utilise pas d'iterator pour parcourir une liste, donc c'est ce que j'ai fait mais l'erreur persiste.
    Non cette erreur se produit quand tu parcours une liste et que, en meme temps, sur un autre thread, tu la modifie. Il faut en multithread que tu code de manière à tenir compte des accès simultané, en protégeant tes ressources partagées contre l'utilisation concurentielle. Donc si tu lit ta liste, il faut mettre un verrou dessus tant que t'as pas fini de la lire, pour empecher un autre thread d'écrire dedans.

    Pour mettre ses verrous t'as le choix entre les blocs synchronized ou l'utilisation d'apis comme apache commons transaction.

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2007
    Messages : 165
    Points : 73
    Points
    73
    Par défaut
    Je pense utiliser synchronized qu'en penses-tu ? Ca me permettrait de ne pas trop modifier mon code.

    Je n'ai jamais utilisé de synchronized, mais faut bien apprendre une fois si ça évite les threads de se bouffer entre eux. Merci pour voter aide je vous tiendrais au courant ici.

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2007
    Messages : 165
    Points : 73
    Points
    73
    Par défaut
    Rebonjour,

    J'ai été me renseigner (Cours Java, FAQ Java et Forum Java par exemple :-°) j'ai vu que pour montrer que le block est synchronizer on ajoute synchronized à la déclaration de la méthode. Donc j'ai créé une méthode qui contient tout les check, supression et addition à la variable list : address. Mais le problème persiste (exactement le même).

    Voici la méthode :

    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
      public synchronized void makeConnectionsChanges(Socket skt, String type, boolean thread){
        if(type.equals("kill")){
          try {
            //remove address from address
                address.remove(skt.getInetAddress());
                //close the socket
                skt.close();
            } catch (IOException ex) {
                Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
            }
            if(thread == true){
                //if want to :
                System.out.println("thread interrupted");
                //kill the thread
                Thread.currentThread().interrupt();
            }
     
        }
        // create connection
        else if(type.equals("create")){
        // add the inetaddress to address
                 address.add(skt.getInetAddress());
                    // create the thread
                 Thread t = new Thread(new ServerData(skt));
                    // start the thread
                 t.start();
        }
     
        //check connection
        else if(type.equals("check")){
            //create an iterator of address
            Iterator it = address.iterator();
            while(it.hasNext()){
                         InetAddress add = (InetAddress) it.next();
                         if(skt.getInetAddress().equals(add)){
                             System.out.print("Server has refused connection : "+add.getHostAddress()+" - Already connect \n");
                             makeConnectionsChanges(skt, "kill", false);
                         }else{
                         }
                     }
     
        }
     
      }
    Avez-vous une idée ?

  5. #5
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    ce sont les changement mais aussi la lecture qui doivent etre synchronisé sur un objet commun. Rien ne sert de synchroniser les changement sur la lecture de la liste se fait sans protection.

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2007
    Messages : 165
    Points : 73
    Points
    73
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    ce sont les changement mais aussi la lecture qui doivent etre synchronisé sur un objet commun. Rien ne sert de synchroniser les changement sur la lecture de la liste se fait sans protection.
    Désolé mais j'ai du mal à comprendre ^^ Ma list (address) doit elle être synchro, c'est cela ? Mais comment le faire ?

  7. #7
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    y a de la doc sur la synchronisation ici

    http://rom.developpez.com/java-synchronisation/

    un synchronizd sur un objet garanti qu'un seul thread peut avoir ce synchronized à la fois. Donc si t'a un thread qui fait sa lecture dans un
    aucun autre thread ne peut se trouver aussi dans un synchronized sur la meme liste.

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2007
    Messages : 165
    Points : 73
    Points
    73
    Par défaut
    Merci pour ta réponse, j'ai lu le tout et je comprend le problème. Mais je ne vois pas comment l'arranger.
    J'ai le "main thread (thread 0)" qui doit accéder à la liste pour ajouter les nouvelle connexions à celles-ci. A coté le main thread lance les sous thread qui correspondent à un par utilisateur. Si je bloque pas le address au main thread et au sous-thread mon appli plante, mais si je le fais elle ne plante pas mais les sous thread ont l'air de bloqués complètement car elle ne reçoit plus les paquets.
    J'ai du mal à voir comment modifier ma façon de faire, car le problème vient surement de ma façon de faire.

  9. #9
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    tu dois faire un synchronized autour des tes ajouts ainsi qu'autour de tes itérations. Bien sur il ne faut pas garder le synchronized plus longtemps que nécessaire. sinon tu empeche les autres thread de travailler sur la liste. Typiquement tu devrais avoir ce genre de code

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    synchronized(liste){
       liste.add(unElement);
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    synchronized(liste){
       for (Type t : liste){
          //faire quelquechose de rapide avec t
       }
    }

  10. #10
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2007
    Messages : 165
    Points : 73
    Points
    73
    Par défaut
    J'ai modifié ma méthode ou je fais des changement sur ma list :
    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
    public synchronized void makeConnectionsChanges(Socket skt, String type, boolean thread){
        if(type.equals("kill")){
          try {
              synchronized(address){
            //remove address from address
                address.remove(skt.getInetAddress());
              }
                //close the socket
                skt.close();
            } catch (IOException ex) {
                Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
            }
            if(thread == true){
                //if want to :
                System.out.println("thread interrupted");
                //kill the thread
                Thread.currentThread().interrupt();
            }
     
        }
        // create connection
        else if(type.equals("create")){
            synchronized(address){
        // add the inetaddress to address
                 address.add(skt.getInetAddress());
            }
                    // create the thread
                 Thread t = new Thread(new ServerData(skt));
                    // start the thread
                 t.start();
        }
     
        //check connection
        else if(type.equals("check")){
            //create an iterator
            Iterator it;
            synchronized(address){
            //init an iterator of address
            it = address.iterator();
            }
            synchronized(it){
            while(it.hasNext()){
                InetAddress add = null;
                         add = (InetAddress) it.next();
                         if(skt.getInetAddress().equals(add)){
                             System.out.print("Server has refused connection : "+add.getHostAddress()+" - Already connect \n");
     
                             makeConnectionsChanges(skt, "kill", false);
                         }else{
                         }
                     }
            }
        }
     
      }
    Mais l'erreur est à la même place que avant, ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    add = (InetAddress) it.next();
    Pourtant it il est synchronizé et j'ai essayé de synchronizé add mais cela ne règle pas le problème.

  11. #11
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    Le synhcronized sur it ca sert absolument a rien, puisque it n'es partagé avec aucun autre thread. La seule variable qui pourrait etre partégée, c'est adresse, donc c'est la dessus qu'il faut le faire pour empecher les accès concurrent par d'autre thread. Cependant ca empechera pas ton code de faire n'importe quoi. En l'occurence ici:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
            while(it.hasNext()){
                InetAddress add = null;
                         add = (InetAddress) it.next();
                         if(skt.getInetAddress().equals(add)){
                             System.out.print("Server has refused connection : "+add.getHostAddress()+" - Already connect \n");
     
                             makeConnectionsChanges(skt, "kill", false);
                         }else{
                         }
                     }
            }
    pendant l'itération tu appelle une mthode qui supprime des éléments de la liste, et synchronisation ou pas, ca empechera pas cette erreur de ce produire. Tu ne peux pas modifier une liste pendant que tu itère dessus, sauf en utilisant it.remove();

  12. #12
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2007
    Messages : 165
    Points : 73
    Points
    73
    Par défaut
    Mais l'erreur arrive avant cette ligne :/

  13. #13
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    c'est pas l'effacement en lui meme qui provoque l'erreur, c'est le fait de poursuivre l'itération après l'effacement qui le pose. De toutes facon c'est pas bon, tu ne peux pas effacer comme tu le faite de la liste pendant que tu itére dessus. Sauf en utilisant iterator.remove(). Ce que tu va devoir faire dans ton cas.

  14. #14
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Décembre 2007
    Messages : 165
    Points : 73
    Points
    73
    Par défaut
    D'accord, je comprend le problème et il est plus ou moins réglé. Mais ce que je comprend pas c'est que mon server croit recevoir 2 connexion et recevoir 2 fois quelque choses alors que du côté client tout va comme sur des roulette.
    Mes testes sont en localhost, est-ce possible que le serveur se connecte à lui même et s'envoie quelque chose à lui même si un problème survient chez le client ou pas ?

    [EDIT] : Oui c'était bien cela, fiou ce problème enfin régler. J'utilise une machine virtuel et ça règle ces problèmes. Mais maintenant le socket se ferme tout seul, à moi de voir pourquoi.

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

Discussions similaires

  1. [JDOM] Exception:Exception in thread "main" java.util.ConcurrentModificationException
    Par solawe dans le forum Format d'échange (XML, JSON...)
    Réponses: 3
    Dernier message: 10/06/2009, 18h33
  2. Réponses: 3
    Dernier message: 12/04/2009, 18h39
  3. Réponses: 2
    Dernier message: 30/01/2009, 09h14
  4. Réponses: 5
    Dernier message: 02/06/2008, 12h21
  5. Exception java.util.PropertyPermission dans mon applet
    Par brunoperel dans le forum Applets
    Réponses: 3
    Dernier message: 11/05/2007, 10h32

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