使用PDH性能计数器(Windows)获取CPU使用率、可用物理内存、上传/下载速率、磁盘读写速率

来源:互联网 发布:格伦罗宾逊数据 编辑:程序博客网 时间:2024/06/05 21:51

最近要写一个windows下的监控客户端,需要收集计算机的一些信息。

其中CPU使用率、可用物理内存(用于计算内存使用率)、上传/下载速率、磁盘读写速率,都需要实时的。各种资料查询之后,决定使用pdh性能计数器来做。

下面直接贴实现函数。需要注意的有几点:1、首先需要导入pdh的lib库;2、注意接收pdh函数的返回值,判断程序运行状态;3、需求是要收集实时值,所以开一个线程,每秒调用一次实现函数即可;4、在通过pdh函数获取数据时,需要延时,否则会导致数据不准确;5、网速的查询是特别的,因为查询语句中会带有网络适配器的名称,也就是网卡名,对于多张网卡的情况,需要自行确定走的是哪个网卡。而不同计算机名称都会不同,所以将该变量放在配置文件中,以保证代码的一致。

还有个疑问,不知道为什么PdhCollectQueryData()需要调用两次,调用一次收集会失败。

最后收集的数据放在结构体中,并压入队列,等待上传到服务端。目前实现是每收集到一组数据就上传一次,当然也可以通过链表长度和时间来控制上传频率。


由于数据最终是以二进制流的方式上传到服务端,所以结构体定义成了类的形式,带了打包、解包函数。如下:

//用于保存搜集的实时数据class RealtimeData : public MY_OBJECT{public:intiCPUUsage;// CPU使用率doubledbDownloadSpeed;// 下载速率doubledbUploadSpeed;// 上传速率intiMemory;// 可用内存(M)doubledbDiskRead;// 磁盘读速率doubledbDiskWrite;// 磁盘写速率INT64time;// 本次搜集的本机时间public://把内部结构打包成char*格式的扁平格式//外部需要自行delete它传出来的char*,用delete []来释放//参数 char * pDataBuf 如果不为 NULL, 则序列化后的结果会保存到这个缓冲指向的空间virtual char * Package_( char * pDataBuf = NULL ) const;//把Package打包的结果反打包,并还原到本类自身//返回处理的字节数,返回-1表示处理失败virtual int UnPackage_( const char * Stream );//获得Package打包后字节流的长度virtual int GetPackageLength_() const;};//搜集的实时数据的链表,用于发送class RealtimeDataList : public MY_OBJECT{public:CMyStdVector<RealtimeData> vtRealtimeDataList;public://把内部结构打包成char*格式的扁平格式//外部需要自行delete它传出来的char*,用delete []来释放//参数 char * pDataBuf 如果不为 NULL, 则序列化后的结果会保存到这个缓冲指向的空间virtual char * Package_( char * pDataBuf = NULL ) const;//把Package打包的结果反打包,并还原到本类自身//返回处理的字节数,返回-1表示处理失败virtual int UnPackage_( const char * Stream );//获得Package打包后字节流的长度virtual int GetPackageLength_() const;};

PDH数据收集实现函数如下:

BOOL CMonitorClientWorkTread::GatherRealtimeData(){HQUERY query;  double dbVal;long iVal;PDH_STATUS status = PdhOpenQuery(NULL, NULL, &query);  if (ERROR_SUCCESS != status)  {  printf("性能计数器查询,打开失败。");return FALSE;}HCOUNTER cntCPU, cntNetDownload, cntNetUpload;  HCOUNTER cntMemory, cntDiskRead, cntDiskWrite;char strNetWork[MAX_PATH];GetPrivateProfileString("data", "network", "", strNetWork, MAX_PATH, m_strConfigDir);  //从配置文件中获取网络适配器名称,用于拼接PDH查询字符串status = PdhAddCounter(query, _TEXT("\\Processor(_Total)\\% Processor Time"), NULL, &cntCPU); //%号和P之间要有空格char strNetReveive[MAX_PATH], strNetSent[MAX_PATH];sprintf_s(strNetReveive, "\\Network Interface(%s)\\Bytes Received/sec", strNetWork);sprintf_s(strNetSent, "\\Network Interface(%s)\\Bytes Sent/sec", strNetWork);status = PdhAddCounter(query, strNetReveive, NULL, &cntNetDownload);status = PdhAddCounter(query, strNetSent, NULL, &cntNetUpload);status = PdhAddCounter(query, _TEXT("\\Memory\\Available MBytes"), NULL, &cntMemory);status = PdhAddCounter(query, _TEXT("\\PhysicalDisk(_Total)\\Disk Read Bytes/sec"), NULL, &cntDiskRead);status = PdhAddCounter(query, _TEXT("\\PhysicalDisk(_Total)\\Disk Write Bytes/sec"), NULL, &cntDiskWrite);if (ERROR_SUCCESS != status)  {  printf("性能计数器查询,查询添加失败。");return FALSE;}  PdhCollectQueryData(query);        Sleep(500);                 //这里要有延时不然结果相当不准确  PdhCollectQueryData(query);  if(ERROR_SUCCESS != status)  {  printf("性能计数器查询,数据请求失败。");return FALSE; }  PDH_FMT_COUNTERVALUE pdhValue;       DWORD dwValue;  RealtimeData realtimeData;status = PdhGetFormattedCounterValue(cntCPU, PDH_FMT_DOUBLE, &dwValue, &pdhValue);  if(ERROR_SUCCESS != status)  {  printf("性能计数器查询,获取数据失败,CPU使用率。");return FALSE; }else{dbVal = pdhValue.doubleValue;  realtimeData.iCPUUsage = (int)(dbVal+0.5);}status = PdhGetFormattedCounterValue(cntNetDownload, PDH_FMT_DOUBLE, &dwValue, &pdhValue);if(ERROR_SUCCESS != status)  {  printf("性能计数器查询,获取数据失败,下载速率。");return FALSE;  }else{dbVal = pdhValue.doubleValue;  realtimeData.dbDownloadSpeed = (double)((dbVal/(1024*1.0f)));}status = PdhGetFormattedCounterValue(cntNetUpload, PDH_FMT_DOUBLE, &dwValue, &pdhValue);if(ERROR_SUCCESS != status)  {  printf("性能计数器查询,获取数据失败,上传速率。");return FALSE;  }else{dbVal = pdhValue.doubleValue;  realtimeData.dbUploadSpeed = (double)((dbVal/(1024*1.0f)));}status = PdhGetFormattedCounterValue(cntMemory, PDH_FMT_LONG, &dwValue, &pdhValue);if(ERROR_SUCCESS != status)  {  printf("性能计数器查询,获取数据失败,可用物理内存。");return FALSE;  }else{iVal = pdhValue.longValue;  realtimeData.iMemory = iVal;}status = PdhGetFormattedCounterValue(cntDiskRead, PDH_FMT_DOUBLE, &dwValue, &pdhValue);if(ERROR_SUCCESS != status)  {  printf("性能计数器查询,获取数据失败,磁盘读速率。");return FALSE;  }else{dbVal= pdhValue.doubleValue;  realtimeData.dbDiskRead = (double)((dbVal/(1024*1.0f)));}status = PdhGetFormattedCounterValue(cntDiskWrite, PDH_FMT_DOUBLE, &dwValue, &pdhValue);if(ERROR_SUCCESS != status)  {  printf("性能计数器查询,获取数据失败,磁盘写速率。");return FALSE;  }else{dbVal = pdhValue.doubleValue;  realtimeData.dbDiskWrite = (double)((dbVal/(1024*1.0f)));}PdhRemoveCounter(cntCPU);PdhRemoveCounter(cntNetDownload);PdhRemoveCounter(cntNetUpload);PdhCloseQuery(query);//将收集到的实时数据保存到链表中time (&realtimeData.time);/*struct tm *st;st = localtime(&realtimeData.time);*/m_realtimeDataList.vtRealtimeDataList.push_back(realtimeData);//将链表数据发送到服务端MsgHead head;head.nMsgLenght = m_realtimeDataList.GetPackageLength();head.nMsgType   = MT_REALTIMEDATA;CMessageItem * pItem = gMsgItemObtain.GetNewMsgItem(); pItem->SetMessageCode( HS_SEND_NETWORK_DATA );pItem->SetAutoReduceRefAfterMsgLoop( true );// 消息头pItem->SetData(&head,sizeof(head));char *p;p = m_realtimeDataList.Package();pItem->AppendDate(p,head.nMsgLenght);gGlobalEnvManager.PostMessage( HSDLL_THREAD_NAME, pItem );delete p;m_realtimeDataList.vtRealtimeDataList.pop_back();return TRUE;}


阅读全文
1 0
原创粉丝点击