Windows網絡通信流量和網速監控設計(一)

第二篇文章連接

三種數據通信傳輸模式

一、單工通信

數據傳輸只支持數據在一個方向上傳輸;在同一時間只有一方能接受或發送數據信息,不能實現雙向通信。比較安全,例如:廣播、電視。

二、半雙工通信

傳輸允許數據在兩個方向上傳輸;在某一時刻,只允許數據在一個方向上傳輸,它實際上是一種切換方向的單工通信;在同一時間只可以有一方接受或發送消息,可以實現雙向通信。例如:對講機。

三、全雙工通信

數據通信允許數據同時在兩個方向上傳輸,全雙I通信是兩個單工通信方式的組合。它要求發送設備和接收設備都有獨立的接收和發送能力;在同一時間可以同時接受和發送消息。例如:電話通信。

相關基礎知識

1、__stdcall

詳解可點擊這裏瞭解

2、GetIfTable()函數

函數

  DWORD GetIfTable(
         PMIB_IFTABLE pIfTable,
         PULONG pdwSize,
         BOOL bOrder
  );

功能

  獲取MIB-II接口列表

參數

  PMIB_IFTABLE pIfTable:接收緩衝區,接收GetIfTable返回的MIB-II接口表

  PULONG pdwSize:pIfTable緩衝區字節數,若緩衝區過小則返回所需大小

  BOOL bOrder:指定pIfTable中返回的接口列表條目是否根據接口索引排序

3、MIB_IFTABLE結構體

MIB_IFTABLE結構體

typedef struct _MIB_IFTABLE {
  DWORD     dwNumEntries;
  MIB_IFROW table[ANY_SIZE];
} MIB_IFTABLE, *PMIB_IFTABLE;

typedef struct _MIB_IFROW {
  WCHAR wszName[MAX_INTERFACE_NAME_LEN];
  DWORD dwIndex;
  DWORD dwType;
  DWORD dwMtu;
  DWORD dwSpeed;
  DWORD dwPhysAddrLen;
  BYTE  bPhysAddr[MAXLEN_PHYSADDR];
  DWORD dwAdminStatus;
  DWORD dwOperStatus;
  DWORD dwLastChange;
  DWORD dwInOctets;
  DWORD dwInUcastPkts;
  DWORD dwInNUcastPkts;
  DWORD dwInDiscards;
  DWORD dwInErrors;
  DWORD dwInUnknownProtos;
  DWORD dwOutOctets;
  DWORD dwOutUcastPkts;
  DWORD dwOutNUcastPkts;
  DWORD dwOutDiscards;
  DWORD dwOutErrors;
  DWORD dwOutQLen;
  DWORD dwDescrLen;
  BYTE  bDescr[MAXLEN_IFDESCR];
} MIB_IFROW, *PMIB_IFROW;


返回值

  成功返回NO_ERROR,否則返回值即錯誤碼

頭文件和引用庫

  #include <IPHlpApi.h>   
  #pragma comment(lib, "IPHlpApi.lib")

細說MIB_IFROW結構體成員

  dwType:接口類型,例如IF_TYPE_ETHERNET_CSMACD=6, Ethernet網絡接口;
  IF_TYPE_SOFTWARE_LOOPBACK=24,軟件迴環測試網絡接口。23號之前的網絡接口可用來統計系統流量。

  dwSpeed:接口速度,單位bps,可用來計算網絡帶寬

  bPhysAddr:接口網卡的MAC地址

  dwInOctets:接收的字節數,自系統啓動,可用來統計系統網絡流量。
  dwOutOctets:發送的字節數,自系統啓動,可用來統計系統網絡流量。

4、獲取網絡帶寬

bool GetNetworkBandwithByMidTable(int &iMbsBandwidth)
{
	/*獲取MIB-II接口表大小*/
	DWORD dwBufferLen = 0;
	GetIfTable(NULL, &dwBufferLen, 0); 

	/*創建MIB-II接口表*/
	PMIB_IFTABLE pMibIfTable = (MIB_IFTABLE*)malloc(dwBufferLen);

	/*獲取MIB-II接口表*/
	DWORD dwRet = GetIfTable(pMibIfTable, &dwBufferLen, 0);
	if(NO_ERROR != dwRet)
	{
		std::cout<<"GetIfTable != NO_ERROR, ErrorCode="<<dwRet<<std::endl;
		free(pMibIfTable);
		return false;
	}

	iMbsBandwidth = INT_MAX;

	/*多網卡*/
	for(int i = 0; i != pMibIfTable->dwNumEntries; ++i)
	{
		if (pMibIfTable->table[i].dwType <= 23)
		{
			int iTmp = static_cast<int>(pMibIfTable->table[i].dwSpeed/1000/1000);
			if(iTmp != 0 && iTmp < iMbsBandwidth)
				iMbsBandwidth = iTmp;
		}
	}

	free(pMibIfTable);
	if(iMbsBandwidth == INT_MAX)
		return false;
	return true;
}

網卡的傳輸速度有10Mbps、100Mbps、1000Mbps,查看網卡速度的方法:設備管理器—網絡適配器—選擇網卡—屬性—高級—連接速度和雙工模式—值—下拉菜單中的最大值。

網絡帶寬由多種因素決定,例如爲連接在只具備100M傳輸速度的雙絞線上的計算機配置1000M的網卡就是一種浪費,因爲其至多也只能實現100M的傳輸速率。

故網絡帶寬爲各種物理介質中的最小值,可認爲是所有網卡傳輸速度的最小值(且不爲0)。

5、獲取發送比特數和接收比特數,自系統啓動

bool GetStatisticOfSysNetworkFlow(DWORD &dwbitTotalRecv, DWORD &dwbitTotalSend)
{
	/*獲取MIB-II接口表大小*/
	DWORD dwBufferLen = 0;
	GetIfTable(NULL, &dwBufferLen, 0); 

	/*創建MIB-II接口表*/
	PMIB_IFTABLE pMibIfTable = (MIB_IFTABLE*)malloc(dwBufferLen);

	/*獲取MIB-II接口表*/
	DWORD dwRet = GetIfTable(pMibIfTable, &dwBufferLen, 0);
	if(NO_ERROR != dwRet)
	{
		std::cout<<"GetIfTable != NO_ERROR, ErrorCode="<<dwRet<<std::endl;
		free(pMibIfTable);
		return false;
	}

	dwbitTotalRecv = dwbitTotalSend = 0;

	/*多網卡*/
	for(int i = 0; i != pMibIfTable->dwNumEntries; ++i)
	{
		if (pMibIfTable->table[i].dwType <= 23)
		{
			dwbitTotalRecv += pMibIfTable->table[i].dwInOctets;
			dwbitTotalSend += pMibIfTable->table[i].dwOutOctets;
		}
	}

	/*Byte轉bit*/
	dwbitTotalRecv *= 8;
	dwbitTotalSend *= 8;

	free(pMibIfTable);
	return true;
}

6、計算每秒發送比特數和每秒接收比特數

bool GetSysNetworkFlowByMidTable(DWORD &dwbpsRecv, DWORD &dwbpsSend)
{
	/*首次獲取*/
	DWORD dwTotalRecv1 = 0, dwTotalSend1 = 0;
	if(!GetStatisticOfSysNetworkFlow(dwTotalRecv1, dwTotalSend1))
	{
		printf("GetStatisticOfSysNetworkFlow == false\n");
		return false;
	}

	Sleep(1000);

	/*再取*/
	DWORD dwTotalRecv2 = 0, dwTotalSend2 = 0;
	if(!GetStatisticOfSysNetworkFlow(dwTotalRecv2, dwTotalSend2))
	{
		printf("GetStatisticOfSysNetworkFlow == false\n");
		return false;
	}

	/*計算*/
	dwbpsRecv = dwTotalRecv2 - dwTotalRecv1;
	dwbpsSend = dwTotalSend2 - dwTotalSend1;

	return true;
}

7、SetupDiGetClassDevs()函數

SetupDiGetClassDevs用來查詢與指定參數匹配的所有已安裝設備。

函數定義

HDEVINFO
SetupDiGetClassDevs(
const GUID* ClassGuid,
PCTSTR Enumerator,
HWND hwndParent,
DWORD Flags
);

參數說明

PGUIDClassGuid
在創建設備列表的時候提供一個指向GUID的指針。如果設定了標誌(參數Flags的值)爲DIGCF_ALLCLASSES,則這個參數可以忽略,且列表結果中包括所有已經安裝的設備類別。
PCTSTREnumerator
提供包含設備實例的枚舉註冊表分支下的鍵名,可以通過它獲取設備信息。如果這個參數沒有指定,則要從整個枚舉樹中獲取所有設備實例的設備信息。
HWNDhwndParent
提供頂級窗口的句柄,所有用戶接口可以使用它來與成員聯繫。
DWORDFlags
提供在設備信息結構中使用的控制選項。可以是以下數值:
DIGCF_PRESENT - 只返回當前存在的設備。
DIGCF_ALLCLASSES - 返回所有已安裝的設備。如果這個標誌設置了,ClassGuid參數將被忽略。
DIGCF_PROFILE - 只返回當前硬件配置文件中的設備。
DIGCF_INTERFACEDEVICE - 返回所有支持的設備。
DIGCF_DEFAULT - 只返回與系統默認設備相關的設備。

返回值

HDEVINFO
如果函數運行成功,返回設備信息結構的句柄,該結構包含與指定參數匹配的所有已安裝設備。如果失敗,則返回INVALID_HANDLE_VALUE。調用GetLastError可以獲得更多錯誤信息。

說明

使用此函數,需要包含頭文件setupapi.h
此外,在project setting中的link頁面需要添加setupapi.lib。
在setupapi.h中有如下定義:
typedef PVOID HDEVINFO;
即HDEVINFO是個無類型指針

舉例

//得到所有設備
HDEVINFO hDevInfo = SetupDiGetClassDevs(NULL, 0, 0, DIGCF_PRESENT | DIGCF_ALLCLASSES );
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章