流量监控实战

  以下是我在网上找的一个关于网络流量监控的程序,它类似于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);
View Code

建立回调函数: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

posted @ 2013-05-27 19:31  galuo  阅读(770)  评论(2编辑  收藏  举报