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

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

原文地址:https://www.cnblogs.com/fightfuture/p/4637087.html