转: 使用过网络的用户都熟悉“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的窗口中放入右上图中所示的控件,如按钮、编辑框和文本显示框等。
然后,在程序的开始部分(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:IPOptionInformation;
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
// 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,FSiz e);
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的函数调用来实现。
一般用它来检查网络连接的好坏程度。其基本原理是利用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的窗口中放入右上图中所示的控件,如按钮、编辑框和文本显示框等。
然后,在程序的开始部分(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:IPOptionInformation;
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
// 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,FSiz e);
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的函数调用来实现。
解决方案 »
- 大家帮我看看,TidTCPServer在同时发送同一个文件包给客户端的时候,只能发其中一个,怎样才能支持同时给客户端发同一文件包??100分,急
- 【delphi面试题】【找工作中,倾家荡产求 delphi面试题,有题者请回贴,重谢!!!!! 】
- sizeof函数和size,CSDN上穷鬼也要提提问
- mysql+delphi的SQL查询问题,限制太多,比较难,高手请进
- 关于pas的结构的问题
- 圣诞快乐!请帮忙进来看看我这段代码怎么解决!!!!
- delphi 控制 word 增加一个表格时 , 能不能给这个表格起名称,访问表格时用名称访问
- 请教POS前台收银系统的功能菜单是用什么控件实现的
- 菜鸟求教
- 像蚂蚁那样
- 如何在dbgrid中添加多条数据?
- 大家好,小弟问一个有关DELPHI 中LISTVIEW的小问题,望大家不吝赐教!
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Ping, StdCtrls;type
TPingTstForm = class(TForm)
Ping1: TPing;
Label1: TLabel;
HostEdit: TEdit;
PingButton: TButton;
DisplayMemo: TMemo;
CancelButton: TButton;
procedure PingButtonClick(Sender: TObject);
procedure Ping1Display(Sender: TObject; Icmp: TObject; Msg: String);
procedure Ping1DnsLookupDone(Sender: TObject; Error: Word);
procedure CancelButtonClick(Sender: TObject);
procedure Ping1EchoRequest(Sender: TObject; Icmp: TObject);
procedure Ping1EchoReply(Sender: TObject; Icmp: TObject; Error: Integer);
private
{ D閏larations priv閑s }
public
{ D閏larations publiques }
end;var
PingTstForm: TPingTstForm;implementation{$R *.DFM}{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TPingTstForm.PingButtonClick(Sender: TObject);
begin
DisplayMemo.Clear;
DisplayMemo.Lines.Add('Resolving host ''' + HostEdit.Text + '''');
PingButton.Enabled := FALSE;
CancelButton.Enabled := TRUE;
Ping1.DnsLookup(HostEdit.Text);
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TPingTstForm.Ping1DnsLookupDone(Sender: TObject; Error: Word);
begin
CancelButton.Enabled := FALSE;
PingButton.Enabled := TRUE; if Error <> 0 then begin
DisplayMemo.Lines.Add('Unknown Host ''' + HostEdit.Text + '''');
Exit;
end; DisplayMemo.Lines.Add('Host ''' + HostEdit.Text + ''' is ' + Ping1.DnsResult);
Ping1.Address := Ping1.DnsResult;
Ping1.Ping;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TPingTstForm.Ping1Display(Sender: TObject; Icmp: TObject; Msg: String);
begin
DisplayMemo.Lines.Add(Msg);
end;{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TPingTstForm.CancelButtonClick(Sender: TObject);
begin
Ping1.CancelDnsLookup;
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TPingTstForm.Ping1EchoRequest(Sender: TObject; Icmp: TObject);
begin
DisplayMemo.Lines.Add('Sending ' + IntToStr(Ping1.Size) + ' bytes to ' +
Ping1.HostName + ' (' + Ping1.HostIP + ')');
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
procedure TPingTstForm.Ping1EchoReply(Sender: TObject; Icmp: TObject; Error: Integer);
begin
if Error = 0 then
DisplayMemo.Lines.Add('Cannot ping host (' + Ping1.HostIP + ') : ' +
Ping1.ErrorString)
else
DisplayMemo.Lines.Add('Received ' + IntToStr(Ping1.Reply.DataSize) +
' bytes from ' + Ping1.HostIP +
' in ' + IntToStr(Ping1.Reply.RTT) + ' msecs');
end;
{* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}end.
C:\Program Files\Borland\Delphi6\Demos\Indy\PingGUI