obitskater
Messages postés45Date d'inscriptionlundi 29 janvier 2007StatutMembreDernière intervention13 mars 2009
-
22 mars 2007 à 12:44
obitskater
Messages postés45Date d'inscriptionlundi 29 janvier 2007StatutMembreDernière intervention13 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
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...
WhiteHippo
Messages postés1154Date d'inscriptionsamedi 14 août 2004StatutMembreDernière intervention 5 avril 20123 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