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

Delphi Discussion :

[Sockets/Sendbuf]Logiciel de chat


Sujet :

Delphi

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 69
    Points : 41
    Points
    41
    Par défaut [Sockets/Sendbuf]Logiciel de chat
    Donc pour résumer là ou j'en suis... j'ai compris comment marchait les sockets Tserver et Tclient. Les procédures pour envoyer et recevoir du texte aussi. Cependant je veux envoyer plus que du texte, donc je me suis tourné vers les routines (je crois que ça s'appelle comme ça) SendBuf et ReceiveBuf. J'envoie un tableau pour l'instant uniquement du coté serveur qui contient le message envoyé par le serveur en Tab[1] et le pseudo en Tab[2]. L'envoi "semble" être un succès puisque le programme serveur ne plante pas. Mais sur le programme client il ya un probleme puisque je demande d'afficher le message dans un mémo et le pseudo dans un autre. Seul une ligne blanche s'affiche dans le mémo du client. Je vais rajouter le code partiel pour ceux qui me trouvent incompréhensible

    Le code ci dessous est présent dans les 2 programmes (juste après l'implementation):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    Type
      T_Tab=Array[1..3] of String;
     
    Var
      Tab:T_Tab;
      Form1: TForm1;
    Coté Serveur:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    Procedure TForm1.Edit2KeyPress(Sender: TObject; var Key: Char);
    Begin
    If Key = #13 Then
      If Edit2.Text <> '' Then
      Begin
        Tab[2]:= 'Admin';
        Tab[1]:= Edit2.Text;
        If Serveur.Socket.ActiveConnections <> 0 Then
        Begin
        Serveur.Socket.Connections[0].SendBuf(Tab,SizeOf(Tab));
        Edit2.Text := '';
        End;
     End;
    Coté Client:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    Procedure TForm1.ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
    Begin
      Recus := Socket.ReceiveLength;
      If Recus <> SizeOf(Tab) then Exit;
      Socket.ReceiveBuf(Tab,Sizeof(Tab));
      If Tab[1] <> '' Then
        Memo2.Lines.Add(Tab[1]);
      If Tab[2] <> '' Then
        Memo3.Lines.Add(Tab[2]);
    end;
    merci d'avoir lu.

  2. #2
    Expert éminent Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Points : 7 903
    Points
    7 903
    Par défaut
    Bonjour,

    Le problème vient du fait qu'en transférant le tableau TAB, on ne passe que 12 bytes : les 3 pointeurs vers les chaines et non leur contenu.

    Il faut revoir le code fin de transmettre la longueur du buffer, puis son contenu (pour transmission de texte, on pourrait aussi utiliser une technique dans laquelle le buffer est compris entre STX et ETX sans indication de longueur).

    Suggestion : à la place d'un tableau de string, utiliser une tstringlist TAB (TAB.length donne la longueur, TAB.text, TAB[i] la ligne i).

  3. #3
    Membre expert
    Avatar de LadyWasky
    Femme Profil pro
    Inscrit en
    Juin 2004
    Messages
    2 932
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 54
    Localisation : France, Hauts de Seine (Île de France)

    Informations forums :
    Inscription : Juin 2004
    Messages : 2 932
    Points : 3 562
    Points
    3 562
    Par défaut
    C'est presque ça !


    Déjà, une première remarques, prends l'habitude de coder l'indice de tes tableaux, de 0 à n-1. Tu t'y retrouveras tout autant, surtout qu'il faut savoir que lorsque tu transmet un tableau (dynamique ou non) à une procédure, un tableau[3..8] par exemple sera récupéré dans la procédure avec des indices allant de 0 à 6 !

    Autre remarque qui va expliquer beaucoup de choses pour la suite :
    autant lorsque tu déclare une chaîne de caractère comme ceci :
    tu peux envoyer ta chaîne de caractère via un buffer comme ceci :
    parce que ta chaîne est assimilée à un variable tableau d'octets

    que si tu la déclares comme ceci :
    tu ne peux plus, parce que dans ce cas, si les chaînes longues sont activés dans les options de compilation (chaîne >255 caractères), s est un pointeur !
    Donc SizeOf(s)= 4 !
    Tu comprendras alors que si tu transmets s à SendBuf, tu n'envoies que le pointeur, et non pas ce qui est pointé !
    Par contre, celà fonctionne toujours :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SendBuf(s[1],length(s));
    tu lui demandes ici de copier à partir de l'emplacement mémoire du premier caractère de la chaîne, tous les caractères

    Je ferme ici cette parenthèse

    Sinon pour ce qui t'intéresse directement, il faudrait que, coté Serveur, tu prépares d'abord l'envoi de tes chaînes de caractères en les regrouppant dans un buffer un peu plus global.

    Imaginons que tu veuilles envoyer :
    Tab[0]='TrucMuche'
    Tab[1]='Bonjour'
    Tab[2]='Salut'

    Il faudrait que tu les places tout d'abord dans un buffer (un tableau d'octets en fait) qui ait cette structure :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    +--+--+--+--+--+--+--+
    |LT|L0|C0|L1|C1|L2|C2|
    +--+--+--+--+--+--+--+
    Où :
    LT=Longueur Totale des données dans le buffer (1 integer=4 octets)
    L0=Longueur de la chaîne n°0 (1 integer=4 octets)
    C0=caractères de la Chaine n°0 (chaque caractère=1 octet)
    etc...

    d'où
    C0='T'|'r'|'u'|'c'|'M'|'u'|'c'|'h'|'e'
    L0=9 (stocké sur 4 octets)
    ...
    L1=7 (stocké sur 4 octets)
    L2=5 (stocké sur 4 octets)
    LT=L0+L1+L2+3*4+1*4 (3 fois 4 octets pour comptabiliser les entiers L0,L1,L2 et 1 fois 4 octets pour lui-même

    Autrement dit : dans ton code, celà devrait donner :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Type
      T_Tab=Array[0..2] of String;
     
    Var
      Tab:T_Tab;
      TonBuffer:array of byte;
      Form1: TForm1;
    Coté Serveur:

    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
     Procedure TForm1.Edit2KeyPress(Sender: TObject; var Key: Char);
    var i,Li,LTOT,L0,L1,L2,position:integer;
         s:string;
    Begin
    If Key = #13 Then
      If Edit2.Text <> '' Then
      Begin
        Tab[2]:= 'Admin';
        Tab[1]:= Edit2.Text;
     
    //Initialisation du buffer
    L0:=Length(Tab[0]);
    L1:=Length(Tab[1]);
    L2:=Length(Tab[2]);
    LTOT:=L0+L1+L2+4*SizeOf(integer);
    SetLength(TonBuffer,LTOT);
    //ecriture dans le buffer
    position:=0;
    Move(LTOT,TonBuffer[position],SizeOf(LTOT));
    inc(position,SizeOf(LTOT));
    for i:=0 to 2 do
    begin
      s:=Tab[i];
      Li:=Length(s);
      Move(Li,TonBuffer[position],SizeOf(Li));
      inc(position,SizeOf(Li));  
      if Li>0 then Move(s[1],TonBuffer[position],Li);
      inc(position,Li);
    end;
     
    //envoi des données
    If Serveur.Socket.ActiveConnections <> 0 Then
        Begin
        Serveur.Socket.Connections[0].SendBuf(TonBuffer[0],LTOT);
        Edit2.Text := '';
        End;
     End;

    Coté Client:

    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
     Procedure TForm1.ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
    var i,Li,LTOT,L0,L1,L2,position,Recus:integer;
          s:string;
    Begin
      Recus := Socket.ReceiveLength;
      //si la longueur reçue est inférieure aux 4 entiers LTOT,L0,L1 et L2 on sort (erreur)
      If Recus<4*SizeOf(integer) then exit;
     
      //sinon on initialise le tableau
      Setlength(TonBuffer,Recus);
         Socket.ReceiveBuf(TonBuffer[0],Recus);
     
      //décodage du buffer
      position:=0;
      Move(TonBuffer[position],LTOT,SizeOf(LTOT));
      inc(position,,SizeOf(LTOT));
        //si la longueur reçue est identique LTOT, les données ont l'air d'être 
        //correcte sinon --> erreur
        if LTOT<>recus then exit;
     for i:=0 to 2 do
     begin  
       Move(TonBuffer[position],Li,SizeOf(Li));
       inc(position,,SizeOf(Li));
          //on vérifie que Li ne nous renvoie pas une longueur supérieure à
          //ce qu'on a (reçu- les 4 entier indiquant des longueurs)
          // sinon il y a erreur de réception
           if (position+Li)>(recus-4*SizeOf(integer)) then exit;
       s:='';
       SetLength(s,Li);
       Move(TonBuffer[position],s[1],Li);
       inc(position,Li);
       Tab[i]:=s;
     end; 
     
      If Tab[1] <> '' Then
        Memo2.Lines.Add(Tab[1]);
      If Tab[2] <> '' Then
        Memo3.Lines.Add(Tab[2]);
    end;
    Je crois que ça devrait marcher

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 69
    Points : 41
    Points
    41
    Par défaut
    Merci à tous les 2 vais relire lentement le post de waskol et à tête reposé sinon vais rien retenir

    Ptite remarque: je croyais que la cellule 0 n'existait pas dans les tableaux sous pascal donc j'ai cru que c'était pareil dans delphi

  5. #5
    Membre expert
    Avatar de LadyWasky
    Femme Profil pro
    Inscrit en
    Juin 2004
    Messages
    2 932
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 54
    Localisation : France, Hauts de Seine (Île de France)

    Informations forums :
    Inscription : Juin 2004
    Messages : 2 932
    Points : 3 562
    Points
    3 562
    Par défaut
    Citation Envoyé par LeFlou
    Merci à tous les 2 vais relire lentement le post de waskol et à tête reposé sinon vais rien retenir

    Citation Envoyé par LeFlou
    Ptite remarque: je croyais que la cellule 0 n'existait pas dans les tableaux sous pascal donc j'ai cru que c'était pareil dans delphi
    Si, même en pascal !
    même que tu peux avoir des indices négatifs :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    var Tab:array[-5..7] of integer;
         Tab2:array[-5..-1] of boolean;

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 69
    Points : 41
    Points
    41
    Par défaut
    J'ai un nouveau souci: les strings contenus dans les cellules du Tab ne sont pas affichables ... pourtant ce ne sont pas des cellules vides d'apres les tests que je viens d'effectuer. Impossible de les afficher dans un TEdit ou dans un TMemo... J'ai manqué quelque chose ? (J'ai essayé de bidouiller ton code pour le modifier ainsi que la copie pure du code en vain...)

    Je me demandais en fait... le plus simple pour intégrer un systeme de pseudonymes/liste de pseudos contenue dans le prog serveur et consultable par les clients n'est-il pas de construire une base de données ? (je n'y connais rien dans les bases de données)

    Merci pour vos réponses.

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 69
    Points : 41
    Points
    41
    Par défaut
    Bonsoir, j'ai repris depuis quelques temps la motivation de comprendre et de maitriser les sockets sous delphi
    (envoi de msg serveur vers client et vice-versa). J'ai repris les codes écrits precedemment mais il semble que c'est l'envoi qui foire et non la réception.

    Procedure TForm1.Edit2KeyPress(Sender: TObject; var Key: Char);
    var i,Li,LTOT,L0,L1,L2,position:integer;
    s:string;
    Begin
    If Key = #13 Then
    If Edit2.Text <> '' Then
    Begin
    Tab[0]:= Edit2.Text;
    Tab[1]:= 'Admin';
    Tab[2]:= 'test';

    //Initialisation du buffer
    L0:=Length(Tab[0]); //on prend la taille du contenu de Tab[0]
    L1:=Length(Tab[1]);
    L2:=Length(Tab[2]);
    LTOT:=L0+L1+L2+4*SizeOf(integer);
    SetLength(Buffer,LTOT); // à quoi sert le +4 ?
    //ecriture dans le buffer
    position := 0;
    Move(LTOT,Buffer[position],SizeOf(LTOT)); // ?
    inc(position,SizeOf(LTOT)); // ?

    For i:=0 to 2 do
    Begin
    s:=Tab[i];
    Li:=Length(s);
    Move(Li,Buffer[position],SizeOf(Li)); // ?
    inc(position,SizeOf(Li)); // ?
    if Li>0 then Move(s[1],Buffer[position],Li); // ?
    inc(position,Li); // ?
    End;

    //envoi des données
    If Serveur.Socket.ActiveConnections <> 0 Then
    Begin
    Serveur.Socket.Connections[0].SendBuf(Buffer[0],LTOT);
    Edit2.Text := '';
    End;
    End;
    End;
    Voici la partie client je ne crois pas qu'il y ait de problemes de ce coté (il marque, à chaque envoi de msg depuis le serveur, sur le prog client Pas d'erreur à signaler...):

    procedure TForm1.ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
    var i,Li,LTOT,L0,L1,L2,position,Recus:integer;
    s:string;
    Begin
    Recus := Socket.ReceiveLength;
    //si la longueur reçue est inférieure aux 4 entiers LTOT,L0,L1 et L2 on sort (erreur)
    If (Recus < (4*SizeOf(integer))) then
    Begin
    Memo2.Lines.Add('Erreur lvl1');
    exit;
    End;

    //sinon on initialise le tableau
    Setlength(Buffer,Recus);
    Socket.ReceiveBuf(Buffer[0],Recus);

    //décodage du buffer
    position := 0;
    Move(Buffer[position],LTOT,SizeOf(LTOT));
    inc(position,SizeOf(LTOT));

    //si la longueur reçue est identique LTOT, les données ont l'air d'être
    //correcte sinon --> erreur
    if LTOT<>recus then
    Begin
    Memo2.Lines.Add('Erreur lvl2');
    exit;
    End;

    For i:=0 to 2 do
    Begin
    Move(Buffer[position],Li,SizeOf(Li));
    inc(position,SizeOf(Li));

    //on vérifie que Li ne nous renvoie pas une longueur supérieure à
    //ce qu'on a (reçu- les 4 entier indiquant des longueurs)
    // sinon il y a erreur de réception

    If (position+Li)>(recus-4*SizeOf(integer)) then
    Begin
    Memo2.Lines.Add('Erreur lvl3');
    exit;
    End;

    s:='';
    SetLength(s,Li);
    Move(Buffer[position],s[1],Li);
    inc(position,Li);
    Tab[i]:=s;
    End;
    Memo2.Lines.Add('Pas d''erreur à signaler');
    End;
    Et j'ai bien rajouté dans les 2 parties:

    Type
    T_Tab=Array[0..2] of string;
    Var
    Tab:T_Tab;
    Buffer:Array of byte;
    Merci de bien vouloir m'expliquer les lacunes de ces bouts de programme

  8. #8
    Membre expert
    Avatar de LadyWasky
    Femme Profil pro
    Inscrit en
    Juin 2004
    Messages
    2 932
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 54
    Localisation : France, Hauts de Seine (Île de France)

    Informations forums :
    Inscription : Juin 2004
    Messages : 2 932
    Points : 3 562
    Points
    3 562
    Par défaut
    Salut,
    de passage vite fait voci ce que je te propose (j'ai testé) :
    C'est coté du client que celà merdouille en fait, au niveau de cette ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    If (position+Li)>(recus-4*SizeOf(integer)) then
    En bricolant vite fait, si tu écris ça, ça va marcher du premier coup :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    If (position+Li)>recus then
    Sinon, dans l'absolu et dans le code que je t'avais donnée, il manquait deux trois petites lignes pour parfaire le tout :

    Au lieu de :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    For i:=0 to 2 do
    Begin
    Move(Buffer[position],Li,SizeOf(Li));
    inc(position,SizeOf(Li));
     
    //on vérifie que Li ne nous renvoie pas une longueur supérieure à
    //ce qu'on a (reçu- les 4 entier indiquant des longueurs)
    // sinon il y a erreur de réception
     
    If (position+Li)>(recus-4*SizeOf(integer)) then
    Begin
    Memo2.Lines.Add('Erreur lvl3');
    exit;
    End;
    Il aurait fallu rajouter une variable pour décompter la taille des Li bien recus, et je ne sait pas trop comment l'appeler, donc je l'appelle compteur (integer) :
    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
    Compteur:=SizeOf(LTOT);
    For i:=0 to 2 do
    Begin
      Move(Buffer[position],Li,SizeOf(Li));
      inc(position,SizeOf(Li));
      inc(Compteur,SizeOf(Li));
    //on vérifie que Li ne nous renvoie pas une longueur supérieure à
    //ce qu'on a (reçu- les 4 entier indiquant des longueurs)
    // sinon il y a erreur de réception
     
      If (position+Li)>(recus-4*SizeOf(integer)+Compteur) then
      Begin
        Memo2.Lines.Add('Erreur lvl3');
       exit;
      End;
    [/CODE]

    Et là ça devrait enfin marcher.

    Sinon, pour comprendre comment le code fonctionne, le mieux
    c'est que tu mette un TClientSocket et un TServerSocket sur une même fiche, avec même numéro de port, le client ayant Host=127.0.0.1, et les deux composants mis sur actif.
    Tu rajoutes un memo (pour la partie cliente) et un TEdit (pour la partie serveur) et tu traces le code en pas à pas en observant ce qui se passe dans la variable appelée Buffer.

    Sinon, Move est une routine standard de Delphi qui permet de copier un certain nombre d'octets d'une variable (tableau ou non) à une autre, quelque soit le type de variable : jettes un oeil dans l'aide de ton Delphi, elle explique ça très bien.

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 69
    Points : 41
    Points
    41
    Par défaut
    Merci beaucoup jvais regarder tout ça. Je met en résolu dès que c'est bon.

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 69
    Points : 41
    Points
    41
    Par défaut
    J'essaye à présent d'intégrer une liste des gens connectés (sur le programme serveur dans un premier temps puis sur les clients ensuite...)

    Je pars du principe que la communication entre client/serveur se base sur un tableau de 3 cases contenant des "string". Ainsi, la premiere case (Tab[0]) correspond au pseudonyme, la deuxieme au message (eventuel...) et la derniere au mode (ex: online/offline,envoi pseudo etc...)

    Lorsque le client appuie sur le bouton connecter (on suppose qu'il réussit à établir la connexion avec le serveur) il communique le tableau suivant:
    Tab[0] := 'Invité' Tab[1]:= ''; Tab[2]:= '2';

    Ainsi on peut anticiper les codages formatés en aval -> Si le serveur reçoit un tableau dont la 3ème case contient 2 (mode envoi pseudo) alors il l'ajoute à la listbox.

    Pour l'instant le chat est établi uniquement entre serveur/client et non client/client. Pour parler à un client spécifique (coté serveur), il suffit de cliquer sur le pseudo dans la listbox et d'envoyer le msg. J'essaie donc de garder une relation logique entre la listbox qui répertorie les arrivants du plus vieux (tout en haut) au plus récent (tout en bas) et les Serveur.Socket.Connections
    (On admet que le serveur est aussi un client donc il est ajouté dans la listbox)
    ainsi le premier élément (indice 0) est 'Serveur' lorsque l'on clique sur l'indice 1
    (si il y a) on enverra à l"Activeconnections[0]" le premier arrivé donc.

    Ceci marche très bien mais je n'ai aucune idée de procéder autrement si il ya des méthodes plus efficaces moins lourdes merci de me les indiquer. En outre, il pose 2 problèmes à résoudre:
    1- Lorsqu'un client se déco il faut virer le pseudo de la listbox et garder la relation logique avec les "Activeconnections".
    2- Si 2 clients se connectent successivement avec le même pseudo il faut renommer le second.

    Si quelqun a des idées... je suis preneur.

    Merci d'avoir lu !

Discussions similaires

  1. Socket en UDP - Multicast - Chat - Problème.
    Par ExSter dans le forum Entrée/Sortie
    Réponses: 14
    Dernier message: 02/09/2010, 13h48
  2. Utilisation des Socket pour un mini chat
    Par megamario dans le forum C++Builder
    Réponses: 2
    Dernier message: 17/11/2009, 14h05
  3. Refresh des données dans un logiciel de chat
    Par bruce-willis dans le forum Développement
    Réponses: 2
    Dernier message: 16/04/2009, 10h42
  4. Problème de connexion vocale sur logiciel de chat
    Par speedobetawatcher dans le forum Apple
    Réponses: 2
    Dernier message: 08/07/2007, 15h16
  5. [Conception][Socket]Conception d'un "chat"
    Par Pill_S dans le forum Entrée/Sortie
    Réponses: 7
    Dernier message: 12/09/2004, 02h41

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