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

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    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
    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 confirmé 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
    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 : 55
    Localisation : France, Hauts de Seine (Île de France)

    Informations forums :
    Inscription : Juin 2004
    Messages : 2 932
    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 confirmé
    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
    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 : 55
    Localisation : France, Hauts de Seine (Île de France)

    Informations forums :
    Inscription : Juin 2004
    Messages : 2 932
    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 confirmé
    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
    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 confirmé
    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
    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

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, 12h48
  2. Utilisation des Socket pour un mini chat
    Par megamario dans le forum C++Builder
    Réponses: 2
    Dernier message: 17/11/2009, 13h05
  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, 09h42
  4. Problème de connexion vocale sur logiciel de chat
    Par speedobetawatcher dans le forum Apple
    Réponses: 2
    Dernier message: 08/07/2007, 14h16
  5. [Conception][Socket]Conception d'un "chat"
    Par Pill_S dans le forum Entrée/Sortie
    Réponses: 7
    Dernier message: 12/09/2004, 01h41

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