スレッドを使用してPINGを飛ばすには?


迷える子羊  2004-04-28 19:07:06  No: 8747

お久しぶりになります。
よろしくお願いします.

現在  192.168.1.1〜192.168.1.254
まで、IndyClient  の  IdIcmpClient  を使用して
デフォルトのタイムアウトを5000(msec) から1000(msec)  
に設定してPING処理をしていますが、
接続されていない端末の数にもよると思いますが、
処理が終わるのに  2分40秒ほどかかりました.

そこで、TThread (スレッド)等を使用すると
254台同時にチェック処理するので1秒足らずで処理がおわるのでは
ないのでしょうか?
と思っているのですが、TThread の使用方法がわかりません。

そこで質問ですが、
192.168.1.1〜192.168.1.254に対して
Pingをとばして確認するのにもっとも処理時間を短縮して
なおかつ、精度を下げずに(タイムアウトを1msecにするとかでなく)
処理する方法を教えてください。

目的は、ネットワークに接続されている各PCが
電源が入っているかどうかを確認するプログラムを作成
したいのです。

よろしくお願いします.


スタテツ  2004-04-29 00:57:53  No: 8748

こんにちわです。
Indyは少し興味があったのでちょびっとだけテストしてみました。
実際の運用の際はスレッド内を適当にsyncronizeしてあげてください。
テストする際下手な値を入れるとネットワーク管理者に怒られますぞ。

>//-------------------------------------------------------------------------
>//メインフォーム Unit1.pas
>//-------------------------------------------------------------------------
uses に PingThreadを追加
Button1,Edit1,ListBox1

procedure TForm1.Button1Click(Sender: TObject);
var
pthread:array [0..255] of TPingThread;
i:integer;
bufstr:string;
begin
for i:=0 to 20 do //多すぎるとOS止まります
begin
  pthread[i]:=TPingThread.Create(True);
  pthread[i].IdIcmpClient1:=TIdIcmpClient.Create(self);
  bufstr:=Edit1.Text + inttostr(i); //Edit1.text:='***.***.***.'
  pthread[i].IdIcmpClient1.Host:=bufstr;
  pthread[i].Resume;
end;

>//-------------------------------------------------------------------------
>//スレッド PingThread.pas
>//-------------------------------------------------------------------------
unit PingThread;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, IdBaseComponent, IdComponent, IdRawBase, IdRawClient,
  IdIcmpClient;

type
  TPingThread = class(TThread)
  private
    { Private 宣言 }
    procedure IdIcmpClient1Reply(ASender: TComponent; const AReplyStatus: TReplyStatus);
  public
    IdIcmpClient1: TIdIcmpClient;
  protected
    procedure Execute; override;
  end;

implementation

uses Unit1;

{ TPingThread }

procedure TPingThread.Execute;
begin
  IdIcmpClient1.OnReply:=IdIcmpClient1Reply;
  IdIcmpClient1.Ping;
end;

procedure TPingThread.IdIcmpClient1Reply(ASender: TComponent;
  const AReplyStatus: TReplyStatus);
begin
  //本当はマズイ
  Form1.ListBox1.Items.Add(AReplyStatus.FromIpAddress);
  IdIcmpClient1.Free;
end;

end.
>//-------------------------------------------------------------------------


HPW  2004-04-29 16:34:16  No: 8749

ピーマコ : 「スレッド使うと255台のPCに一気にPING送信出来ると思ったら、ダメですよね〜」
なかざわ : 「使うてるOSはなんやねん?」
オジャマ : 「ピーマコさん、まだWin98なんですよ」
なかざわ : 「それやったらスレッド数は30くらいが限度やな。まぁ、1〜20、21〜40…と分けて実行しても30秒くらいで全部終わるンちゃうか?」
オジャマ : 「わたしのWin2000だったらどうなんですか〜?」
なかざわ : 「聞くよりやってみればエエやん」
オジャマ : 「うわ〜、255個のスレッドでPING送信出来ちゃいました〜 TimeOutが5000msでも5秒くらいで全部応答完了です♪」
ピーマコ : 「でもスレッド使うと応答順序がバラバラですよ〜、送信順にならないですか〜?」
なかざわ : 「ListView使うたら自動ソートのプロパティあるやんか」
ピーマコ : 「あっ、そうですネ…忘れてましたぁ…」
オジャマ : 「VCLってスレッド実行中に使う時は やっぱりSynchronizeでスレッド停止しないとダメなんですか〜? チョット面倒みたいなぁ…」
なかざわ : 「スレッドのOnTerminateイベントで表示せな〜。ンならナンも問題あらへんで」
オジャマ : 「あっ!、そんな手があったんですか〜」
ピーマコ : 「ところで…255個もスレッド使っちゃって、OSはホントに大丈夫なんですか〜?」
なかざわ : 「心配なら、Priority := tpLower; とか追加しといてレベル下げといてや」
ピーマコ : 「ナルホド…、それじゃぁ…ナカザワさんも、そろそろ理想の相手のレベル下げとかないとヤバイですかね〜」
なかざわ : 「ほっとけ!」


迷える子羊  2004-05-07 01:26:58  No: 8750

スタテツさん、HPW さん
どうもありがとうございます.
当方システムOSはWindows2000です。

プログラムを実行してみました.

結果>>
フォーム上にパネルを254個用意し、
TPanel を配列でせんげんしました。
そして、192.168.1.1〜192.168.1.254 までPingを実行しました。
TPingThreadクラスにTagプロパティを追加して、
以下のように呼び出しました.

  for i:=1 to 254 do begin
    pthread[i]  := TPingThread.Create(True);
    pthread[i].Priority  := tpLowest;
    pthread[i].IdIcmpClient := TIdIcmpClientPing.Create(self);
    pthread[i].IdIcmpClient.ReceiveTimeout := 5000;
    pthread[i].IdIcmpClient.Host := '192.168.1.' + IntToStr(i);
    pthread[i].Tag := i;
    pthread[i].Resume;
  end;

スレッドユニットでは以下のようにしました。
procedure TPingThread.Execute;
begin
  IdIcmpClient.OnReply := IdIcmpClientReply;
  IdIcmpClient.Ping;
end;

procedure TPingThread.IdIcmpClientReply(ASender: TComponent; const AReplyStatus: TReplyStatus);
var
  S: String;
begin
  if AReplyStatus.FromIpAddress = '192.168.1.' + IntToStr(Tag) then begin
    Form1.ViewPanel[Tag].Color := clBlue;
  end else begin
    Form1.ViewPanel[Tag].Color := clRed;
  end;
  IdIcmpClient.Free;
end;

以上のプログラムを作成してみましたが、
実際  AReplyStatus.FromIpAddress  に入ってくるアドレスの値(文字列)が
違っているようで、実際には電源が入っているのに赤くなります。
電源の入っていないものが青くなることはありませんでした.

そこで、Syncronize 等を使用すればいけるのだろうと思いますが、
その方法がわかりません。

どうすればよいのでしょうか?
よろしくお願いします.


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加