zoukankan      html  css  js  c++  java
  • WinPcap网络抓包分析程序--总结

    应付大作业写的一个程序,先给出程序的运行界面

    程序的核心内容是抓包然后分析数据,我做的最多的也是协议分析这块内容。上面首先给出的是当前网络的上传下载速度,这块内容我是参考Windows性能计数器来写的,就是PDH,直接获取相应的接口,

    获取数据,这块内容直接放出代码 

     1 #include <Pdh.h>
     2 #include <list>
     3 #pragma comment(lib, "Pdh.lib") 
     4 
     5 class NetWorkSpeed
     6 {
     7 public:
     8     NetWorkSpeed();
     9     ~NetWorkSpeed();
    10 public:
    11     double getRecSpeed()  {return m_RecSpeed; }
    12     double getSendSpeed() {return m_SendSpeed;}
    13 
    14     bool init();
    15 
    16     void update();
    17 private:
    18     double m_RecSpeed;
    19     double m_SendSpeed;
    20     HQUERY m_hQuery; 
    21 
    22     std::list<double>   m_receiveBps; 
    23     std::list<double>   m_sendBps; 
    24     std::list<HCOUNTER> m_allhCounters;   
    25 };
    网络速度头文件
      1 using namespace std;
      2 
      3 NetWorkSpeed::NetWorkSpeed()
      4 {
      5 
      6 }
      7 
      8 NetWorkSpeed::~NetWorkSpeed()
      9 {   
     10     m_allhCounters.clear();
     11     m_sendBps.clear();
     12     m_receiveBps.clear();
     13 
     14     PdhCloseQuery(m_hQuery);
     15 }
     16 
     17 bool NetWorkSpeed::init()
     18 {
     19     DWORD counters_len=0;                                //计数器的个数
     20     DWORD instances_len=0;                               //网卡的个数
     21     string counters_names;                               //保存计数器名称
     22     string instances_names;                              //保存网卡名称
     23     const char* networkInterface="Network Interface";    //网络接口部分
     24 
     25     PdhEnumObjectItemsA(0,0,networkInterface,0,&counters_len,0,&instances_len,PERF_DETAIL_WIZARD,0);  
     26     counters_names.assign(counters_len,0);               //初始化字符串
     27     instances_names.assign(instances_len,0);
     28     if (ERROR_SUCCESS!=PdhEnumObjectItemsA(0,            //使用本地电脑不使用log日志文件
     29         0,                                               //使用本地电脑
     30         networkInterface,                                //接口声明
     31         &counters_names[0],                              //保存字符串
     32         &counters_len,                                   //个数
     33         &instances_names[0],
     34         &instances_len,
     35         PERF_DETAIL_WIZARD,                              //四种  这里是获取所有的计数器
     36         0))                                              //必须设置成0 
     37         return false;
     38 
     39     
     40 
     41     const char* in_speed="Bytes Received/sec";
     42     const char* out_speed="Bytes Sent/sec";
     43 
     44     PDH_STATUS resulte=PdhOpenQuery(0,0,&m_hQuery);  //打开计数器 
     45     if (ERROR_SUCCESS!=resulte)
     46         return false;                                //打开失败
     47 
     48     char* tpStr=&instances_names[0];
     49     for(;*tpStr!=0;tpStr+=(strlen(tpStr)+1))
     50     {   
     51         string pdh_Receive_path=string("\")+networkInterface+"("+tpStr+")"+"\"+in_speed;  //计数器具体路径
     52         string pdh_Sent_path=string("\")+networkInterface+"("+tpStr+")"+"\"+out_speed;
     53 
     54         HCOUNTER tpCounter;
     55         resulte=PdhAddCounterA(m_hQuery,pdh_Receive_path.c_str(),0,&tpCounter);             //增加计数器  
     56         if (ERROR_SUCCESS!=resulte)
     57             return false;
     58         m_allhCounters.push_back(tpCounter);                                                 //加入
     59 
     60         resulte=PdhAddCounterA(m_hQuery,pdh_Sent_path.c_str(),0,&tpCounter);
     61         if (ERROR_SUCCESS!=resulte)
     62             return false;
     63         m_allhCounters.push_back(tpCounter);
     64     }
     65     return true;
     66 }
     67 
     68 void NetWorkSpeed::update()
     69 {
     70     PDH_FMT_COUNTERVALUE relustValue;
     71     DWORD dType;
     72 
     73     PDH_STATUS resulte=PdhCollectQueryData(m_hQuery);  //收集数据 
     74 
     75     double in_bps=0;
     76     double out_bps=0;
     77     double in_avg_bps=0;
     78     double out_avg_bps=0;
     79 
     80     //遍历每个计数器
     81     for(list<HCOUNTER>::iterator begin=m_allhCounters.begin();begin!=m_allhCounters.end();begin++)
     82     {
     83         resulte=PdhGetFormattedCounterValue(*begin,PDH_FMT_DOUBLE,&dType,&relustValue);
     84         if (ERROR_SUCCESS==resulte)
     85             in_bps+=relustValue.doubleValue;  //增加
     86         begin++;
     87         resulte=PdhGetFormattedCounterValue(*begin,PDH_FMT_DOUBLE,&dType,&relustValue);
     88         if (ERROR_SUCCESS==resulte)
     89             out_bps+=relustValue.doubleValue;
     90     }
     91 
     92     m_receiveBps.push_back(in_bps);
     93     m_sendBps.push_back(out_bps);
     94 
     95     if (m_receiveBps.size()>10)
     96         m_receiveBps.pop_front();  
     97     if (m_sendBps.size()>10)
     98         m_sendBps.pop_front();
     99 
    100     //计算平均值 
    101     in_avg_bps=accumulate(m_receiveBps.begin(),m_receiveBps.end(),0.0)/m_receiveBps.size();
    102     out_avg_bps=accumulate(m_sendBps.begin(),m_sendBps.end(),0.0)/m_sendBps.size();
    103 
    104     //转成 千字节 
    105     m_RecSpeed=in_avg_bps/1024;
    106     m_SendSpeed=out_avg_bps/1024;
    107 }
    网络速度源文件

    然后就是Pcap程序里面要做的第一步,选择网卡,然后打开设备,开启网卡的混杂模式,使用pcap_loop函数进行抓包,当然这里需要开启一条新的线程,具体的可以直接参考WinPcap入门文档里面的例子,这里我

    先说一下我遇到的问题。开始我是每来一个包就进行分析,然后发现这种情况下是会丢包的,而且流量突然变大的时候丢包非常严重,会影响后面流量统计的精度。后来的话是打算参考WireShark的源代码,但无奈水平

    不够,代码太复杂,就没看了。不过,我大概有下面一些理解,WireShark对发来的包是先存到堆里面,然后再取出分析,分析的话是采用树形的结构,确定它的父协议,然后一层层向下分析,而且它的插件开发也是向

    协议树中进行注册,分析的时候就会通过插件,协议种类很多,这一块内容我还在学习,实现提供一个便捷的接口供外部注册使用。具体的分析网上很多,就不多说了。我呢,也是建立链表,将包数据存到链表里面,然后在

    外部开启定时器,每隔一段时间对抓到的包进行分析,这样就能避免丢包。但是,需要注意的是,内存是有限的,所以必须定时的清理链表,释放相关的内存,当然你也可以先将数据写到文件里面,这一块需要你自己决定了。

    这一块的话我就不给出相关代码了,毕竟网上太多了。

    然后就是协议分析,先给出一些资料的链接, http://download.csdn.net/detail/zhoupeng39/8888363

    这块我是写了两遍,毕竟看不看资料对不同协议的理解程度还是不同的,代码写的很简陋,如下

      1 //头部基类 
      2 class Head_Top
      3 {
      4 public:
      5     Packet_Type own_type;    //记录类型
      6     int         own_len;     //记录长度  
      7 
      8     Head_Top():next(NULL){}
      9 
     10     Head_Top* next;                                //下一个
     11 
     12     virtual void packet_analysis(u_char* data,Packet_Type& type,int remain_len)=0;  //分析
     13 
     14     virtual CString packet_own_print()=0;          //打印
     15 
     16     virtual void    insertIntoTree(HTREEITEM root)=0;                    //形成树列表  
     17 };
     18 
     19 //以太网V2帧 
     20 class Head_EthernetII: public Head_Top
     21 {
     22 public:
     23     u_char sMac[6];   //源Mac地址
     24     u_char dMac[6];   //目的Mac地址
     25     u_char kind[2];   //上层网络协议类型  
     26 
     27     void packet_analysis(u_char* data,Packet_Type& type,int remain_len);
     28 
     29     CString packet_own_print();
     30 
     31     void  insertIntoTree(HTREEITEM root);
     32 };
     33 
     34 //以太网802.3帧 
     35 class Head_802_3 : public Head_Top
     36 {
     37 public:
     38     u_char sMac[6];  //mac地址  
     39     u_char dMac[6];
     40     u_char kind[2];  //类型
     41 
     42     void packet_analysis(u_char* data,Packet_Type& type,int remain_len);
     43 
     44     CString packet_own_print();
     45 
     46     void  insertIntoTree(HTREEITEM root);
     47 };
     48 
     49 //使用网线连接 
     50 class Head_PPPoE : public Head_Top
     51 {
     52 public:
     53     u_short version;    //版本
     54     u_short pppoe_type; //类型
     55     u_short code;       //代码
     56     u_short session_id; //会话ID 保持不变
     57     u_short len;        //长度
     58     CString nextDataType;  //保存净荷域数据类型   只是分析IP包  其他类型未分析 
     59 
     60     void packet_analysis(u_char* data,Packet_Type& type,int remain_len);
     61 
     62     CString packet_own_print();
     63 
     64     void  insertIntoTree(HTREEITEM root);
     65 };
     66 
     67 //地址解析协议 
     68 class Head_ARP : public Head_Top
     69 {
     70 public:
     71     u_short handWareType;  //硬件类型  1 表示以太网
     72     u_short protocal_type; //协议类型  IP地址 
     73     u_short handWare_Len;  //硬件长度  Mac地址 6个字节
     74     u_short protocal_len;  //协议长度  Ip地址  4个字节
     75     u_short op_code;       //操作码    1 请求 2 应答  
     76     u_char sMac[6];        //源Mac
     77     u_char dMac[6];        //目的Mac
     78     u_char sIp[4];         //源IP
     79     u_char dIp[4];         //目的IP
     80 
     81     void packet_analysis(u_char* data,Packet_Type& type,int remain_len);
     82 
     83     CString packet_own_print();
     84 
     85     void  insertIntoTree(HTREEITEM root);
     86 };
     87 
     88 //IP协议
     89 class Head_IPv4 : public Head_Top
     90 {
     91 public:
     92     u_short version;    //版本号  
     93     u_short header_len; //报头长度 *4为头部的长度  头部长度可变 
     94     u_short service_type; //业务类型 
     95     u_short len;          //数据包长度 
     96     u_short sign;         //标识符 IP包分组时候使用  同一个标识符进行重组
     97     u_char    df;         //标记是否能分段   1 表示不能分段(不能分段 进行分段 会丢包处理) 
     98     u_char    mf;          //分段包的结束操作 0 表示分段包的最后一个包 
     99     u_short offset;       //分段偏移
    100     u_char  TTL;          //存活时间
    101     u_short protocol;     //下层协议类型
    102     u_char sIp[4];        //源地址
    103     u_char dIp[4];        //目的地址  
    104 
    105     void packet_analysis(u_char* data,Packet_Type& type,int remain_len);
    106 
    107     CString packet_own_print();
    108 
    109     void  insertIntoTree(HTREEITEM root);
    110 };
    111 
    112 //IPV6协议  
    113 class Head_IPv6 : public Head_Top
    114 {
    115 public:
    116     u_char  version;   //IP版本  为6 
    117     u_char  trafficClass;  //通信类别 
    118     u_char  flowLabel[3];  //流标记
    119     u_short next_len;      //负载长度  包括扩展头和上层载荷
    120     u_short protocol;      //上层协议 
    121     u_short hopLimit;      //跳数限制 
    122     u_char sIp[16];        //源MAC
    123     u_char dIp[16];        //目的MAC
    124     u_short ext_len;       //扩展长度
    125     u_short sign;          //标记是否存在扩展头部 
    126 
    127     void packet_analysis(u_char* data,Packet_Type& type,int remain_len);
    128 
    129     CString packet_own_print();
    130 
    131     void  insertIntoTree(HTREEITEM root);
    132 };
    133 
    134 //ICMP控制协议  
    135 class Head_ICMP : public Head_Top
    136 {
    137 public:
    138     u_short ic_type;  //类型  
    139     u_short code;     //代码
    140 
    141     void packet_analysis(u_char* data,Packet_Type& type,int remain_len);
    142 
    143     CString packet_own_print();
    144 
    145     void  insertIntoTree(HTREEITEM root);
    146 };
    147 
    148 //UDP协议
    149 class Head_UDP : public Head_Top
    150 {
    151 public:
    152     u_short sPort;   //源端口
    153     u_short dPort;   //目的端口
    154     u_short len;     //总长度 
    155 
    156     void packet_analysis(u_char* data,Packet_Type& type,int remain_len);
    157 
    158     CString packet_own_print();
    159 
    160     void  insertIntoTree(HTREEITEM root);
    161 };
    162 
    163 
    164 class Head_IGMP : public Head_Top
    165 {
    166 public:
    167     u_char version;  //版本
    168     u_char ig_type;  //类型
    169     u_char Multicast[4];   //D类 组地址
    170 
    171     void packet_analysis(u_char* data,Packet_Type& type,int remain_len);
    172 
    173     CString packet_own_print();
    174 
    175     void  insertIntoTree(HTREEITEM root);
    176 };
    177 
    178 //TCP协议 
    179 class Head_TCP : public Head_Top
    180 {
    181 public:
    182     u_short sPort;        //源端口
    183     u_short dPort;        //目的端口 
    184     int     seq;          //序号
    185     int     refirm_seq;   //确认序号
    186     u_short header_len;   //首部长度 *4 
    187     u_char  URG;          //紧急指针有效
    188     u_char  ACK;          //确认字段有效
    189     u_char  PSH;          //推送数据
    190     u_char  RST;          //连接复位
    191     u_char  SYN;          //连接建立时序号同步
    192     u_char  FIN;          //终止连接 
    193     u_short window_size;  //窗口大小 
    194     u_short imppoint;     //紧急指针  标志那些数据可以优先处理 
    195 
    196     void packet_analysis(u_char* data,Packet_Type& type,int remain_len);
    197 
    198     CString packet_own_print();
    199 
    200     void  insertIntoTree(HTREEITEM root);
    201 };
    202 
    203 //OSPF协议 
    204 class Head_OSPF : public Head_Top
    205 {
    206 public:
    207     u_char version;    //版本 
    208     u_short ospf_type; //报文类型
    209     u_short len;       //长度
    210     u_char routerIp[4];//路由器标识
    211     u_char areaIp[4];  //区域标识
    212     u_short autype;    //验证类型 
    213     CString auData;    //验证信息  
    214 
    215     void packet_analysis(u_char* data,Packet_Type& type,int remain_len);
    216 
    217     CString packet_own_print();
    218 
    219     void  insertIntoTree(HTREEITEM root);
    220 };
    221 
    222 //域名解析协议 
    223 class Head_DNS : public Head_Top
    224 {
    225 public:
    226     u_short sign;         //唯一标识 
    227     u_char  symbol[2];    //标志 
    228     u_char  QR;           //查询还是响应报文 
    229     u_short questionNum;  //问题数目
    230     u_short answerNum;    //回答数目
    231     u_short au_answer;    //权威回答数目
    232     u_short ex_answer;    //附加回答数目 
    233 
    234     CString question;     //问题
    235 
    236     void packet_analysis(u_char* data,Packet_Type& type,int remain_len);
    237 
    238     CString packet_own_print();
    239 
    240     void  insertIntoTree(HTREEITEM root);
    241 };
    242 
    243 //DHCP协议
    244 class Head_DHCP : public Head_Top
    245 {
    246 public:
    247     u_char   op;     //操作代码 
    248     u_char   Htype;  //硬件地址类型  1表示以太网地址 
    249     u_short  Hlen;   //硬件地址长度
    250     u_short  Hops;   //跳数  经过一个路由器加一
    251     int      Transaction_ID;  //事务ID  请求和回复时判断的依据  唯一 
    252     u_short  Secs;   //客户机启动时间
    253     u_char   Ciaddr[4];  //客户端IP地址  如果继续使用之前的IP 放在这里
    254     u_char   Yiaddr[4];  //服务器提供的IP地址
    255     u_char   Siaddr[4];  //服务器IP地址
    256     u_char   Giaddr[4];  //转发代理地址  跨网段获取IP时候使用 
    257     u_char   Chaddr[6];  //客户端硬件地址  Mac地址
    258     CString  Sname;      //服务器名称
    259     CString  File;       //引导文件名称
    260     u_short  message_type;  //消息类型  0x35 只是识别一种消息类型 
    261     u_short  message_in;    //具体消息  
    262 
    263     void packet_analysis(u_char* data,Packet_Type& type,int remain_len);
    264 
    265     CString packet_own_print();
    266 
    267     void  insertIntoTree(HTREEITEM root);
    268 };
    269 
    270 //超文本协议  
    271 class Head_HTTP : public Head_Top
    272 {
    273 public:    
    274     CString  HttpData;   //打印信息 
    275 
    276     void packet_analysis(u_char* data,Packet_Type& type,int remain_len);
    277 
    278     CString packet_own_print();
    279 
    280     void  insertIntoTree(HTREEITEM root);
    281 };
    282 
    283 //FTP协议分析 主动模式和被动模式  控制端口  数据端口  
    284 class Head_FTP : public Head_Top
    285 {
    286 public:
    287     CString  command;    //只是打印命令  不做解析
    288 
    289     void packet_analysis(u_char* data,Packet_Type& type,int remain_len);
    290 
    291     CString packet_own_print();
    292 
    293     void  insertIntoTree(HTREEITEM root);
    294 };
    295 
    296 //简单邮件协议SMTP
    297 class Head_SMTP : public Head_Top
    298 {
    299 public:
    300      CString command;
    301 
    302      void packet_analysis(u_char* data,Packet_Type& type,int remain_len);
    303 
    304      CString packet_own_print();
    305 
    306      void  insertIntoTree(HTREEITEM root);
    307 };
    308 
    309 #endif
    View Code

    源文件我给出部分代码,毕竟大同小异,看看上面的资料就都会写了

      1 void Head_EthernetII::packet_analysis(u_char* data,Packet_Type& type,int remain_len)
      2 {   
      3     memcpy(dMac,data,6);
      4     memcpy(sMac,data+6,6);
      5     memcpy(kind,data+12,2);
      6 
      7     int tmpKind=kind[0]<<8|kind[1];
      8 
      9     own_type=EthernetII;
     10     own_len=14;
     11     remain_len-=own_len;
     12 
     13     switch (tmpKind)
     14     {
     15     case sign_ipv4:
     16         next=new Head_IPv4();
     17         next->packet_analysis(data+14,type,remain_len);
     18         break;
     19     case sign_arp:
     20         next=new Head_ARP();
     21         next->packet_analysis(data+14,type,remain_len);
     22         break;
     23     case sign_ipv6:
     24         next=new Head_IPv6();
     25         next->packet_analysis(data+14,type,remain_len);
     26         break;
     27     case sign_pppoe:
     28         next=new Head_PPPoE();
     29         next->packet_analysis(data+14,type,remain_len);
     30         break;
     31     default:
     32         next=NULL;
     33         type=EthernetII;
     34         break;
     35     }
     36 }
     37 
     38 void Head_PPPoE::packet_analysis(u_char* data,Packet_Type& type,int remain_len)
     39 {
     40     version=(data[0]&0xf0)>>4;
     41     pppoe_type=data[0]&0x0f;
     42     code=data[1];
     43     session_id=data[2]<<8|data[3];
     44     len=data[4]<<8|data[5];
     45 
     46     own_type=PPPoE;
     47     own_len=8;
     48     remain_len-=own_len;
     49 
     50     int kind=data[6]<<8|data[7];
     51 
     52     if (0x0021==kind)
     53     {
     54         nextDataType="IP数据包";
     55         next=new Head_IPv4();
     56         next->packet_analysis(data+8,type,remain_len);
     57     }
     58     else
     59     {  
     60         switch (kind)
     61         {
     62         case 0xc021:
     63              nextDataType="链路控制数据LCP";
     64              break;
     65         case 0x8021:
     66              nextDataType="网络控制数据NCP";
     67              break;
     68         case 0xc023:
     69              nextDataType="安全性认证PAP";
     70              break;
     71         case 0xc025:
     72              nextDataType="LQR";
     73              break;
     74         case 0xc223:
     75              nextDataType="安全性认证CHAP";
     76              break;
     77         }
     78         next=NULL;
     79         type=PPPoE;
     80     }
     81 }
     82 
     83 void Head_IPv4::packet_analysis(u_char* data,Packet_Type& type,int remain_len)
     84 {
     85     version=(data[0]&0xf0)>>4;
     86     header_len=data[0]&0x0f;
     87     service_type=data[1];
     88     len=data[2]<<8|data[3];
     89     sign=data[4]<<8|data[5];
     90     df=data[6]&0x40>>6;
     91     mf=data[6]&0x20>>5;
     92     offset=(data[6]&0x1f)|data[7];
     93     TTL=data[8];
     94     protocol=data[9]&0xff;
     95     memcpy(sIp,data+12,4);
     96     memcpy(dIp,data+16,4);
     97 
     98     own_type=IPv4;
     99     own_len=header_len*4;
    100     remain_len=len-own_len;
    101 
    102     switch (protocol)
    103     {
    104     case TYPE_ICMP_IPV4:
    105          next=new Head_ICMP();
    106          next->packet_analysis(data+header_len*4,type,remain_len);
    107          break;
    108     case TYPE_IGMP:
    109          next=new Head_IGMP();
    110          next->packet_analysis(data+header_len*4,type,remain_len);
    111          break;
    112     case TYPE_TCP:
    113          next=new Head_TCP();
    114          next->packet_analysis(data+header_len*4,type,remain_len);
    115          break;
    116     case TYPE_UDP:
    117          next=new Head_UDP();
    118          next->packet_analysis(data+header_len*4,type,remain_len);
    119          break;
    120     default:
    121          next=NULL;
    122          type=IPv4;
    123         break;
    124     }
    125 }
    View Code

    好了,有了协议分析的结果,后面的三个模块就很好写了,这里先给出流程图

    关于进程流量这块,没有映射到具体的程序上面,做的很简陋,给出部分代码

    bool CProcessDlg::GetAllProcessesInfo()
    {
        /*得到所有进程的快照*/
        HANDLE hProcessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
        if(INVALID_HANDLE_VALUE==hProcessSnap)
            return false;
    
        /*保存进程信息的结构体*/
        PROCESSENTRY32 ProEntry32;
        memset(&ProEntry32,0,sizeof(ProEntry32));
        ProEntry32.dwSize=sizeof(ProEntry32);
    
        /*得到第一个进程的信息*/
        if(!Process32First(hProcessSnap,&ProEntry32))
        {
            CloseHandle(hProcessSnap);
            return false;
        }
    
        /*显示所有的进程的相关信息*/
        do
        {
            /*显示进程名称*/
            if (ProEntry32.th32ProcessID!=0)             //不包括系统进程 
            {
                CString name=CString(ProEntry32.szExeFile);
                int index;
                if (isContainString(name,index))
                    m_allProcesses[index]._processPID.push_back(ProEntry32.th32ProcessID);
                else
                {
                    ProcessInfo tpInfo;
                    tpInfo._processName=name;
                    tpInfo._processPID.push_back(ProEntry32.th32ProcessID);
                    m_allProcesses.push_back(tpInfo);
                }
             }
        } while(Process32Next(hProcessSnap,&ProEntry32));
    
        CloseHandle(hProcessSnap);
        return true;
    }
    
    void CProcessDlg::GetAllPortByProcessId(DWORD dwProcessId,std::vector<int>& port)
    {
        HMODULE hModule=LoadLibraryW(L"iphlpapi.dll");
        if (hModule==NULL)
            return;                 //加载失败 
    
        //Win7 Vista系统下使用 
    
        //tcp 部分
        PMIB_TCPEXTABLE_VISTA pTcpExTable = NULL;
        PFNInternalGetTcpTable2 pInternalGetTcpTable2 = (PFNInternalGetTcpTable2)GetProcAddress(hModule, "InternalGetTcpTable2");
        if (pInternalGetTcpTable2!=NULL)
        {
           if (pInternalGetTcpTable2(&pTcpExTable, GetProcessHeap(), 1))
           {
              if (pTcpExTable)
                 HeapFree(GetProcessHeap(), 0, pTcpExTable);
               FreeLibrary(hModule);
               hModule = NULL;
               return;
           }
           for (UINT i=0;i<pTcpExTable->dwNumEntries;i++)
           {
                // 过滤掉数据,只获取我们要查询的进程的 TCP Port 信息
                if(dwProcessId==pTcpExTable->table[i].dwProcessId)
                     port.push_back(ntohs(0x0000FFFF & pTcpExTable->table[i].dwLocalPort));
            }
            if (pTcpExTable)
                HeapFree(GetProcessHeap(), 0, pTcpExTable);
         }
    
        //udp 部分 
        PMIB_UDPEXTABLE pUdpExTable=NULL;
        PFNInternalGetUdpTableWithOwnerPid pInternalGetUdpTableWithOwnerPid;
        pInternalGetUdpTableWithOwnerPid=(PFNInternalGetUdpTableWithOwnerPid)GetProcAddress(hModule, "InternalGetUdpTableWithOwnerPid");
        if (pInternalGetUdpTableWithOwnerPid != NULL)
        {
            if (pInternalGetUdpTableWithOwnerPid(&pUdpExTable, GetProcessHeap(), 1))
            {
                if (pUdpExTable)
                    HeapFree(GetProcessHeap(), 0, pUdpExTable);
                FreeLibrary(hModule);
                hModule = NULL;
                 return;
            }
    
            for (UINT i=0;i<pUdpExTable->dwNumEntries;i++)
            {
                if(dwProcessId == pUdpExTable->table[i].dwProcessId)
                     port.push_back(ntohs(0x0000FFFF & pUdpExTable->table[i].dwLocalPort));
            }
    
            if (pUdpExTable)
                HeapFree(GetProcessHeap(), 0, pUdpExTable);
         }
        FreeLibrary(hModule);
        hModule = NULL;
    }
    
    void CProcessDlg::OnTimer(UINT_PTR nIDEvent)
    {   
        clearAllSpeed();
        int maxSize=PData->getPackerResSize();
        for(int i=m_currSize;i<maxSize;i++)
        {
            int sPort,dPort;
            PacketAnalysis* res=PData->getPacketResAtIndex(i);
            if (res->getPort(sPort,dPort))  //获取到端口 
            {
                for(int i=0;i<m_allProcesses.size();i++)
                {
                    for(int j=0;j<m_allProcesses[i]._processPort.size();j++)
                    {
                        if (m_allProcesses[i]._processPort[j]==sPort)
                        {
                            m_allProcesses[i]._upSpeed+=res->getLength();
                            m_allProcesses[i]._upTotal+=res->getLength();
                            break;
                        }
                        if (m_allProcesses[i]._processPort[j]==dPort)
                        {
                            m_allProcesses[i]._downSpeed+=res->getLength();
                            m_allProcesses[i]._downTotal+=res->getLength();
                            break;
                        }
                    }
                }
            }
        }
        m_currSize=maxSize;
    
        //设置文本 
        CString strItem;
        for(int i=0;i<m_allProcesses.size();i++)
        {   
            strItem.Format("%.2lf",m_allProcesses[i]._upSpeed/1024);
            m_process.SetItemText(i,2,strItem);
            strItem.Format("%.2lf",m_allProcesses[i]._downSpeed/1024);
            m_process.SetItemText(i,3,strItem);
            strItem.Format("%.2lf",m_allProcesses[i]._upTotal/1024);
            m_process.SetItemText(i,4,strItem);
            strItem.Format("%.2lf",m_allProcesses[i]._downTotal/1024);
            m_process.SetItemText(i,5,strItem);
        }
    
        CDialogEx::OnTimer(nIDEvent);
    }
    View Code

    然后就是最后一块,使用SQLITE数据库,简单的桌面型数据库,保存每段时间的流量,当然这里主要是绘图控件的使用,从MsChart到TeeChart,最后放弃使用这些复杂的控件,直接使用High Speed Charting Control,简单实用,具体的大家可以

    看 http://www.codeproject.com/Articles/14075/High-speed-Charting-Control,网上的博客啥的写的都很浅,直接看作者给的例子,当然直接看源码是最好的了。给出部分代码

    void SumPicDlg::initDlg()
    {
        //初始化数据类型
        m_dataType.InsertString(0,"网络速度");
        m_dataType.InsertString(1,"月流量");
        m_dataType.InsertString(2,"日流量");
        m_dataType.InsertString(3,"时流量");
        m_dataType.SetCurSel(0);
        
        initSpeedSelect();
    
        //网络速度统计图初始化 
        m_chartCtrl.EnableRefresh(false);
    
        m_chartCtrl.SetEdgeType(EDGE_SUNKEN);   //凹陷边框 
        m_chartCtrl.SetBorderColor(RGB(0,180,0)); //边框颜色
        m_chartCtrl.SetBackColor(RGB(0,50,0));   //设置背景颜色
        m_chartCtrl.GetLegend()->SetVisible(true);  //解释文本可见
        m_chartCtrl.GetTitle()->AddString(_T("网络速度"));  //标题内容
        CChartFont titleFont;
        titleFont.SetFont(_T("Arial Black"),140,true,false,true);  
        m_chartCtrl.GetTitle()->SetFont(titleFont);      //设置字体
        m_chartCtrl.GetTitle()->SetColor(RGB(200,0,10));  //设置颜色
    
        //创建坐标轴 
        CChartStandardAxis* pLeftAxis=m_chartCtrl.CreateStandardAxis(CChartCtrl::LeftAxis);
        pLeftAxis->GetLabel()->SetText(_T("速度(K/S)"));
        pLeftAxis->SetAutomatic(true);
        pLeftAxis->GetGrid()->SetColor(RGB(0,180,0));
        CChartStandardAxis* pBottomAxis=m_chartCtrl.CreateStandardAxis(CChartCtrl::BottomAxis);
        pBottomAxis->SetMinMax(0,30);
        pBottomAxis->SetDiscrete(true);
        pBottomAxis->SetTickIncrement(false,1.0);
        pBottomAxis->GetGrid()->SetColor(RGB(0,180,0));
    
        CChartCrossHairCursor* pCursor=m_chartCtrl.CreateCrossHairCursor();    //交叉线光标   
        m_chartCtrl.ShowMouseCursor(false);                                    //隐藏光标 
    
        //初始化数据
        for(int i=0;i<30;i++)
        {
            m_chartX[i]=i;
            m_recvChartY[i]=0;
            m_sendChartY[i]=0;
        }
    
        m_chartCtrl.RemoveAllSeries();   //去除所有的序列 
        //创建折线数据 
        CChartBarSerie* pBarSerie=m_chartCtrl.CreateBarSerie();
        CChartLineSerie* pRecvSerie=m_chartCtrl.CreateLineSerie();
        CChartLineSerie* pSendSerie=m_chartCtrl.CreateLineSerie();
        pRecvSerie->AddPoints(m_chartX,m_recvChartY,30);
        pRecvSerie->SetColor(RGB(255,0,0));
        pRecvSerie->SetName("接收速度");
        pRecvSerie->EnableShadow(true);
        pRecvSerie->SetShadowColor(RGB(128,255,128));
        pRecvSerie->SetWidth(2);
        pSendSerie->AddPoints(m_chartX,m_sendChartY,30);
        pSendSerie->SetColor(RGB(255,255,0));
        pSendSerie->SetName("发送速度");
        pSendSerie->EnableShadow(true);
        pSendSerie->SetWidth(2);
        pBarSerie->SetColor(RGB(255,255,0));
        pBarSerie->SetGradient(RGB(255,10,10),gtVertical);
        pBarSerie->SetName("");
    
        m_chartCtrl.EnableRefresh(true);
    
        m_toInitChart=false;     //不需要再初始化 
    
        SetTimer(UPDATE_SPEED,1000,NULL);
    }
    
    void SumPicDlg::addDataFromSQL(int maxNum,bool isLine,bool isBar,CChartBarSerie* pBar,CChartLineSerie* pLine)
    {
        CString sql;
        m_chartCtrl.GetBottomAxis()->SetMinMax(0,maxNum+1);
        double* yValue=new double[maxNum];
        double  maxValue=0;
        for(int i=0;i<maxNum;i++)
        {  
            switch (m_dataSrcIndex)
            {
            case 1: sql.Format("select sum(FlowSum) from Flow where Year=%d and Month=%d",m_selectYear,i+1); break;
            case 2: sql.Format("select sum(FlowSum) from Flow where Year=%d and Month=%d and Day=%d",m_selectYear,m_selectMonth,i+1); break;
            case 3: sql.Format("select sum(FlowSum) from Flow where Year=%d and Month=%d and Day=%d and Hour=%d",m_selectYear,m_selectMonth,m_selectDay,i+1);break;
            }
            PData->m_sqlInterFace.selectData(sql);
            if ((yValue[i]=PData->m_sqlInterFace.getDataAtIndex(0))==-1)
                yValue[i]=0;
            if (yValue[i]>maxValue)
                maxValue=yValue[i];
        }
        m_chartCtrl.GetLeftAxis()->SetMinMax(0,maxValue+maxValue/4);
        ((CChartStandardAxis*)m_chartCtrl.GetLeftAxis())->SetTickIncrement(false,(int)(maxValue/6));
        for(int i=0;i<maxNum;i++)
        {
            if (isLine)
            {    
                sql.Format("%.1lf",yValue[i]);
                pLine->AddPoint(i+1,yValue[i]);
                pLine->CreateBalloonLabel(i,TChartString(sql));
            }
            if (isBar)
                pBar->AddPoint(i+1,yValue[i]);
        }
        delete[] yValue;
    }
    
    void SumPicDlg::OnBnClickedButtonCheck()
    {
        m_chartCtrl.EnableRefresh(false);
    
        //获得 序列 
        CChartLineSerie* pLine1=(CChartLineSerie*)m_chartCtrl.GetSerie(1);    
        CChartBarSerie* pBar=(CChartBarSerie*)m_chartCtrl.GetSerie(0);        
        pLine1->ClearSerie();
        pBar->ClearSerie();
        //获取 图表类型 
        bool  isLine=m_checkLine.GetCheck();
        bool  isBar=m_checkBar.GetCheck();
    
    #pragma region 图表初始化部分
        if (m_toInitChart)       //需要初始化 图表
        {   
            pLine1->SetName("流量");
            pBar->SetName("流量");
            CChartLineSerie* pLine2=(CChartLineSerie*)m_chartCtrl.GetSerie(2);
            pLine2->ClearSerie();
            pLine2->SetName("");
    
            CChartStandardAxis* pLeft=(CChartStandardAxis*)m_chartCtrl.GetLeftAxis();
            pLeft->GetLabel()->SetText(_T("流量(Kb)"));
            pLeft->SetAutomatic(false);
            pLeft->SetMinMax(0,100);
            pLeft->SetTickIncrement(false,1);
            switch (m_dataSrcIndex)
            {
            case 1:
                 m_chartCtrl.GetTitle()->RemoveAll();
                 m_chartCtrl.GetTitle()->AddString(_T("月流量"));
                 break;
            case 2:
                 m_chartCtrl.GetTitle()->RemoveAll();
                 m_chartCtrl.GetTitle()->AddString(_T("日流量"));
                 break;
            case 3:
                 m_chartCtrl.GetTitle()->RemoveAll();
                 m_chartCtrl.GetTitle()->AddString(_T("时流量"));
            }
            m_toInitChart=false;
        }
    #pragma endregion
    
        if (((CButton*)GetDlgItem(IDC_RADIO_LASTDAY))->GetCheck())
        {
             //暂时没写  
        }
        else 
        {
            switch (m_dataSrcIndex)
            {
            case 1:addDataFromSQL(m_maxMonthNum,isLine,isBar,pBar,pLine1);  break;
            case 2:addDataFromSQL(m_maxDayNum,isLine,isBar,pBar,pLine1);  break;
            case 3:addDataFromSQL(m_maxHourNum,isLine,isBar,pBar,pLine1);  break;
            }
        }
    
        m_chartCtrl.EnableRefresh(true);
    }
    View Code

    差不多了,程序的源码在后面我会放出,当然只是入门级别的资料,程序写的很简陋。

  • 相关阅读:
    中译英26
    listen 59
    Speaking 1
    listen 58
    listen 57
    中译英25
    listen 56
    2018.2.27 RF module distance test part I
    中译英24
    第二章、PyQt5应用构建详细过程介绍
  • 原文地址:https://www.cnblogs.com/fightfuture/p/4637087.html
Copyright © 2011-2022 走看看