简体   繁体   English

Delphi 7 + Indy +多线程客户端

[英]Delphi 7 + Indy + Multithread clients

My PC is connected to two electronic devices that send data using a TCP connection. 我的PC已连接到两个使用TCP连接发送数据的电子设备。 I would like to develop a Delphi program able to log all this data. 我想开发一个能够记录所有这些数据的Delphi程序。 In the following code I create two TCPClients using two threads. 在下面的代码中,我使用两个线程创建两个TCPClient。 I am able to log data from one device using one thread, but when two threads are runnning the application freezes. 我可以使用一个线程从一台设备记录数据,但是当运行两个线程时,应用程序冻结。 I don´t have experience programming in Delphi, sorry if there are too many mistakes... I am using Delphi 7. What can I do to avoid freezing the app? 我没有使用Delphi编程的经验,如果有太多错误,抱歉...我正在使用Delphi7。如何避免冻结该应用程序?

Thanks in advance 提前致谢

//************************************************************************//
type TThreadConn1 = class(TThread)
    private
    protected
        procedure Execute; override;
    end;

type TThreadConn2 = class(TThread)
    private
    protected
        procedure Execute; override;
    end;


var
    Form1: TForm1;
    TCP1: TThreadConn1;
    TCP2: TThreadConn2;
    flag1: bool;
    flag2: bool;


implementation
{$R *.dfm}

//******************************Connection 1******************************//
procedure TThreadConn1.Execute;  //Connect+loop read buffer+disconnect
begin
    Form1.IdTCPClient1.Connect;  
    While flag1 = false do   
        Form1.IdTCPClient1.CurrentReadBuffer;
    Form1.IdTCPClient1.Disconnect;
end; 

procedure TForm1.ButtonConnection1Click(Sender: TObject);
begin
    flag1:=false;
    TCP1 := TThreadConn1.Create(false);  //Launch thread 
end;

procedure TForm1.ButtonDisconnection1Click(Sender: TObject);
begin
    flag1:=true;
    if (TCP1.Terminated = false) then
        TCP1.Terminate;   //Is it ok to finish this way a thread?
    end;

//******************************Connection2******************************//
procedure TThreadConn2.Execute;  //Connect+loop read buffer+disconnect
begin
    Form1.IdTCPClient2.Connect;
    While flag2 = false do   
        Form1.IdTCPClient1.CurrentReadBuffer;
    Form1.IdTCPClient2.Disconnect;
end; { of procedure }

procedure TForm1.ButtonConnection2Click(Sender: TObject);
begin
    flag2:=false;
    TCP2 := TThreadConn2.Create(false);
end;

procedure TForm1.ButtonDisconnection2Click(Sender: TObject);
begin
    flag2:=true;
    if (TCP2.Terminated = false) then
        TCP2.Terminate;
end;
end.

You don't need to create two separate threads that do the same thing. 您不需要创建两个单独的线程来执行相同的操作。 Create one class and then instantiate multiple copies of it. 创建一个类,然后实例化它的多个副本。 Try this instead: 尝试以下方法:

type
  TThreadConn = class(TThread)
  private
    FClient: TIdTCPClient;
  protected
    procedure Execute; override;
  public
    constructor Create(AClient: TIdTCPClient);
  end;

var
  TCP1: TThreadConn = nil;
  TCP2: TThreadConn = nil;

constructor TThreadConn.Create(AClient: TIdTCPClient);
begin
  inherited Create(False);
  FClient := AClient;
end;

procedure TThreadConn.Execute;
begin
  FClient.Connect;  
  try
    while Terminated = false do   
      FClient.CurrentReadBuffer;
  finally
    FClient.Disconnect;
  end;
end; 

procedure TForm1.ButtonConnection1Click(Sender: TObject);
begin
  TCP1 := TThreadConn.Create(TIdTCPClient1);
end;

procedure TForm1.ButtonDisconnection1Click(Sender: TObject);

begin if (TCP1 <> nil) then begin TCP1.Terminate; 如果(TCP1 <> nil)开始,则开始TCP1.Terminate; TCP1.WaitFor; TCP1.WaitFor; FreeAndNil(TCP1); FreeAndNil(TCP1); end; 结束; end; 结束;

procedure TForm1.ButtonConnection2Click(Sender: TObject);

begin TCP2 := TThreadConn.Create(IdTCPClient2); 开始TCP2:= TThreadConn.Create(IdTCPClient2); end; 结束;

procedure TForm1.ButtonDisconnection2Click(Sender: TObject);
begin
  if (TCP2 <> nil) then
  begin
    TCP2.Terminate;
    TCP2.WaitFor;
    FreeAndNil(TCP2);
  end;
end;

Apart from the overall design, (which you will probably fix in time, maybe with some more help), in TThreadConn2 .Execute, you call Form1. 除了总体设计(您可能会及时修复,也许需要更多帮助)之外,在TThreadConn2中 。执行时,您调用Form1。 IdTCPClient1 .CurrentReadBuffer. IdTCPClient1 .CurrentReadBuffer。

Hints: 提示:

If you want to use threads to communicate with several different clients, don't plonk TidTCPClients onto forms. 如果要使用线程与多个不同的客户端进行通信,请不要将TidTCPClients插入表单。 This is inflexible because every time you want to add a new client, you have to plonk another instance onto the form and rebuild. 这是不灵活的,因为每次您要添加新客户端时,都必须将另一个实例插入到表单中并进行重建。 It also makes for a lot of extra work to get your app to shut down cleanly which, I assure you, you will not want. 它还使您需要进行大量额外的工作才能完全关闭应用程序,我向您保证,您将不希望这样做。

Dynamically create a TidTCPClient instance in either the TThread descendant ctor or at the top of the 'Execute' method. 在TThread的后代ctor或“ Execute”方法的顶部动态创建一个TidTCPClient实例。

Try and declare one class that can be instantiated for each client connection, so you don't have to copy/paste code, edit it and and get it wrong 尝试声明一个可以为每个客户端连接实例化的类,这样您就不必复制/粘贴代码,对其进行编辑并可以将其弄错。

Oh - for now, don't try and terminate the threads at all. 哦-现在,不要尝试终止线程。 In fact, forever, don't try and terminate the threads at all. 实际上,永远不要尝试终止线程。 In the execute, loop around connect() until successful, then read stuff in a loop, write to log, (in a thread-safe manner). 在execute中,围绕connect()循环直到成功,然后循环读取内容,写入日志(以线程安全的方式)。 Do that forever. 永远做到这一点。 If you wnat to stop the logging, set a 'don't log' boolean so that the thread still runs but simply doesn't bother calling the logger. 如果您必须停止记录,请设置一个“不记录”布尔值,以便线程仍在运行,但根本不会打扰记录器。 Again - don't go near trying to terminate the threads. 再说一遍-不要试图终止线程。

If I get a chance over the weekend, I'll do a simple example - one form, four TEdits for two pair hostname/port and two TMemos to send data to and display data from the server. 如果周末有机会,我将举一个简单的例子-一种形式,两个主机名/端口对的四个TEdit和两个TMemo,用于向服务器发送数据和从服务器显示数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM