Delphi: Indy TIdTCPClient De La Lecture Des Données
Je suis à l'aide de Delphi 2007 & Indy 10; je suis un peu Delphi noob alors, toutes mes excuses si j'ai manqué quelque chose d'évident...
Contexte: j'ai une simple application serveur qui envoie simplement le mot "PING" lorsque vous vous connectez à son port. Il permettra également de répondre s'il reçoit le mot "PONG". Cela fonctionne bien, j'ai manuellement testé cela en utilisant netcat/wireshark.
Je suis en train de code à mon client de se connecter au port et automatiquement à répondre à la parole de PING à chaque fois qu'il reçoit. J'ai créé un formulaire simple avec un bouton pour se connecter manuellement.
Le client se connecte, mais il ne répond pas à la parole de PING.
Je pense que le problème se trouve avec:
TLog.AddMsg(FConn.IOHandler.ReadLn);
Mon journal de débogage rapports seulement dans la mesure où "DEBUG: TReadingThread.Exécuter - FConn.Connecté".
Mon code client:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdCustomTransparentProxy, IdSocks, IdBaseComponent,
IdComponent, IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack,
IdTCPConnection, IdTCPClient, IdSync;
type
TReadingThread = class(TThread)
protected
FConn: TIdTCPConnection;
procedure Execute; override;
public
constructor Create(AConn: TIdTCPConnection); reintroduce;
end;
TLog = class(TIdSync)
protected
FMsg: String;
procedure DoSynchronize; override;
public
constructor Create(const AMsg: String);
class procedure AddMsg(const AMsg: String);
end;
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
IdIOHandlerStack1: TIdIOHandlerStack;
client: TIdTCPClient;
IdSocksInfo1: TIdSocksInfo;
procedure Button1Click(Sender: TObject);
procedure clientConnected(Sender: TObject);
procedure clientDisconnected(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
rt: TReadingThread = nil;
implementation
{$R *.dfm}
constructor TReadingThread.Create(AConn: TIdTCPConnection);
begin
Form1.Memo1.Lines.Add('DEBUG: TReadingThread.Create'); // Debug
FConn := AConn;
inherited Create(False);
end;
procedure TReadingThread.Execute;
begin
Form1.Memo1.Lines.Add('DEBUG: TReadingThread.Execute'); // Debug
while not Terminated and FConn.Connected do
begin
Form1.Memo1.Lines.Add('DEBUG: TReadingThread.Execute - FConn.Connected'); // Debug
TLog.AddMsg(FConn.IOHandler.ReadLn);
end;
end;
constructor TLog.Create(const AMsg: String);
begin
Form1.Memo1.Lines.Add('DEBUG: TLog.Create'); // Debug
FMsg := AMsg;
inherited Create;
end;
procedure TLog.DoSynchronize;
var
cmd : string;
begin
Form1.Memo1.Lines.Add('DEBUG: TLog.DoSynchronize'); // Debug
cmd := copy(FMsg, 1, 1);
if cmd='PING' then begin
Form1.client.Socket.WriteLn('PONG');
end
end;
class procedure TLog.AddMsg(const AMsg: String);
begin
Form1.Memo1.Lines.Add('DEBUG: TLog.AddMsg'); // Debug
with Create(AMsg) do try
Synchronize;
finally
Free;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Clear;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Host : String;
Port : Integer;
begin
Host := '127.0.0.1';
Port := StrToInt('1234');
client.Host := Host;
client.Port := Port;
with client do
begin
try
Connect;
except
on E: Exception do
Memo1.Lines.Add('Error: ' + E.Message);
end;
end;
end;
procedure TForm1.clientConnected(Sender: TObject);
begin
Form1.Memo1.Lines.Add('DEBUG: TForm1.clientConnected'); // Debug
rt := TReadingThread.Create(client);
end;
procedure TForm1.clientDisconnected(Sender: TObject);
begin
Form1.Memo1.Lines.Add('DEBUG: TForm1.clientDisconnected'); // Debug
if rt <> nil then
begin
rt.Terminate;
rt.WaitFor;
FreeAndNil(rt);
end;
end;
end.
Toute aide/conseil serait apprécié.
Grâce
PONG, le serveur bandes nouvelle ligne de flux, etc
OriginalL'auteur Jamie Wright | 2013-06-28
Vous devez vous connecter pour publier un commentaire.
Le thread de lecture est directement accès à
Form1.Memo1
, ce qui n'est pas thread-safe et peut provoquer des blocages, des accidents, des corrompus de la mémoire, etc. Donc il est possible que le thread de lecture n'est pas à même d'atteindre laReadLn()
appel à tous. Vous DOIT synchroniser TOUS l'accès à des contrôles d'INTERFACE utilisateur pour le thread principal, peu importe comment trivial l'accès est réellement. Il suffit de ne pas prendre le risque.Aussi, vous faites de votre fil de ping/pong logique à l'intérieur de
TLog
lui-même, où il n'appartient pas. Pour ne pas mentionner que vous êtes en tronquant lecmd
à seulement son premier personnage avant de vérifier sa valeur, de sorte qu'il sera JAMAIS détecter unPING
de commande. Vous avez besoin de déplacer la logique de retour sur le fil, où il appartient vraiment, et de supprimer la troncature.Essayez ceci:
Si cela ne fonctionne toujours pas, alors assurez-vous que le serveur est en fait la délimitation de la
PING
chaîne avec unCRLF
séquence, ou au moins unLF
personnage (qui est le minimum queReadLn()
recherche par défaut).OriginalL'auteur Remy Lebeau