Delphi程式實作Ping操作
張泰立
使用過網路的使用者都熟悉「Ping」這個指令,它是一個DOS下的可執行文件,一般用它來檢查網路連線的好壞程度。其基本原理是利用TCP/ip協定包中ICMP協定中的一個功能,即向所指定的計算機發送一個請求,收到請求的計算機返回一個應答,藉此來判斷該計算機是否在網上運行或者檢查網絡連接是否穩定可靠。在Ping程式執行過程中,雙方電腦所耗費的資源都很少,因此,它是一個非常實用的工具。
我們可以透過程式設計來實現「Ping」操作,加以改進,使其具有Windows的介面風格,顯示比DOS更直覺。
首先,對程式設計中需要的動態連結庫作一簡要說明:在Windows的System目錄下,你可以找到Icmp.dll文件,該動態連結庫提供了ICMP協定的所有功能,我們的程式就建立在對該動態連結庫的呼叫上。
Icmp.dll檔案內的呼叫函數說明如下:
1、IcmpCreateFile
打開一個句柄,透過該句柄你可以發送ICMP的請求回傳訊息。
2、IcmpCloseHandle
關閉你透過IcmpCreateFile函數開啟的句柄。
3、IcmpSendEcho
透過你開啟的句柄發送ICMP請求,在逾時或應答封包接收後回傳。其參數基本上和它的幀結構一致,可參考下面的程序部分,其具體含意你可以參看有關ICMP協議的書籍。
初步了解上述的三個函數後,我們就可以開始程式設計了。
首先,我們的程式運行後應該會有如圖1所示的基本功能。為此,我們可先在Delphi的視窗中放入右上圖所示的控件,如按鈕、編輯框和文字顯示框等。
(G72.JPG)
例程運行示意圖
然後,在程式的開始部分(FormCreate)對WinSocket進行初始化,其作用是申明使用的版本訊息,同時調入Icmp.dll函式庫。
type
PIPOptionInformation = ^TIPOptionInformation;
TIPOptionInformation = packed record
TTL: Byte;
TOS: Byte;
Flags: Byte;
OptionsSize: Byte;
OptionsData: PChar;
end;
PIcmpEchoReply = ^TIcmpEchoReply;
TIcmpEchoReply = packed record
Address: DWord;
Status: DWORD;
RTT: DWORD;
DataSize: Word;
Reserved: Word;
Data: Pointer;
Options: TIPOptionInformation;
end;
TIcmpCreateFile = function: THandle; stdcall;
TIcmpCloseHandle = function(IcmpHandle: THandle): Boolean; stdcall;
TIcmpSendEcho = function(IcmpHandle:THandle;
DestinationAddress: DWORD;
RequestData: Pointer;
RequestSize: Word;
RequestOptions: PIPOptionInformation;
ReplyBuffer: Pointer;
ReplySize: DWord;
Timeout: DWord
): DWord; stdcall;
TMyPing = class(TForm)
Panel1: TPanel;
Label1: TLabel;
PingEdit: TEdit;
ExeBtn: TButton;
Button2: TButton;
Button3: TButton;
StatusShow: TMemo;
PRocedure Button3Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure ExeBtnClick(Sender: TObject);
private
{ Private declarations }
hICMP: THANDLE;
IcmpCreateFile : TIcmpCreateFile;
IcmpCloseHandle: TIcmpCloseHandle;
IcmpSendEcho: TIcmpSendEcho;
public
{ Public declarations }
end;
procedure TMyPing.FormCreate(Sender: TObject);
var
WSAData: TWSAData;
hICMPdll: HMODULE;
begin
WSAStartup($101, WSAData);
// Load the icmp.dll stuff
hICMPdll := LoadLibrary('icmp.dll');
@ICMPCreateFile := GetProcAddress(hICMPdll, 'IcmpCreateFile');
@IcmpCloseHandle := GetProcAddress(hICMPdll, 'IcmpCloseHandle');
@IcmpSendEcho := GetProcAddress(hICMPdll, 'IcmpSendEcho');
hICMP := IcmpCreateFile;
StatusShow.Text := ';
StatusShow.Lines.Add('目的IP位址位元組數回傳時間(毫秒)');
end;
接下來,就要進行如下所示的Ping操作的實際編程過程了。
procedure TMyPing.ExeBtnClick(Sender: TObject);
var
IPOpt:TIPOptionInformation;// IP Options for packet to send
FIPAddress:DWORD;
pReqData,pRevData:PChar;
pIPE:PIcmpEchoReply;// ICMP Echo reply buffer
FSize: DWORD;
MyString:string;
FTimeOut:DWORD;
BufferSize:DWORD;
begin
if PingEdit.Text <> ' then
begin
FIPAddress := inet_addr(PChar(PingEdit.Text));
FSize := 40;
BufferSize := SizeOf(TICMPEchoReply) + FSize;
GetMem(pRevData,FSize);
GetMem(pIPE,BufferSize);
FillChar(pIPE^, SizeOf(pIPE^), 0);
pIPE^.Data := pRevData;
MyString := 'Hello,World';
pReqData := PChar(MyString);
FillChar(IPOpt, Sizeof(IPOpt), 0);
IPOpt.TTL := 64;
FTimeOut := 4000;
IcmpSendEcho(hICMP, FIPAddress, pReqData, Length(MyString), @IPOpt, pIPE, BufferSize, FTimeOut);
if pReqData^ = pIPE^.Options.OptionsData^ then
begin
StatusShow.Lines.Add(PChar(PingEdit.Text) + ' ' +IntToStr(pIPE^.DataSize) + ' ' +IntToStr(pIPE^.RTT));
end;
FreeMem(pRevData);
FreeMem(pIPE);
end
end;
透過上面的編程,我們就實現了Ping功能的介面操作。實際上,ICMP協定的功能還有很多,都可以透過Icmp.dll的函數呼叫來實現。