[英]Delphi: Indy TIdTCPClient Reading Data
我正在使用Delphi 2007和Indy 10; 如果我錯過了一些顯而易見的東西,我會有點像德爾福的菜鳥道歉
背景:我有一個簡單的服務器應用程序,只需在連接到其端口時發送單詞“PING”。 如果收到“PONG”字樣,它也會回復。 這工作正常,我已經使用netcat / wireshark手動測試了這個。
我正在嘗試編寫我的客戶端以連接到端口,並在收到它時自動響應PING一詞。 我創建了一個帶有手動連接按鈕的簡單表單。
客戶端連接,但它不響應PING這個詞。 我認為問題在於:
TLog.AddMsg(FConn.IOHandler.ReadLn);
我的調試日志僅報告“DEBUG:TReadingThread.Execute - FConn.Connected”。
我的客戶代碼:
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.
任何幫助/建議將不勝感激。
謝謝
讀取線程直接訪問Form1.Memo1
,它不是線程安全的,可能導致死鎖,崩潰,內存損壞等。因此讀取線程甚至可能根本沒有到達ReadLn()
調用。 無論訪問實際上多么微不足道,您必須將對UI控件的所有訪問同步到主線程。 只是不要冒險。
此外,您正在TLog
本身內部執行線程的ping / pong邏輯,它不屬於它。 更不用說在檢查其值之前將cmd
截斷為僅第一個字符,因此它永遠不會檢測到PING
命令。 您需要將邏輯移回到它真正屬於的線程中,並刪除截斷。
嘗試這個:
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;
procedure DoTerminate; 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
TLog.AddMsg('DEBUG: TReadingThread.Create');
FConn := AConn;
inherited Create(False);
end;
procedure TReadingThread.Execute;
var
cmd: string;
begin
TLog.AddMsg('DEBUG: TReadingThread.Execute');
while not Terminated do
begin
cmd := FConn.IOHandler.ReadLn;
TLog.AddMsg('DEBUG: TReadingThread.Execute. Cmd: ' + cmd);
if cmd = 'PING' then begin
FConn.IOHandler.WriteLn('PONG');
end
end;
end;
procedure TReadingThread.DoTerminate;
begin
TLog.AddMsg('DEBUG: TReadingThread.DoTerminate');
inherited;
end;
constructor TLog.Create(const AMsg: String);
begin
inherited Create;
FMsg := AMsg;
end;
procedure TLog.DoSynchronize;
begin
Form1.Memo1.Lines.Add(FMsg);
end;
class procedure TLog.AddMsg(const AMsg: String);
begin
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;
try
client.Connect;
except
on E: Exception do
TLog.AddMsg('Error: ' + E.Message);
end;
end;
end;
procedure TForm1.clientConnected(Sender: TObject);
begin
TLog.AddMsg('DEBUG: TForm1.clientConnected');
rt := TReadingThread.Create(client);
end;
procedure TForm1.clientDisconnected(Sender: TObject);
begin
TLog.AddMsg('DEBUG: TForm1.clientDisconnected');
if rt <> nil then
begin
rt.Terminate;
rt.WaitFor;
FreeAndNil(rt);
end;
end;
end.
如果仍然不起作用,那么請確保服務器實際上使用CRLF
序列或至少一個LF
字符(這是默認情況下ReadLn()
查找的最小字符)分隔PING
字符串。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.