網(wǎng)絡(luò)通訊中經(jīng)常需要確定遠程主機是否存活,以決定下一部進行的操作。可以直接使用ICMP協(xié)議來實現(xiàn),但是要考慮許多協(xié)議細節(jié),實現(xiàn)起來比較麻煩。Windows 自帶的ICMP庫里有現(xiàn)成的函數(shù)可以使用,只要在使用前填充相應(yīng)的數(shù)據(jù)結(jié)構(gòu)就可以了。
以下是要使用的數(shù)據(jù)結(jié)構(gòu)。這些結(jié)構(gòu)MSDN里有C形式的聲明,這里給出的是Delphi的形式。
//用到的協(xié)議數(shù)據(jù)結(jié)構(gòu) PIPOptionInfo = ^TIPOptionInfo; // IP 頭選項 TIPOptionInfo = packed record TTL: Byte;//存活時間 TOS: Byte;//Type of Service,請求類型 Flags: Byte;//標志 OptionsSize: Byte;//選項長度 OptionsData: PChar;//選項數(shù)據(jù) end; PIcmpEchoReply = ^TIcmpEchoReply; TIcmpEchoReply = packed record // ICMP 返回信息 Address: DWORD;//IP地址 Status: DWORD;//狀態(tài) RTT: DWORD; DataSize: Word;//數(shù)據(jù)長度 Reserved: Word;//保留 Data: Pointer;//數(shù)據(jù) Options: TIPOptionInfo;//選項區(qū) end;
//動態(tài)庫中的函數(shù)聲明 TIcmpCreateFile = function: THandle; stdcall; //創(chuàng)建ICMP句柄 TIcmpCloseHandle = function(IcmpHandle: THandle): Boolean; stdcall; //關(guān)閉ICMP句柄 TIcmpSendEcho = function(IcmpHandle:THandle; DestinationAddress:DWORD; RequestData:Pointer; RequestSize:Word; RequestOptions:PIPOptionInfo; ReplyBuffer:Pointer; ReplySize:DWord; Timeout:DWord):DWord; stdcall;//發(fā)送ICMP探測數(shù)據(jù)報
//要用到的變量聲明 hICMPDll,hICMP:THandle; wsaData:TWSADATA; ICMPCreateFile:TICMPCreateFile; IcmpCloseHandle:TIcmpCloseHandle; IcmpSendEcho:TIcmpSendEcho;
//destip:要探測的遠程地址,形如 192.168.1.1 procedure f_CheckOnline(destip:string); var IPOpt:TIPOptionInfo;// 發(fā)包的 IP 選項 IPAddr:DWORD; pReqData,pRevData:PChar; pIPE:PIcmpEchoReply;// ICMP Echo 回復(fù)緩沖區(qū) FSize: DWORD; MyString:string; FTimeOut:DWORD; BufferSize:DWORD; i:integer; begin hICMPdll := LoadLibrary('icmp.dll'); //調(diào)取icmp 動態(tài)庫 if hICMPDll<>NULL then begin WSAStartup($101,wsaData);//初始化網(wǎng)絡(luò)協(xié)議棧 @ICMPCreateFile := GetProcAddress(hICMPdll, 'IcmpCreateFile'); //取動態(tài)庫中的導(dǎo)出函數(shù) @IcmpCloseHandle := GetProcAddress(hICMPdll, 'IcmpCloseHandle'); @IcmpSendEcho := GetProcAddress(hICMPdll, 'IcmpSendEcho'); hICMP := IcmpCreateFile; //創(chuàng)建 icmp句柄 IPAddr:= inet_addr(PChar(destip)); //取要探測的遠端主機ip地址
FSize := 40; BufferSize := SizeOf(TICMPEchoReply) + FSize; GetMem(pRevData,FSize); GetMem(pIPE,BufferSize); FillChar(pIPE^, SizeOf(pIPE^), 0); pIPE^.Data := pRevData; MyString := 'Hi, OnLine?';//任意字符串 pReqData := PChar(MyString); FillChar(IPOpt, Sizeof(IPOpt), 0); IPOpt.TTL := 64; FTimeOut := 500;//等待時長 i:=IcmpSendEcho(hICMP, IPAddr, pReqData, Length(MyString), @IPOpt, pIPE, BufferSize, FTimeOut);//如果有返回,返回值表示收到的回復(fù)的個數(shù)。如果為0表示沒有回復(fù),主機無法到達 FreeMem(pRevData); FreeMem(pIPE); IcmpCloseHandle(hicmp); FreeLibrary(hICMPdll);//釋放動態(tài)庫 WSAcleanup();//清理協(xié)議棧 end; end;
|