Delphi (XE2) Indy (10) 多线程 Ping [英] Delphi (XE2) Indy (10) Multithread Ping

查看:41
本文介绍了Delphi (XE2) Indy (10) 多线程 Ping的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个房间,里面有 60 台计算机/设备(40 台计算机和 20 台基于 Windows CE 的示波器),我想知道使用 ping 的每个人都活着.首先我写了一个标准的 ping(见这里 Delphi Indy Ping Error 10040),这是现在工作正常,但在大多数计算机离线时需要很长时间.

所以我想做的是写一个多线程 Ping,但我很挣扎.我在互联网上只看到了很少的例子,没有人符合我的需求,这就是我尝试自己编写的原因.

我使用 XE2 和 Indy 10,表单仅由备忘录和按钮组成.

unit Main;界面用途Winapi.Windows、System.SysUtils、System.Classes、Vcl.Forms、IdIcmpClient、IdGlobal、Vcl.StdCtrls、Vcl.Controls;类型TMainForm = 类(TForm)备忘录1:TMemo;ButtonStartPing: TButton;过程 ButtonStartPingClick(Sender: TObject);私人的{ 私人声明}上市{ 公开声明 }结尾;类型TMyPingThread = 类(TThread)私人的fIndex : 整数;fIdIcmpClient: TIdIcmpClient;程序 doOnPingReply;受保护程序执行;覆盖;上市构造函数创建(索引:整数);结尾;无功MainForm:TMainForm;线程数:整数;执行{$R *.dfm}构造函数 TMyPingThread.Create(index: integer);开始继承创建(假);fIndex := 索引;fIdIcmpClient := TIdIcmpClient.Create(nil);fIdIcmpClient.ReceiveTimeout := 200;fIdIcmpClient.PacketSize := 24;fIdIcmpClient.Protocol := 1;fIdIcmpClient.IPVersion := Id_IPv4;//第一台计算机在地址 211fIdIcmpClient.Host := '128.178.26.'+inttostr(211+index-1);self.FreeOnTerminate := true;结尾;程序 TMyPingThread.doOnPingReply;开始MainForm.Memo1.lines.add(inttostr(findex)+' '+fIdIcmpClient.ReplyStatus.Msg);十二月(线程数);如果 ThreadCount = 0 那么MainForm.Memo1.lines.add('--- End ---');结尾;过程 TMyPingThread.Execute;开始遗传;尝试fIdIcmpClient.Ping('',findex);除了结尾;虽然没有被终止做开始如果 fIdIcmpClient.ReplyStatus.SequenceId = findex 然后终止;结尾;同步(doOnPingReply);fIdIcmpClient.Free;结尾;过程 TMainForm.ButtonStartPingClick(Sender: TObject);无功i:整数;myPing : TMyPingThread;开始Memo1.Lines.Clear;线程数:= 0;对于 i := 1 到 40 做开始公司(线程计数);myPing := TMyPingThread.Create(i);//睡眠(10);结尾;结尾;结尾.

我的问题是,当我取消注释sleep(10)"时它似乎"起作用,而没有它似乎"不起作用.这肯定意味着我在编写的线程中遗漏了一点.

换句话说.当 Sleep(10) 在代码中时.每次我点击按钮去检查连接时,结果都是正确的.

如果没有 sleep(10),它大部分"时间都在工作,但有时结果是错误的,在离线计算机上给我一个 ping 回声,而在线计算机上没有 ping 回声,因为没有分配 ping 回复到正确的线程.

欢迎任何评论或帮助.

----- 编辑/重要 -----

作为对这个问题的一般跟进,@Darian Miller 开始了一个 此处的 Google 代码项目 https://code.google.com/p/delphi-stackoverflow/ 这是一个工作基础.我将他的答案标记为接受的答案",但用户应该参考这个开源项目(所有功劳归他所有),因为它将来肯定会得到扩展和更新.

解决方案

Remy 解释了这些问题...我想在 Indy 中这样做有一段时间了,所以我发布了一个可能的解决方案,我只是把它放在一个新的谷歌代码项目,而不是在这里有很长的评论.这是第一次尝试,如果您有一些更改要集成,请告诉我:https://code.google.com/p/delphi-vault/>

此代码有两种方法可以 Ping...多线程客户端,如您的示例中所示,或者使用简单的回调过程.为 Indy10 及更高版本的 Delphi 编写.

您的代码最终会使用定义 SynchronizedResponse 方法的 TThreadedPing 后代:

 TMyPingThread = class(TThreadedPing)受保护过程 SynchronizedResponse(const ReplyStatus:TReplyStatus);覆盖;结尾;

为了触发一些客户端线程,代码变成了这样:

procedure TfrmThreadedPingSample.butStartPingClick(Sender: TObject);开始TMyPingThread.Create('www.google.com');TMyPingThread.Create('127.0.0.1');TMyPingThread.Create('www.shouldnotresolvetoanythingatall.com');TMyPingThread.Create('127.0.0.1');TMyPingThread.Create('www.microsoft.com');TMyPingThread.Create('127.0.0.1');结尾;

线程响应在同步方法中调用:

procedure TMyPingThread.SynchronizedResponse(const ReplyStatus:TReplyStatus);开始frmThreadedPingSample.Memo1.Lines.Add(TPingClient.FormatStandardResponse(ReplyStatus));结尾;

I have a room with 60 computers/devices (40 computers and 20 oscilloscopes Windows CE based) and I would like to know which and every one is alive using ping. First I wrote a standard ping (see here Delphi Indy Ping Error 10040), which is working fine now but takes ages when most computers are offline.

So what I am trying to do is to write a MultiThread Ping but I am quite struggling with it. I have seen only very few examples over the internet and no one was matching my needs, that's why I try to write it myself.

I use XE2 and Indy 10 and the form is only constitued of a memo and a button.

unit Main;

interface

uses
  Winapi.Windows, System.SysUtils, System.Classes, Vcl.Forms,
  IdIcmpClient, IdGlobal, Vcl.StdCtrls, Vcl.Controls;

type
  TMainForm = class(TForm)
    Memo1: TMemo;
    ButtonStartPing: TButton;
    procedure ButtonStartPingClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  TMyPingThread = class(TThread)
  private
    fIndex : integer;
    fIdIcmpClient: TIdIcmpClient;
    procedure doOnPingReply;
  protected
    procedure Execute; override;
  public
    constructor Create(index: integer);
  end;

var
  MainForm: TMainForm;
  ThreadCOunt : integer;

implementation

{$R *.dfm}

constructor TMyPingThread.Create(index: integer);
begin
  inherited Create(false);

  fIndex := index;
  fIdIcmpClient := TIdIcmpClient.Create(nil);
  fIdIcmpClient.ReceiveTimeout := 200;
  fIdIcmpClient.PacketSize := 24;
  fIdIcmpClient.Protocol := 1;
  fIdIcmpClient.IPVersion := Id_IPv4;

  //first computer is at adresse 211
  fIdIcmpClient.Host := '128.178.26.'+inttostr(211+index-1);

  self.FreeOnTerminate := true;
end;

procedure TMyPingThread.doOnPingReply;
begin
  MainForm.Memo1.lines.add(inttostr(findex)+' '+fIdIcmpClient.ReplyStatus.Msg);
  dec(ThreadCount);

  if ThreadCount = 0 then
    MainForm.Memo1.lines.add('--- End ---');
end;

procedure TMyPingThread.Execute;
begin
  inherited;

  try
    fIdIcmpClient.Ping('',findex);
  except
  end;

  while not Terminated do
  begin
    if fIdIcmpClient.ReplyStatus.SequenceId = findex then Terminate;
  end;

  Synchronize(doOnPingReply);
  fIdIcmpClient.Free;
end;

procedure TMainForm.ButtonStartPingClick(Sender: TObject);
var
  i: integer;
  myPing : TMyPingThread;
begin
  Memo1.Lines.Clear;

  ThreadCount := 0;
  for i := 1 to 40 do
  begin
    inc(ThreadCount);
    myPing := TMyPingThread.Create(i);
    //sleep(10);
  end;
end;

end.

My problem is that it "seems" to work when I uncomment the "sleep(10)", and "seems" not to be working without it. This for sure means I am missing a point in the threading I have written.

In other words. When Sleep(10) is in the code. Every time I clicked the button to get to check the connections the result was correct.

Without the sleep(10), it is working "most" of the time but some times the result is wrong giving me a ping echo on offline computers and no ping echo on online computer, as is the ping reply was not assigned to the correct thread.

Any comment or help is welcome.

----- EDIT / IMPORTANT -----

As a general follow up of this question, @Darian Miller started a Google Code project here https://code.google.com/p/delphi-stackoverflow/ which is a working basis. I mark his answer as the "accepted answer" but users should refer to this open source project (all the credit belongs to him) as it will surely be extended and updated in the future.

解决方案

Remy explained the problems... I've wanted to do this in Indy for a while so I posted a possible solution that I just put together to a new Google Code project instead of having a long comment here. It's a first-stab sort of thing, let me know if you have some changes to integrate: https://code.google.com/p/delphi-vault/

This code has two ways to Ping...multi-threaded clients as in your example, or with a simple callback procedure. Written for Indy10 and later versions of Delphi.

Your code would end up using a TThreadedPing descendant defining a SynchronizedResponse method:

  TMyPingThread = class(TThreadedPing)
  protected
    procedure SynchronizedResponse(const ReplyStatus:TReplyStatus); override;
  end;

And to fire off some client threads, the code becomes something like:

procedure TfrmThreadedPingSample.butStartPingClick(Sender: TObject);
begin
  TMyPingThread.Create('www.google.com');
  TMyPingThread.Create('127.0.0.1');
  TMyPingThread.Create('www.shouldnotresolvetoanythingatall.com');
  TMyPingThread.Create('127.0.0.1');
  TMyPingThread.Create('www.microsoft.com');
  TMyPingThread.Create('127.0.0.1');
end;

The threaded response is called in a synchronized method:

procedure TMyPingThread.SynchronizedResponse(const ReplyStatus:TReplyStatus);
begin
  frmThreadedPingSample.Memo1.Lines.Add(TPingClient.FormatStandardResponse(ReplyStatus));
end;

这篇关于Delphi (XE2) Indy (10) 多线程 Ping的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆