流量监控实战
以下是我在网上找的一个关于网络流量监控的程序,它类似于360在桌面上的流量悬浮窗口。
该程序主要实现流量的监控,再加上用按钮控件实现的一个坐标显示的功能,将流量的数据使用图形传达出来,这是一个很好的方式,在很多地方我们都会遇到类似的情况,比如说在做上位机的时候,我们需要将下位机采集到的温湿度等数据实时的显示出来,用该种方式就显得很有水平。
其实我也是拿到这个工程的代码很看不懂,我们来一段一段的分析,源代码见下文我给出的地址下载。
首先,建立MFC对话框工程NetTrafficButton。在IDD_NETTRAFFICBUTTON_DIALOG中添加控件,如下图
在CNetTrafficButtonApp.cpp中添加:
#include "winnet.h" #pragma comment(lib, "winnet.lib")
注意这里给出的不是wininet.lib,而这个库应该是作者自己写的一个库,从头文件中我找到了两个函数:
BOOL DLLENTRY NetInit(); void DLLENTRY NetUnint();
建立流量处理类MFNetTraffic。其头文件如下:
/******************************************* MFTrafficButton Version: 1.0 Date: 31.10.2001 Author: Michael Fatzi Mail: Michael_Fatzi@hotmail.com Copyright 1996-1997, Keith Rule You may freely use or modify this code provided this Copyright is included in all derived versions. History: 10.2001 Startup Handy little button control to display current nettraffic as graph in a button. ********************************************/ // MFNetTraffic.h: interface for the MFNetTraffic class. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_MFNETTRAFFIC_H__9CA9C41F_F929_4F26_BD1F_2B5827090494__INCLUDED_) #define AFX_MFNETTRAFFIC_H__9CA9C41F_F929_4F26_BD1F_2B5827090494__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include <afxtempl.h> class MFNetTraffic { public: enum TrafficType { AllTraffic = 388, IncomingTraffic = 264, OutGoingTraffic = 506 }; void SetTrafficType(int trafficType); DWORD GetInterfaceTotalTraffic(int index); BOOL GetNetworkInterfaceName(CString *InterfaceName, int index); int GetNetworkInterfacesCount(); double GetTraffic(int interfaceNumber); DWORD GetInterfaceBandwidth(int index); MFNetTraffic(); virtual ~MFNetTraffic(); private: BOOL GetInterfaces(); double lasttraffic; CStringList Interfaces; CList < DWORD, DWORD &> Bandwidths; CList < DWORD, DWORD &> TotalTraffics; int CurrentInterface; int CurrentTrafficType; }; #endif // !defined(AFX_MFNETTRAFFIC_H__9CA9C41F_F929_4F26_BD1F_2B5827090494__INCLUDED_)
MFNetTraffic.cpp代码如下:
/******************************************* MFTrafficButton Version: 1.0 Date: 31.10.2001 Author: Michael Fatzi Mail: Michael_Fatzi@hotmail.com Copyright 1996-1997, Keith Rule You may freely use or modify this code provided this Copyright is included in all derived versions. History: 10.2001 Startup Handy little button control to display current nettraffic as graph in a button. ********************************************/ // MFNetTraffic.cpp: implementation of the MFNetTraffic class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "MFNetTraffic.h" #include "float.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif #include "winperf.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// MFNetTraffic::MFNetTraffic() { lasttraffic = 0.0; CurrentInterface = -1; CurrentTrafficType = AllTraffic; GetInterfaces(); } MFNetTraffic::~MFNetTraffic() { } // Little helper functions // Found them on CodeGuru, but do not know who has written them originally static PERF_OBJECT_TYPE *FirstObject(PERF_DATA_BLOCK *dataBlock) { return (PERF_OBJECT_TYPE *) ((BYTE *)dataBlock + dataBlock->HeaderLength); } static PERF_OBJECT_TYPE *NextObject(PERF_OBJECT_TYPE *act) { return (PERF_OBJECT_TYPE *) ((BYTE *)act + act->TotalByteLength); } static PERF_COUNTER_DEFINITION *FirstCounter(PERF_OBJECT_TYPE *perfObject) { return (PERF_COUNTER_DEFINITION *) ((BYTE *) perfObject + perfObject->HeaderLength); } static PERF_COUNTER_DEFINITION *NextCounter(PERF_COUNTER_DEFINITION *perfCounter) { return (PERF_COUNTER_DEFINITION *) ((BYTE *) perfCounter + perfCounter->ByteLength); } static PERF_COUNTER_BLOCK *GetCounterBlock(PERF_INSTANCE_DEFINITION *pInstance) { return (PERF_COUNTER_BLOCK *) ((BYTE *)pInstance + pInstance->ByteLength); } static PERF_INSTANCE_DEFINITION *FirstInstance (PERF_OBJECT_TYPE *pObject) { return (PERF_INSTANCE_DEFINITION *) ((BYTE *) pObject + pObject->DefinitionLength); } static PERF_INSTANCE_DEFINITION *NextInstance (PERF_INSTANCE_DEFINITION *pInstance) { // next instance is after // this instance + this instances counter data PERF_COUNTER_BLOCK *pCtrBlk = GetCounterBlock(pInstance); return (PERF_INSTANCE_DEFINITION *) ((BYTE *)pInstance + pInstance->ByteLength + pCtrBlk->ByteLength); } static char *WideToMulti(wchar_t *source, char *dest, int size) { int nLen = WideCharToMultiByte(CP_ACP, 0, source, -1, dest, size, 0, 0); dest[nLen] = '\0'; return dest; } /* returns the traffic of given interface */ double MFNetTraffic::GetTraffic(int interfaceNumber) { try { #define DEFAULT_BUFFER_SIZE 40960L POSITION pos; CString InterfaceName; pos = Interfaces.FindIndex(interfaceNumber); if(pos==NULL) return 0.0; InterfaceName = Interfaces.GetAt(pos); // buffer for performance data unsigned char *data = new unsigned char [DEFAULT_BUFFER_SIZE]; // return value from RegQueryValueEx: ignored for this application DWORD type; // Buffer size DWORD size = DEFAULT_BUFFER_SIZE; // return value of RegQueryValueEx DWORD ret; // request performance data from network object (index 510) while((ret = RegQueryValueEx(HKEY_PERFORMANCE_DATA, "510", 0, &type, data, &size)) != ERROR_SUCCESS) { if(ret == ERROR_MORE_DATA) { // buffer size was too small, increase allocation size size += DEFAULT_BUFFER_SIZE; delete [] data; data = new unsigned char [size]; } else { // some unspecified error has occured return 1; } } PERF_DATA_BLOCK *dataBlockPtr = (PERF_DATA_BLOCK *)data; // enumerate first object of list PERF_OBJECT_TYPE *objectPtr = FirstObject(dataBlockPtr); // trespassing the list for(int a=0 ; a<(int)dataBlockPtr->NumObjectTypes ; a++) { char nameBuffer[255]; // did we receive a network object? if(objectPtr->ObjectNameTitleIndex == 510) { // Calculate the offset DWORD processIdOffset = ULONG_MAX; // find first counter PERF_COUNTER_DEFINITION *counterPtr = FirstCounter(objectPtr); // walking trough the list of objects for(int b=0 ; b<(int)objectPtr->NumCounters ; b++) { // Check if we received datatype wished if((int)counterPtr->CounterNameTitleIndex == CurrentTrafficType) { processIdOffset = counterPtr->CounterOffset; break; } // watch next counter counterPtr = NextCounter(counterPtr); } if(processIdOffset == ULONG_MAX) { delete [] data; return 1; } // Find first instance PERF_INSTANCE_DEFINITION *instancePtr = FirstInstance(objectPtr); DWORD fullTraffic; DWORD traffic; for(b=0 ; b<objectPtr->NumInstances ; b++) { // evaluate pointer to name wchar_t *namePtr = (wchar_t *) ((BYTE *)instancePtr + instancePtr->NameOffset); // get PERF_COUNTER_BLOCK of this instance PERF_COUNTER_BLOCK *counterBlockPtr = GetCounterBlock(instancePtr); // now we have the interface name char *pName = WideToMulti(namePtr, nameBuffer, sizeof(nameBuffer)); CString iName(""); iName.Format("%s",pName); if( iName == "" ) continue; POSITION pos = TotalTraffics.FindIndex(b); if(pos!=NULL) { fullTraffic = *((DWORD *) ((BYTE *)counterBlockPtr + processIdOffset)); TotalTraffics.SetAt(pos,fullTraffic); } // If the interface the currently selected interface? if(InterfaceName == iName) { traffic = *((DWORD *) ((BYTE *)counterBlockPtr + processIdOffset)); double acttraffic = (double)traffic; double trafficdelta; // Do we handle a new interface (e.g. due a change of the interface number if(CurrentInterface != interfaceNumber) { lasttraffic = acttraffic; trafficdelta = 0.0; CurrentInterface = interfaceNumber; } else { trafficdelta = acttraffic - lasttraffic; lasttraffic = acttraffic; } delete [] data; return(trafficdelta); } // next instance instancePtr = NextInstance(instancePtr); } } // next object in list objectPtr = NextObject(objectPtr); } delete [] data; return 0; } catch(...) { return 0; } } /* Enumerate installed interfaces. See comments above */ BOOL MFNetTraffic::GetInterfaces() { try { #define DEFAULT_BUFFER_SIZE 40960L Interfaces.RemoveAll(); unsigned char *data = (unsigned char*)malloc(DEFAULT_BUFFER_SIZE); DWORD type; DWORD size = DEFAULT_BUFFER_SIZE; DWORD ret; char s_key[4096]; sprintf( s_key , "%d" , 510 ); while((ret = RegQueryValueEx(HKEY_PERFORMANCE_DATA, s_key, 0, &type, data, &size)) != ERROR_SUCCESS) { while(ret == ERROR_MORE_DATA) { size += DEFAULT_BUFFER_SIZE; data = (unsigned char*) realloc(data, size); } if(ret != ERROR_SUCCESS) { return FALSE; } } PERF_DATA_BLOCK *dataBlockPtr = (PERF_DATA_BLOCK *)data; PERF_OBJECT_TYPE *objectPtr = FirstObject(dataBlockPtr); for(int a=0 ; a<(int)dataBlockPtr->NumObjectTypes ; a++) { char nameBuffer[255]; if(objectPtr->ObjectNameTitleIndex == 510) { DWORD processIdOffset = ULONG_MAX; PERF_COUNTER_DEFINITION *counterPtr = FirstCounter(objectPtr); for(int b=0 ; b<(int)objectPtr->NumCounters ; b++) { if(counterPtr->CounterNameTitleIndex == 520) processIdOffset = counterPtr->CounterOffset; counterPtr = NextCounter(counterPtr); } if(processIdOffset == ULONG_MAX) { free(data); return 1; } PERF_INSTANCE_DEFINITION *instancePtr = FirstInstance(objectPtr); for(b=0 ; b<objectPtr->NumInstances ; b++) { wchar_t *namePtr = (wchar_t *) ((BYTE *)instancePtr + instancePtr->NameOffset); PERF_COUNTER_BLOCK *counterBlockPtr = GetCounterBlock(instancePtr); char *pName = WideToMulti(namePtr, nameBuffer, sizeof(nameBuffer)); if( strcmp(pName, "") == 0 ) continue; DWORD bandwith = *((DWORD *) ((BYTE *)counterBlockPtr + processIdOffset)); DWORD tottraff = 0; Interfaces.AddTail(CString(pName)); Bandwidths.AddTail(bandwith); TotalTraffics.AddTail(tottraff); // initial 0, just for creating the list instancePtr = NextInstance(instancePtr); } } objectPtr = NextObject(objectPtr); } free(data); return TRUE; } catch(...) { return FALSE; } } /* Returns the count of installed interfaces */ int MFNetTraffic::GetNetworkInterfacesCount() { return Interfaces.GetCount()-1; } /* Returns the name of the given interface (-number) */ BOOL MFNetTraffic::GetNetworkInterfaceName(CString *InterfaceName, int index) { POSITION pos = Interfaces.FindIndex(index); if(pos==NULL) return FALSE; InterfaceName->Format("%s",Interfaces.GetAt(pos)); return TRUE; } /* Returns bandwith of interface e.g. 100000 for 100MBit */ DWORD MFNetTraffic::GetInterfaceBandwidth(int index) { POSITION pos = Bandwidths.FindIndex(index); if(pos==NULL) return 0; else return Bandwidths.GetAt(pos) / 8; } /* Sometime it is nice to know, how much traffic has a specific interface sent and received */ DWORD MFNetTraffic::GetInterfaceTotalTraffic(int index) { DWORD totaltraffic = 0; POSITION pos; pos= TotalTraffics.FindIndex(index); if(pos!=NULL) { totaltraffic = TotalTraffics.GetAt(pos); if(totaltraffic == 0.0) { GetTraffic(index); pos= TotalTraffics.FindIndex(index); if(pos!=NULL) { totaltraffic = TotalTraffics.GetAt(pos); } } } return(totaltraffic); } /* To prevent direct manipulation of member variables.... */ void MFNetTraffic::SetTrafficType(int trafficType) { CurrentTrafficType = trafficType; }
建立处理显示坐标的类MFTrafficButton。
建立处理画刷的处理类CMemDC。
#if !defined(AFX_MEMDC_H__CA1D3541_7235_11D1_ABBA_00A0243D1382__INCLUDED_) #define AFX_MEMDC_H__CA1D3541_7235_11D1_ABBA_00A0243D1382__INCLUDED_ #if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000 // MemDC.h : header file // ////////////////////////////////////////////////// // CMemDC - memory DC // // Author: Keith Rule // Email: keithr@europa.com // Copyright 1996-1997, Keith Rule // // You may freely use or modify this code provided this // Copyright is included in all derived versions. // // History - 10/3/97 Fixed scrolling bug. // Added print support. // 25 feb 98 - fixed minor assertion bug // // This class implements a memory Device Context class CMemDC : public CDC { public: // constructor sets up the memory DC CMemDC(CDC* pDC) : CDC() { ASSERT(pDC != NULL); m_pDC = pDC; m_pOldBitmap = NULL; m_bMemDC = !pDC->IsPrinting(); if (m_bMemDC) // Create a Memory DC { pDC->GetClipBox(&m_rect); CreateCompatibleDC(pDC); m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height()); m_pOldBitmap = SelectObject(&m_bitmap); SetWindowOrg(m_rect.left, m_rect.top); } else // Make a copy of the relevent parts of the current DC for printing { m_bPrinting = pDC->m_bPrinting; m_hDC = pDC->m_hDC; m_hAttribDC = pDC->m_hAttribDC; } } // Destructor copies the contents of the mem DC to the original DC ~CMemDC() { if (m_bMemDC) { // Copy the offscreen bitmap onto the screen. m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(), this, m_rect.left, m_rect.top, SRCCOPY); //Swap back the original bitmap. SelectObject(m_pOldBitmap); } else { // All we need to do is replace the DC with an illegal value, // this keeps us from accidently deleting the handles associated with // the CDC that was passed to the constructor. m_hDC = m_hAttribDC = NULL; } } // Allow usage as a pointer CMemDC* operator->() {return this;} // Allow usage as a pointer operator CMemDC*() {return this;} private: CBitmap m_bitmap; // Offscreen bitmap CBitmap* m_pOldBitmap; // bitmap originally found in CMemDC CDC* m_pDC; // Saves CDC passed in constructor CRect m_rect; // Rectangle of drawing area. BOOL m_bMemDC; // TRUE if CDC really is a Memory DC. }; ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Developer Studio will insert additional declarations immediately before the previous line. #endif // !defined(AFX_MEMDC_H__CA1D3541_7235_11D1_ABBA_00A0243D1382__INCLUDED_)
在BOOL CNetTrafficButtonDlg::OnInitDialog()中添加:
int SelectedInterface = 0; // Let us use the first found network connection UINT timerresolution = 1000; // Well, I think a refresh of the netstatus every second is enough UINT gridresolution = 100; // To fake the Taskmanager.... m_cTotalTraffic.SetInterfaceNumber(SelectedInterface); // Interface to monitor m_cTotalTraffic.SelectTrafficType(MFTrafficButton::Traffic_Total); // In this case the total traffic is monitored m_cTotalTraffic.SetInterfaceNumberNotificationFunction(interfaceHasChanged); // Set the callback handler to get informed... m_cTotalTraffic.SetUpdateSpeed(timerresolution, gridresolution); m_cOutgoing.SetInterfaceNumber(SelectedInterface); m_cOutgoing.SelectTrafficType(MFTrafficButton::Traffic_Outgoing); m_cOutgoing.SetInterfaceNumberNotificationFunction(interfaceHasChanged); m_cOutgoing.SetUpdateSpeed(timerresolution, gridresolution); m_cIncoming.SetInterfaceNumber(SelectedInterface); m_cIncoming.SelectTrafficType(MFTrafficButton::Traffic_Incoming); m_cIncoming.SetInterfaceNumberNotificationFunction(interfaceHasChanged); m_cIncoming.SetUpdateSpeed(timerresolution, gridresolution);
建立回调函数:static void CALLBACK interfaceHasChanged(int interfacenumber)
// 'So called' callback function for handling messages from the Buttons // Here you can react on interface number changes static void CALLBACK interfaceHasChanged(int interfacenumber) { SelectedInterface = interfacenumber; CString text; text.Format("NetTrafficButton using Interface: %d",SelectedInterface); me->SetWindowText(text); }
运行程序结果如下图:
源码下载网址:https://code.google.com/p/my-project-galuo/downloads/list