铺垫
获取进程使用的端口
http://blog.csdn.net/rongxiaojun1989/article/details/42417767
抓包
http://blog.csdn.net/rongxiaojun1989/article/details/42744761
IP数据包格式
http://blog.csdn.net/rongxiaojun1989/article/details/42743503
概要方案
1. 获取进程此刻使用的端口号
2. 网卡抓包
3. 流量累积
4. 计算结果
详细方案
1. 获取进程此刻使用的端口号
2. 在各个网卡抓包
3. 拆包解析,查看四元组
4. 流量累计
5. 流量累计结果与所用时间的比值即为结果
附加知识
经验证,非阻塞recv抓包30w约等于1s,视电脑处理速度而定。
实现代码
bool GetProcNetworkFlow(const std::string &sNameProc, double &dbpsRecv, double &dbpsSend) { /*获取进程Port*/ std::set<DWORD> setPort; if(!GetProcessPort(sNameProc, setPort)) { printf("GetProcessPort == false, sNameProc=%s ", sNameProc.c_str()); return false; } /*获取所有网卡IP*/ std::vector<std::string> vecHostIp; if(!GetLocalHostIp(vecHostIp)) { printf("GetLocalHostIp == false "); return false; } /*遍历网卡*/ for(size_t i = 0; i != vecHostIp.size(); ++i) { /*创建RAW socket*/ SOCKET s = socket(AF_INET, SOCK_RAW, IPPROTO_IP); if(INVALID_SOCKET == s) { printf("socket == INVALID_SOCKET, ErrorCode=%d ", GetLastError()); return false; } /*设置非阻塞*/ DWORD dwCmdParam = 1; if(SOCKET_ERROR == ioctlsocket(s, FIONBIO, &dwCmdParam)) { printf("ioctlsocket(s, FIONBIO, &dwCmdParam) == SOCKET_ERROR, ErrorCode=%d ", GetLastError()); return false; } /*初始化sockaddr*/ sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr(vecHostIp[i].c_str()); addr.sin_port = htons(4444); /*绑定网卡地址*/ if(SOCKET_ERROR == bind(s, (sockaddr*)&addr, sizeof(addr))) { printf("bind == SOCKET_ERROR, ErrorCode=%d ", GetLastError()); return 0; } /*设置socket模式*/ RCVALL_VALUE emRcvallValue = RCVALL_IPLEVEL; DWORD dwBytesReturned = 0; if(SOCKET_ERROR == WSAIoctl(s, SIO_RCVALL, &emRcvallValue, sizeof(emRcvallValue), NULL, 0, &dwBytesReturned, NULL, NULL)) { printf("WSAIoctl == SOCKET_ERROR, ErrorCode=%d ", GetLastError()); return false; } /*设置计时器*/ LARGE_INTEGER liTimeStart, liTimeEnd, liTimeElapse; LARGE_INTEGER liFrequency; QueryPerformanceFrequency(&liFrequency); QueryPerformanceCounter(&liTimeStart); /*抓包*/ int iBytesRecv = 0, iBytesSend = 0; char cBuffer[100*1024] = {0}; for(int k = 0; k != 300000; ++k) { int iLenRecv = recv(s, cBuffer, 100*1024, 0); if(SOCKET_ERROR == iLenRecv) { if(WSAEWOULDBLOCK == GetLastError()) continue; printf("recv == SOCKET_ERROR, ErrorCode=%d ", GetLastError()); break; } if(0 == iLenRecv) { printf("recv == SOCKET_ERROR, Connection Closed "); break; } cBuffer[iLenRecv] = ' '; /*验证IP协议版本*/ int iVersionIp = static_cast<unsigned char>(cBuffer[0]) >> 4; if(iVersionIp != 4) continue; /*验证协议*/ int iProto = static_cast<unsigned char>(cBuffer[9]); if(iProto != 6 && iProto != 17) continue; /*取IP头长度*/ int iLenIpHeader = cBuffer[0] & 0x0F; iLenIpHeader *= 4; /*获取Ip*/ std::string sIpSrc, sIpDest; for(int m = 0; m != 4; ++m) { sIpSrc += std::to_string(static_cast<ULONGLONG>(static_cast<unsigned char>(cBuffer[12+m]))); sIpDest += std::to_string(static_cast<ULONGLONG>(static_cast<unsigned char>(cBuffer[16+m]))); if(m != 3) { sIpSrc += "."; sIpDest += "."; } } /*判断传输方向*/ bool bRecv; if(std::find(vecHostIp.begin(), vecHostIp.end(), sIpDest) != vecHostIp.end()) bRecv = true; else if(std::find(vecHostIp.begin(), vecHostIp.end(), sIpSrc) != vecHostIp.end()) bRecv = false; else continue; /*获取Port*/ int iPortSrc = 0, iPortDest = 0; memcpy(&iPortSrc, &cBuffer[iLenIpHeader], 2); memcpy(&iPortDest, &cBuffer[iLenIpHeader+2], 2); iPortSrc = ntohs(iPortSrc); iPortDest = ntohs(iPortDest); /*获取本地端口*/ int iPortLocal = 0; if(bRecv) iPortLocal = iPortDest; else iPortLocal = iPortSrc; /*验证Port*/ if(setPort.find(iPortLocal) == setPort.end()) continue; /*获取IP总长*/ int iLenIp = 0; memcpy(&iLenIp, &cBuffer[2], 2); iLenIp = ntohs(iLenIp); /*取实际数据长*/ int iLenData = 0; if(iProto == 6) { int iLenTcpHeader = static_cast<unsigned char>(cBuffer[iLenIpHeader+12]) >> 4; iLenTcpHeader *= 4; iLenData = iLenIp - iLenIpHeader - iLenTcpHeader; } else { iLenData = iLenIp - iLenIpHeader - 20; } /*流量累加*/ if(bRecv) iBytesRecv += iLenData; else iBytesSend += iLenData; } /*计算时间间隔*/ QueryPerformanceCounter(&liTimeEnd); liTimeElapse.QuadPart = liTimeEnd.QuadPart - liTimeStart.QuadPart; double dTimeElapse = static_cast<double>(liTimeElapse.QuadPart) / liFrequency.QuadPart; /*统计流量*/ dbpsRecv += static_cast<double>(iBytesRecv) * 8 / dTimeElapse; dbpsSend += static_cast<double>(iBytesSend) * 8 / dTimeElapse; /*关闭SIO_RCVALL*/ emRcvallValue = RCVALL_OFF; if(SOCKET_ERROR == WSAIoctl(s, SIO_RCVALL, &emRcvallValue, sizeof(emRcvallValue), NULL, 0, &dwBytesReturned, NULL, NULL)) { printf("WSAIoctl == SOCKET_ERROR, ErrorCode=%d ", GetLastError()); return false; } /*关闭socket*/ closesocket(s); } return true; }