用VC++ 6.0製作網路自動測試程式 (轉)

worldblog發表於2007-12-08
用VC++ 6.0製作網路自動測試程式 (轉)[@more@]本報2000年11月27日第46期的應用中,登載了“用VC++6.0製作測試”一文。該文介紹的網路測試方法是透過目錄下的.EXE命令來實現的。程式時,須用滑鼠點中拓撲圖某網路節點熱區,並透過所執行PING.EXE命令的DOS視窗來觀察測試結果。由於沒有自動測試功能,所以使用不夠方便。 由公司開發的WINDOWS SOCKETS提供了WINDOWS環境下網路通訊的程式設計介面。在VC++6.0中,可以透過呼叫WINDOWS SOCKETS,採用原始套接字(RAW SOCKETS)型別和互連網控制訊息(ICMP),來編制一個能實現PING功能的函式。透過定時呼叫該函式,就可實現網路的自動測試。若再加上語音報警功能,就是一個很實用的網路測試程式。本文擬介紹實現此功能的程式的製作方法。 為便於說明起見,我們還是按“用VC++6.0製作網路測試程式”一文介紹的方法,先做一個簡單的網路測試程式est)。注意,在製作Netest工程的STEP 4 OF 6時 ,要鉤選WINDOWS SOCKETS選項。否則,在下面要編譯AUTOP.CPP時,將會出錯。在Netest工程編譯成功後,再做以下幾項工作: 一、增加AUTOP. CPP到工程檔案中 在工程à新增工程à檔案à將AUTOP.CPP新增到當前工程檔案中(AUTOP.CPP的原始碼見下面第三節的內容所示,應事先將其COPY到當前工程的目錄中)。 二、在工程中增加自動測試的有關選單和函式 (1)在“用VC++6.0製作網路測試程式”一文介紹的Netest工程中,其Readinfo()函式的最後一條語句GlobalFree(hHost)釋放了裝載有初始化資訊的,當隨後呼叫PING.EXE時,問題不是很大。但若呼叫WINSOCK函式,記憶體中的初始化資訊會被沖掉。所以須將該語句移到程式結束處再執行。可如下增加OnDestroy()函式: 在ClassWizard中,對應Class name=CNetestView, IDs=estView,Message =WM_DESTROY,點選Add FunctionàOnDestroyàEdit Code,增加相應程式碼如下: void CNtestView::OnDestroy() { CFormView::OnDestroy(); GlobalFree(hHost); //從Readinfo()移到此 for (int i=0; iGetMenu(); pMenu->EnableMenuItem(ID_AUTOPING,MF_BYCOMMAND| MF_DISABLED | MF_GRAYED); pMenu->EnableMenuItem(ID_STOPAUTO,MF_ENABLED); AfxGetMainWnd()->SendMessage (WM_TIMER,0, 0L); } 其中SetTimer()將定時器設為每30秒中斷一次。由Tc計算中斷次數。餘下幾句條語句令Autotest選單變灰,以免多次重入。最後一條語句使得滑鼠點選Autotest選單後,即轉到OnTimer()函式開始自動測試。 (3)增加定時測試程式碼。在ClassWizard中,對應Class name=CNetestView的Message, 選中WM_TIMERàAdd FunctionàEdit Code,在OnTimer() 函式中增加如下程式碼:   void CNetestView::OnTimer(UINT nvent) { if(Tc++<20) return; KillTimer(1); Tc=0; BOOL bOK=TRUE; InvalidateRect(NULL); for(int ipT=0;ipT { if(Autotest(lpHost[ipT].nodeIP,3)==FALSE) { CString strerr; strerr.Format("err%d.wav",ipT+1); sndPlaySound(strerr, SND_L |SND_ASYNC ); HDC hdc= CreateDC("DISPLAY",0,0,0); Object(hdc,lpHost[ipT].hrgn); InvertRgn(hdc,lpHost[ipT].hrgn); DeleteDC(hdc); bOK=FALSE; } else if(bOK) sndPlaySound("Bird0.wav", SND_ASYNC); } SetTimer(1, 30000,NULL); CFormView::OnTimer(nIDEvent); } 本為每10分鐘對網路作一次自動測試。所以第一條語句須檢查定時器中斷是否已夠20次(30秒*20=10分鐘)。若夠的話,就關斷定時器,迴圈呼叫Autotest()對所有網路節點進行測試。若Autotest()的返回值為FALSE,說明該節點有問題,隨即呼叫對應聲波檔案發出不停的報警聲。在報警的同時,程式繼續往下執行,作餘下網路節點的測試。若所有節點均正常,則呼叫BIRD0.WAV聲波檔案發出動聽的鳥鳴聲。全部節點測試完後,才用SetTimer()再次啟動定時器。 報警聲波檔案的製作,可在WINDOWS的附件à娛樂à錄音機,透過麥克風錄下報警語音。按照在INFO.INI檔案中各節點的順序,將語音檔案分別存為ERR1.WAV,ERR2.WAV……。這樣,網路節點的報警聲就能和出錯節點正確對應。 測試時,若有2個以上網路節點有問題,前一個出錯節點只會報警一次,最後一個出錯節點則會發出迴圈報警聲。為了便於觀察出錯情況,用InvertRgn()來反相顯示出錯節點的區域。InvalidateRect(NULL)函式用來使螢幕重新整理,以便下一次測試的觀察。 三、AUTOP.CPP的原始碼及說明 AUTO.CPP的原始碼如下: //#include 標頭檔案略 . . . . . . . . . . . typedef struct _ihdr { BYTE i_type, i_code; u_short i_cksum,i_id, i_seq; }IcmpHeader; struct sockaddr_in saDestAddr; CString Messtr,Tmpstr;   u_short checksum(u_short *buffer, int size) { . . . . . . .(略) }   BOOL Autotest(char far * szDestHost,int Ktest) { WSADATA wsaData; SOCKET sockRaw; struct sockaddr_in dest,from; char icmp_data[10], recvbuf[100]; unsigned int addr=0; int fromlen = sizeof(from); int timeout = 1000; //ms   Wtartup(MAKE(2,1),&wsaData) ; sockRaw = socket (AF_INET,SOCK_RAW,IPPROTO_ICMP); setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO, (char*)&timeout,sizeof(timeout) ); memset(&dest,0,sizeof(dest)); dest.sin_family = AF_INET; dest.sin_addr.s_addr= inet_addr(szDestHost); memset(icmp_data,0,sizeof(icmp_data)); //clear icmp_data. ((IcmpHeader*)icmp_data)->i_type = 8; //ICMP_ECHO ((IcmpHeader*)icmp_data)->i_code = 0; ((IcmpHeader*)icmp_data)->i_id = (u_short)GetCurrentProcessId(); ((IcmpHeader*)icmp_data)->i_seq = 0;   for(int k=0; k { ((IcmpHeader*)icmp_data)->i_cksum = 0; ((IcmpHeader*)icmp_data)->i_seq ++; ((IcmpHeader*)icmp_data)->i_cksum=checksum((u_short*)icmp_data,8); sendto(sockRaw,icmp_data,8,0,(struct sockaddr*)&dest,sizeof(dest)); int bread=recvfrom(sockRaw,recvbuf,1024,0,(struct sockaddr*)&from, &fromlen); if (bread == SOCKET_ERROR){ if(k==Ktest-1) goto ERR1 ; else continue; //try again(3 times) } } return TRUE; //no erros. ERR1: closesocket (sockRaw); sockRaw= INVALID_SOCKET; WSACleanup(); return FALSE; } 為簡潔起見,原始碼中大部分的出錯處理語句都刪去了。整個函式執行的過程如下: (1)用WSAStartup()函式初始化WINSOCK DLL。 (2)用socket()函式建立一個原始套接字sockRaw。 (3)用setsockopt()函式來設定套接字的選擇項。這裡用SO_RCVTIMEO引數來設定接收超時。超時值由timeout=1000設定超時最長時間為1秒鐘。 (4)給被測節點的dest和Icmpheader結構變數賦值。其中szDestHost放被測節點的(點間隔格式),inet_addr()函式將一個點間隔的地址轉換成4位元組的地址;Icmpheader結構的i_type=8表示傳送一個請求響應資料包(ICMP_ECHO),i_id為資料包的標識,i_cksum為資料包的校驗和,i_seq用來為傳送包計數。 (5)用sendto()函式向被測節點傳送資訊,用recvfrom()函式接收被測節點的應答資訊。若在規定時間內(1秒)收不到應答資訊,再連測2次。若3次的傳送均收不到應答資訊,可認為網路故障。Ktest的值決定對被測節點反覆測試的次數。(當收到應答資訊時,還認應檢查應答資訊內容正確後,才認為網路正常。本例略去這些檢查似乎也無妨)。 (6)測試完一個節點後,用closesocket()函式關閉套接字,用WSAcCleanup()函式釋放為應用程式分配的資源。 至此,就可以編譯和執行程式,體會個中樂趣。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-989818/,如需轉載,請註明出處,否則將追究法律責任。

相關文章