Probleme de reception de texte avec TClientSocket

Résolu
obitskater Messages postés 45 Date d'inscription lundi 29 janvier 2007 Statut Membre Dernière intervention 13 mars 2009 - 22 mars 2007 à 12:44
obitskater Messages postés 45 Date d'inscription lundi 29 janvier 2007 Statut Membre Dernière intervention 13 mars 2009 - 23 mars 2007 à 09:56
Bonjour à tous.
Je suis en train de développer un chat au moyen des composants TserverSocket et TclientSocket tous les deux présents sur la même form, ainsi un utilisateur peut héberger une conversation au moyen du TserverSocket ou rejoindre une conversation existante au moyen du TClientSocket.

Jusque là le principe de chat en lui même fonctionne parfaitement. Maintenant je rencontre un problème car je suis en train de gérer l'affichage des personnes connectés sur une même conversation dans un TMemo (son nom est "actif"), ceci se passe de la manière suivante (bien entendu ces personnes sont déjà connectés à la conversation concernée):

// pseudo est une variable globale qui contient le pseudo de la personne qui utilise le chat (qui diffèrent donc de chaque utilisation)

//envoie au serveur du pseudo de la personne qui vient de se connecter
procedure TForm2.ClientSocket1Connect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  ClientSocket1.Socket.sendText('$*!*$'+pseudo);
end;

//Envoie au nouveau connecté de la liste des personnes déjà connecté

procedure envoieConnectes();
var
  intermediaire : string;
  i, last :integer;

begin
with form2 do
 begin
   last:= ServerSocket1.Socket.ActiveConnections-1;
   for i:= 2 to actif.Lines.Count-1 do //on commence à 2 car les 2 premières lignes du memo ne changent jamais
   begin
      //showmessage('actif '+actif.Lines.strings[i]);
      intermediaire: =actif.lines.strings[i];
      ServerSocket1.Socket.Connections[last].SendText('$*!*$'+intermediaire);//on ajoute $*!*$ à la chaine pour signifier au client d'afficher cette string dans la fenetre des personnes connectés et non dans la fenetre de chat principale
      intermediaire:= '';
   end;
 end;
end;

//Gestion de la nouvelle connexion d'un client
procedure TForm2.ServerSocket1ClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
    Champ.selattributes.Color : = clblue; // champ est le TRichEdit qui affiche tous les messages du chat
    Champ.Lines.Add('******** Connexion d''un client acceptée par le serveur ********');
    Champ.selattributes.Color := clblack;
    envoieConnectes();
end;

//envoie des infos récupérer par le serveur à tous ses clients
procedure TForm2.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var i : integer;
    phrase : string;
begin

  phrase: =Socket.ReceiveText;

  for i:= 0 to ServerSocket1.Socket.ActiveConnections-1 do
  begin
    ServerSocket1.Socket.Connections[i].SendText(phrase);
  end;
end;

//Récupération du client des données envoyés par le serveur
procedure TForm2.ClientSocket1Read(Sender: TObject;
  Socket: TCustomWinSocket);
var
   pseud, recu : string;
   p,p2: integer;
begin

  recu:=Clientsocket1.Socket.ReceiveText;
  p2:=pos('$*!*$', recu);

  if p2>0 then //On verifie que le message reçu doit être affiché dans la fenetre des personnes connectés ou si c'est seulement un message de chat à afficher dans la fenetre principale de chat
   begin
     recu: =copy(recu, p2+5, length(recu));
     if recu<>pseudo then
       actif.lines.add(recu);
   end
  else
   begin
     p:=pos('dit :', recu);
     pseud:=copy(recu, 0, p-2);
     if pseud=pseudo then
        Champ.SelAttributes.Style:=[fsbold];
     Champ.Lines.add(recu);
     Champ.Lines.add('');
     Champ.SelAttributes.Style:=Champ.SelAttributes.Style-[fsbold];
     SendMessage(Champ.Handle, WM_VScroll, SB_BOTTOM, 0);
   end;
end;

Donc mon problème est que une fois sur deux les noms des personnes connectés envoyés par le serveur dans la boucle for de la procédure envoieConnectes (en vert) ne sont reçus qu'en un seul bloc par le client.
C'est à dire si les noms suivants sont connectés : toto, tutux, et que le nouveau connectés s'appelle gilou, il ne reçoit qu'une chaîne de caractères : $*!*$toto$*!*$tutux$*!*$gilou
Et cela au lieu de 3 chaines distinctes   $*!*$tutux$*!*$gilou
Ce qui fait donc totalement foiré mon affichage!!!
Mais lorsque je met le showmessage (en rouge) dans cette même boucle, tout marche nikel!!!
Donc je me demande si cela ne vient pas d'un écart de temps trop réduit entre l'envoie des différentes chaines et la réception, mais même avec un sleep ça ne marche pas, donc je suis un peu perdu...

Merci d'avance pour votre aide!

2 réponses

WhiteHippo Messages postés 1154 Date d'inscription samedi 14 août 2004 Statut Membre Dernière intervention 5 avril 2012 3
22 mars 2007 à 20:09
Bonsoir

Le problème me semble t-il ne se situe pas du côté de l'envoi mais plutôt du côté de la réception.
Il est normal que tu reçoives toutes les chaines les unes derrières les autres (Le socket gère un buffer qui emmagasine les données les unes derrières les autres, c'est pourquoi les données sont reçues également de la même façon).
Il faut donc simplement les décomposer correctement.

Une solution simple serait par exemple de rajouter une retour à la ligne (const CRLF = #13#10;) en fin de chacune des chaines à envoyer :
  intermediaire:=actif.lines.strings[i] + CRLF ;

Ensuite, il suffit de déterminer chacune des chaines reçues qui commencerons toutes par '$*!*$' et se terminerons par CRLF. Ce qui donnera '$*!*$toto'+CLRF+'$*!*$tutux'+CLRF+'$*!*$gilou'+CLRF.

N.B. Lors de la reception, il ne faudra donc tenir compte que des chaines complètes, c'est à dire satisfaisant aux 2 conditions ci-dessus. Par exemple dans le cas d'un envoi de 10000 connexions (ça c'est du chat ) tout ne sera pas envoyer en une seule fois (dépend de la taille du tampon), et donc un nom pourra être séparé dans 2 trames :
  Trame 1 = '$*!*$toto'+CLRF+'$*!*$tutux'+CLRF+'$*!*$gil'

  Trame 2 = 'ou'+CLRF
Si tel n'est pas le cas, c'est que le socket n'a pas tout reçu, il faudra alors attendre la reception des données manquantes, et les concaténer avec les précédentes (Prévoir la gestion d'un TimeOut en cas d'erreur de reception est alors OBLIGATOIRE!)

Cordialement.
<hr />"L'imagination est plus importante que le savoir." Albert Einstein
3
obitskater Messages postés 45 Date d'inscription lundi 29 janvier 2007 Statut Membre Dernière intervention 13 mars 2009
23 mars 2007 à 09:56
Trés bonne solution merci beaucoup! Je teste ça de suite!
0
Rejoignez-nous