范智鑫 王毅燕
隨著計(jì)算機(jī)用戶的增多,計(jì)算機(jī)網(wǎng)絡(luò)越來越復(fù)雜,如何進(jìn)行實(shí)時(shí)的網(wǎng)絡(luò)檢測(cè)成為網(wǎng)管人員關(guān)心的問題。實(shí)時(shí)監(jiān)測(cè)可以在最早的時(shí)間內(nèi)發(fā)現(xiàn)問題,避免網(wǎng)絡(luò)長(zhǎng)時(shí)間繼線。本文介紹一種利用Delphi編寫應(yīng)用程序?qū)崿F(xiàn)專線狀態(tài)探測(cè)的方法。 實(shí)現(xiàn)原理 許多人經(jīng)常利用Windows中的兩條DOS命令(Ping和Tracert)來測(cè)試網(wǎng)絡(luò)狀態(tài),其原理是通過向探測(cè)的節(jié)點(diǎn)端口發(fā)送數(shù)據(jù)包請(qǐng)求,然后從該端口是否應(yīng)答來判斷網(wǎng)絡(luò)是否暢通。其實(shí),在Windows的System目錄下有一個(gè)Icmp.dll文件,該動(dòng)態(tài)鏈接庫(kù)提供了ICMP協(xié)議的所有功能,通過對(duì)該動(dòng)態(tài)鏈接庫(kù)的調(diào)用可以完成發(fā)送請(qǐng)求和接收應(yīng)答。因此,可以利用該動(dòng)態(tài)鏈接庫(kù)實(shí)現(xiàn)專線狀態(tài)的探測(cè)。 Icmp.dll文件內(nèi)的主要調(diào)用函數(shù)如下: ● IcmpCreateFile: 打開一個(gè)句柄,通過該句柄發(fā)送ICMP的請(qǐng)求報(bào)文; ● IcmpCloseHandle: 關(guān)閉通過IcmpCreateFile函數(shù)打開的句柄; ● IcmpSendEcho:通過打開的句柄發(fā)送ICMP請(qǐng)求,在超時(shí)或接收到應(yīng)答報(bào)文后返回。 編程實(shí)現(xiàn) 首先構(gòu)造節(jié)點(diǎn)庫(kù)(如圖1所示),然后通過調(diào)用ICMP協(xié)議,向測(cè)試端口發(fā)送請(qǐng)求,如果接收到該端口的應(yīng)答,則狀態(tài)為“正常”,否則,狀態(tài)為“中斷”。
圖1 1. 初始化WinSock,調(diào)入Icmp.dll庫(kù) var wsadata: TWSAData; begin if WSAStartup($101,wsadata) <> 0 then begin ShowMessage(‘Error initialising WinSock’); halt; end; hICMPlib ∶= loadlibrary(icmpDLL); if hICMPlib <> null then begin @ICMPCreateFile ∶= GetProcAddress(hICMPlib, ‘IcmpCreateFile’); @IcmpCloseHandle∶= GetProcAddress(hICMPlib, ‘IcmpCloseHandle’); @IcmpSendEcho∶= GetProcAddress(hICMPlib, ‘IcmpSendEcho’); if (@ICMPCreateFile = Nil) or (@IcmpCloseHandle = Nil) or (@IcmpSendEcho=Nil) then begin ShowMessage(‘Error loading dll functions’); halt; end; hICMP ∶= IcmpCreateFile; if hICMP=INVALID_HANDLE_VALUE then begin ShowMessage(‘Unable to get ping handle’); halt; end; end; else begin ShowMessage(‘Unable to register’+ icmpDLL); halt; end; end; 2. 使用定時(shí)器啟動(dòng)探測(cè) 在測(cè)試中,如果端口狀態(tài)正常,則net_stat=0;狀態(tài)異常則net_stat=1,并顯示“中斷”,系統(tǒng)響鈴報(bào)警。對(duì)節(jié)點(diǎn)表中所有節(jié)點(diǎn)進(jìn)行測(cè)試的主要代碼如下: //取得欲測(cè)試端口的IP地址 net_ip∶=Table1. FieldByName(‘對(duì)端IP’). asstring; //調(diào)用端口測(cè)試 Test(Sender); if net_stat=0 then begin Table1. FieldByName(‘狀態(tài)’). asstring∶=‘中斷’; //端口異常,則net=1 if net=0 then net∶=1; end else Table1. FieldByName(‘狀態(tài)’). asstring∶=‘正常’; //整表測(cè)試后,如有異常的端口,則10次響鈴報(bào)警 if net=1 then FOR I∶=1 TO 10 DO PlaySound(‘RINGIN’, 0, SND_RESOURCE); 3. 探測(cè)指定的端口:Test(Sender) const Size = 56; TimeOut = 3000; var Address: DWord; HostName, HostIP: String; Phe: PHostEnt; BufferSize, nPkts: Integer; pReqData, pData: Pointer; pIPE: PIcmpEchoReply; IPOpt: TIPOptionInformation; begin //將存儲(chǔ)字符串的地址轉(zhuǎn)化為標(biāo)準(zhǔn)的網(wǎng)絡(luò)IP地址 Address ∶= inet_addr(PChar(net_ip)); //取得測(cè)試端口的句柄 Phe ∶= GetHostByAddr(@Address, 4, PF_INET); // 設(shè)定一個(gè)緩沖區(qū),填充指定數(shù)據(jù)作為待發(fā)送的數(shù)據(jù)包 BufferSize ∶= SizeOf(TICMPEchoReply) + Size; GetMem(pReqData, Size); GetMem(pData, Size); GetMem(pIPE, BufferSize); FillChar(pReqData^, Size, $AA); pIPE^.Data ∶= pData; FillChar(IPOpt, SizeOf(IPOpt), 0); IPOpt.TTL ∶= 64; //通過打開的句柄,發(fā)送ICMP數(shù)據(jù)包請(qǐng)求,在超時(shí)或接收應(yīng)答報(bào)文后返回 NPkts ∶= IcmpSendEcho(hICMP, Address, pReqData, Size, @IPOpt, pIPE, BufferSize, TimeOut); //根據(jù)是否從測(cè)試端口返回應(yīng)答報(bào)文,判斷網(wǎng)絡(luò)狀態(tài) if NPkts = 0 then net_stat∶=0 else begin HostIP ∶= StrPas(inet_ntoa(TInAddr(pIPE^.Address))); if trim(HostIP)=trim(net_ip) then net_stat∶=1 else net_stat∶=0; end; //釋放變量 FreeMem(pIPE); FreeMem(pData); FreeMem (pReqData); end; 4. 關(guān)閉探測(cè)程序 //釋放ICMP IcmpCloseHandle(hICMP); FreeLibrary(hICMPlib); //釋放WinSock if WSACleanup <> 0 then ShowMessage(‘Error freeing WinSock’); 完善程序 上述程序僅提供了基本的網(wǎng)絡(luò)探測(cè)方法,為了更好地體現(xiàn)網(wǎng)絡(luò)狀態(tài)和處理情況,可以對(duì)此程序進(jìn)一步完善: 1. 再建兩個(gè)表: ● 故障記錄和處理表: 在探測(cè)中將故障節(jié)點(diǎn)記錄保存,并記錄故障處理情況; ● 探測(cè)間隔表:靈活設(shè)置探測(cè)時(shí)間間隔。 2. 添加節(jié)點(diǎn)庫(kù)維護(hù)模塊。 3. 對(duì)于探測(cè)模塊的顯示進(jìn)行改造,使故障節(jié)點(diǎn)呈現(xiàn)報(bào)警色(如紅色)。
|