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

差不多了,程序的源碼在后面我會放出,當然只是入門級別的資料,程序寫的很簡陋。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM