gpt4 book ai didi

multithreading - Delphi:Indy TIdTCPClient 读取数据

转载 作者:行者123 更新时间:2023-12-03 15:43:18 29 4
gpt4 key购买 nike

我正在使用 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 分隔 PING 字符串code> 字符(这是 ReadLn() 默认查找的最小值)。

关于multithreading - Delphi:Indy TIdTCPClient 读取数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17372366/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com