网络编程——基于UDP的网络化CPU性能检测
网络化计算机性能检测软件的开发,可对指定目标主机的CPU利用率进行远程检测,并自动对远程主机执行性能指标进行周期性检测,最终实现图形化显示检测结果。
网络通信模块:(客户端类似,因为udp是对等通信)
启动服务器:创建套接字并注册网络事件 void CRemoteCPUImitateDlg::OnBnClickedOk() { // TODO: 在此添加控件通知处理程序代码 int Ret; char BufferData[2000] = { 0 }; int ClientAddrSize = sizeof(ClientAddress); GetDlgItem(IDOK)->EnableWindow(FALSE); memset(BufferData, 0, sizeof(BufferData)); ServerAddress.sin_port = htons(4440); ServerAddress.sin_family = AF_INET; ServerAddress.sin_addr.s_addr = INADDR_ANY; //初始化本地网卡 m_ServerSocket = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0, 0); if (m_ServerSocket == SOCKET_ERROR) { MessageBox(L"创建套接字失败!"); return ; } int Result = bind(m_ServerSocket, (sockaddr*)&ServerAddress, sizeof(ServerAddress)); if (Result != 0) { int a = GetLastError(); MessageBox(L"绑定套接字失败!"); return; } if (WSAAsyncSelect(m_ServerSocket, m_hWnd, UM_RECV, FD_ALL_EVENTS)) { MessageBox(L"注册网络读取事件失败!"); return; } } 网络事件响应函数 afx_msg LRESULT CRemoteCPUImitateDlg::OnUmRecv(WPARAM wParam, LPARAM lParam) { int Ret; int i; memset(BufferData, 0, sizeof(BufferData)); int ClientAddrSize = sizeof(ClientAddress); memset(&ClientAddress, 0, sizeof(ClientAddress)); if (WSAGETSELECTERROR(lParam)) { return false; } else { switch (WSAGETSELECTEVENT(lParam)) { case FD_ACCEPT://接受客户端连接请求。 { MessageBox(L"FD_ACCEPT"); } break; case FD_READ://可读,接收数据。 { if ((Ret = recvfrom(m_ServerSocket, BufferData, 2000, 0, (SOCKADDR *)&ClientAddress, &ClientAddrSize)) == SOCKET_ERROR) { //MessageBox(L"接受数据失败"); closesocket(m_ServerSocket); return 0; } else { BYTE bToken = (BYTE)BufferData[0]; switch (bToken) { case 1://登录 { LOGIN_INFORMATION* li = (LOGIN_INFORMATION*)BufferData; CString str,strIP, strAddr, strPCName, strOS, strCPU, strPing; int ClientLength = sizeof(sockaddr_in); strIP = inet_ntoa(ClientAddress.sin_addr); for (i = 0; i < m_ListUser.GetItemCount(); i++) { str = m_ListUser.GetItemText(i, 0); if (str == strIP) { MessageBox(L"该用户已在线!"); return 0; } } //主机名称 strPCName = li->PCName; switch (li->OsVerInfoEx.dwPlatformId) { case VER_PLATFORM_WIN32_NT: if (li->OsVerInfoEx.dwMajorVersion <= 4) strOS = "WindowsNT"; if (li->OsVerInfoEx.dwMajorVersion == 5 && li->OsVerInfoEx.dwMinorVersion == 0) strOS = "Windows2000"; if (li->OsVerInfoEx.dwMajorVersion == 5 && li->OsVerInfoEx.dwMinorVersion == 1) strOS = "WindowsXP"; if (li->OsVerInfoEx.dwMajorVersion == 5 && li->OsVerInfoEx.dwMinorVersion == 2) strOS = "Windows2003"; if (li->OsVerInfoEx.dwMajorVersion == 6 && li->OsVerInfoEx.dwMinorVersion == 0) strOS = "WindowsVista"; if (li->OsVerInfoEx.dwMajorVersion == 6 && li->OsVerInfoEx.dwMinorVersion == 1) strOS = "Windows7"; if (li->OsVerInfoEx.dwMajorVersion == 6 && li->OsVerInfoEx.dwMinorVersion == 2) strOS = "Windows10"; } //CPU strCPU.Format(L"%dMHz", li->CPUMHz); //网速 strPing.Format(L"%d", li->Speed); AddList(strIP, strPCName, strOS, strCPU, strPing); break; } case 2://cpu信息 { sumCpu = (UINT)BufferData[sizeof(BYTE)]; if (Dlg == NULL) { return 0; } Dlg->m_sumCpu = sumCpu; WPARAM a; a = sumCpu; ::PostMessage(Dlg->GetSafeHwnd(), UM_CHANGE, a, 0); break; } case 3://下线 { CString strIP, str; strIP = inet_ntoa(ClientAddress.sin_addr); for (i = 0; i < m_ListUser.GetItemCount() ; i++) { str = m_ListUser.GetItemText(i, 0); if (str == strIP) { m_ListUser.DeleteItem(i); } } break; } default: break; } } //在新接受的套接字发生FD_READ,FD_WRITE,FD_CLOSE网络事件发生,发送WM_SOCKET消息; //WSAAsyncSelect(sAccept, this->m_hWnd, UM_RECV, FD_READ | FD_WRITE | FD_CLOSE); } break; case FD_WRITE://可写,发送数据。 { //MessageBox(L"FD_WRITE"); } break; case FD_CLOSE://对方关闭套接字连接。 { if (WSAGETSELECTERROR(lParam) == 0) { //从容关闭。 } else if (WSAGETSELECTERROR(lParam) == WSAECONNREFUSED) { //硬关闭。 } } break; default: break; } } return 0; }
CPU图像绘制模块:(参考了网上的代码)
绘制CPU使用率进度条 UINT CDisplayDlg::DoSysCpu(LPVOID pParam) { CDisplayDlg *pthis = (CDisplayDlg *)pParam; CString showCpu; UINT sumCpu = 0; if (bFirst) { bFirst = FALSE; m_sumCpu = 1; } else { sumCpu = m_sumCpu; } sumCpu = sumCpu % 101; pthis->m_Process_CPU.SetPos(sumCpu); showCpu.Format(L"%u %%", sumCpu); pthis->GetDlgItem(IDC_STATIC_CPU)->SetWindowText(showCpu); pthis->UpdateWindow(); pthis->Invalidate(FALSE); ::PostMessage(pthis->GetSafeHwnd(), WM_PAINT, 0, 0); return 0; } 4.5 绘制CPU使用记录折线 BOOL CDisplayDlg::CDrawCpu(CDC *pDC) { CRect rect; GetDlgItem(IDC_SHOWCPU)->GetClientRect(&rect); CDC dcMem; //用于缓冲作图的内存DC CBitmap bmp; //内存中承载临时图象的位图 CBitmap *oldBmp; dcMem.CreateCompatibleDC(pDC); //依附窗口DC创建兼容内存DC bmp.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());//创建兼容位图 oldBmp = dcMem.SelectObject(&bmp); //将位图选择进内存DC int i = 1; //绘图 //背景 dcMem.FillSolidRect(rect, RGB(222, 222, 222)); CPen pen; if (!pen.CreatePen(PS_DOT, 1, RGB(255, 255, 255))) { return FALSE; } CPen *pOldPen = dcMem.SelectObject(&pen);//保存旧画笔 //横线 for (i = 1; i < 10; i++) { dcMem.MoveTo(0, rect.Height()*i / 10); dcMem.LineTo(rect.Width(), rect.Height()*i / 10); } //竖线 for (i = 1; i < 30; i++) { dcMem.MoveTo(rect.Width()*i / 30, 0); dcMem.LineTo(rect.Width()*i / 30, rect.Height()); } //收回资源并释放 dcMem.SelectObject(pOldPen); pen.DeleteObject(); //绘制四边(防止闪烁) dcMem.MoveTo(0, 0); dcMem.LineTo(rect.Width(), 0); dcMem.MoveTo(0, rect.Height() - 1); dcMem.LineTo(rect.Width(), rect.Height() - 1); dcMem.MoveTo(0, 0); dcMem.LineTo(0, rect.Height()); dcMem.MoveTo(rect.Width() - 1, 0); dcMem.LineTo(rect.Width() - 1, rect.Height()); //绘制CPU运行状态线 if (!pen.CreatePen(0, 2, RGB(0, 200, 0))) { return FALSE; } pOldPen = dcMem.SelectObject(&pen);//保存旧画笔 pointCpu[0].x = rect.Width(); pointCpu[0].y = rect.Height() - rect.Height()*m_sumCpu / 100; for (i = m_nMovNum; i > 0; i--) { if (i > 1) { dcMem.MoveTo(pointCpu[i - 2]); dcMem.LineTo(pointCpu[i - 1]); } pointCpu[i].x = pointCpu[i - 1].x - rect.Width() / maxpix - 1; pointCpu[i].y = pointCpu[i - 1].y; } dcMem.SelectObject(pOldPen); pen.DeleteObject(); pOldPen = NULL; //将内存DC上的图象拷贝到前台 pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &dcMem, 0, 0, SRCCOPY); //释放资源 dcMem.SelectObject(oldBmp); dcMem.DeleteDC(); //删除DC bmp.DeleteObject(); //删除位图 return TRUE; }
运行效果:
附件:源码(客户端和服务器)