• windows获取进程流量


    铺垫

    获取进程使用的端口

    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;
    }
  • 相关阅读:
    时间操作
    2021.10.9数据结构实验课作业
    2021.9.28数据结构实验课作业
    2021.9.15数据结构实验课作业
    2021.9.7数据结构实验课作业
    苹果ios开发,CocoaPods安装方法-2021/9/11
    写组件库文档常用的技术
    document.execCommand 的用法
    手写JSON.stringify
    Object常用方法
  • 原文地址:https://www.cnblogs.com/chaikefusibushiji/p/6775764.html
Copyright © 2020-2023  润新知