查詢網路狀態

chief1985發表於2008-10-12
導讀:
前兩天因為其他原因需要編寫一段查詢網路狀態的程式碼,一開始的想法是查詢登錄檔中的某個鍵值,後來查了老半天,雖然找到了那個鍵,但是比較麻煩,我在這裡就不再贅述了,有興趣的可以上網查相關的資料。如果你找不到,也可以給我訊息,我可以提供給你。
因為查詢登錄檔的方法實在麻煩,就轉向與其它的方法獲取網路狀態。也就是確認網路的連通性如何。後來查到IpHlpApi[ip助手]裡面有一個函式比較好用GetIfTable,通過呼叫該函式後查詢其中返回的引數可以確認網路的連通性。下面是程式碼:

//預定義幾個結構
#define MAX_INTERFACE_NAME_LEN 256
#define MAXLEN_PHYSADDR 8
#define MAXLEN_IFDESCR 256
#define ANY_SIZE 1
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;

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

typedef DWORD (__stdcall *GIT)(PMIB_IFTABLE, PULONG, BOOL);
GIT lpGetIfTable;


//檢查網路狀態函式
//返回值:如果網路連通則返回 true,否則返回false
bool _CheckNetGoto()
{
BOOL bResult=false;
DWORD dwSize = 0;

HINSTANCE hIphlpDll = LoadLibrary("iphlpapi.dll");
if (hIphlpDll == NULL) { return false;}
lpGetIfTable = (GIT)GetProcAddress(hIphlpDll, "GetIfTable");
if (lpGetIfTable == NULL) {return false;}
MIB_IFTABLE *pMIT = new MIB_IFTABLE[sizeof(MIB_IFTABLE)];
if (lpGetIfTable(pMIT, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER)
{
delete []pMIT;
pMIT = new MIB_IFTABLE[dwSize];
}

//dwNumEntries alwayse>=1, and the last entry is loopback interface.
if (lpGetIfTable(pMIT, &dwSize, 0) == NO_ERROR)
{
if (pMIT->dwNumEntries <= 1){ bResult = false; }
else
{
for(int i=0; i<(pMIT->dwNumEntries); i++)
if (pMIT->table[i].dwType <= 23)
{
bResult = pMIT->table[i].dwOperStatus;
if (bResult) { delete []pMIT; FreeLibrary(hIphlpDll); return true; }
}
}
}
delete []pMIT;
FreeLibrary(hIphlpDll);
return bResult;
}

下面對程式碼進行一點簡單的解釋。
好像2000 SP3以上就已經引入了IP助手,但是使用 IpHlpApi.lib 還需要其他一些標頭檔案,引入庫什麼的。比較麻煩,為了一個GetIfTAble 而引入那麼多垃圾,很不值。所以我在預定義處定義了GetIfTable();所需要的引數的型別定義。然後通過GetProcAddress得到 GetIfTable的地址,直接拿指標進行呼叫。省了很多麻煩。
函式的引數主要說說 PMIB_IFTABLE , 這個指向一個
typedef struct _MIB_IFTABLE { DWORD dwNumEntries; MIB_IFROW table[ANY_SIZE];
} MIB_IFTABLE, *PMIB_IFTABLE;
結構,dwNumEntries指出本機安裝的網路卡數。(後邊會提到),table指向一系列 MIB_IFROW 結構,每個結構指定了當前網路卡的狀態。這個結構包括了一些很實用的資訊,包括網路卡的名字(注意,WCHAR型別),網路卡描述字串,最大速率,索引,接收到的位元組,傳送的位元組,連通狀態,MAC地址等。(這也是一個獲取本機MAC地址的好辦法。)各取所需吧,我需要的是網路狀態。
win 一共定義了6種網路狀態:
MIB_IF_OPER_STATUS_NON_OPERATIONAL :LAN adapter has been disabled, for example because of an address conflict.
MIB_IF_OPER_STATUS_UNREACHABLE WAN :adapter that is not connected.
MIB_IF_OPER_STATUS_DISCONNECTED :For LAN adapters: network cable disconnected. For WAN adapters: no carrier.
MIB_IF_OPER_STATUS_CONNECTING : WAN adapter that is in the process of connecting.
MIB_IF_OPER_STATUS_CONNECTED :WAN adapter that is connected to a remote peer.
MIB_IF_OPER_STATUS_OPERATIONAL :Default status for LAN adapters
但是實際應用中,我發現基本上就用到這兩種:

MIB_IF_OPER_STATUS_NON_OPERATIONAL 網路不通時
MIB_IF_OPER_STATUS_OPERATIONAL 網路連通時

其他狀態你可以自行測試。

另外要提的一點比較有趣的東西是,GetIfTable返回時候的 dwNumEntries 值,總是大於或者等於1。[在TCP/IP網路協議正確安裝的情況下]後來經過確認,原來M$定義了以下幾種網路卡的型別:
MIB_IF_TYPE_OTHER
MIB_IF_TYPE_ETHERNET
MIB_IF_TYPE_TOKENRING
MIB_IF_TYPE_FDDI
MIB_IF_TYPE_PPP
MIB_IF_TYPE_LOOPBACK
MIB_IF_TYPE_SLIP
第二種就是我們正確安裝網路卡後的型別。其中最值得注意的是 MIB_IF_TYPE_LOOPBACK 型別,從名字上我們可以看出是loopback,不好翻譯,“回溯網路卡”?無論你的網路卡在不在使用,只要你的協議是正確的,呼叫GetIfTable總是會返回該型別的"網路卡",從另外一個角度來考慮,為什麼我們平時“ping 127.0.0.1”,其實不是ping的別人,就是ping的這塊網路卡,因為當tcp/ip協議正確安裝的時候, MIB_IF_TYPE_LOOPBACK 網路卡的狀態總是 MIB_IF_OPER_STATUS_OPERATIONAL ,所以,無論你的網路卡如何,你都能 ping 127.0.0.1了。原來就這麼簡單!

一個簡單的擴充套件,你通過不斷呼叫這個函式,就可以製作出一個網路流量分析的圖來了。有興趣的可以自己實現一下,別忘了發一份給我。

文章寫的太簡單,實際做的時候遠沒有那麼複雜。而且,我也不知道安焦以前有沒有發過類似的文章,如果重複的話。嘿嘿,絕對沒有盜版的意思。
如果你有好的想法或者其他的問題,歡迎交流。這是我的幾個朋友們開的論壇,我經常線上,歡迎大家來交流。



本文轉自
http://www.scdc.com.cn/yycnet/display.asp?id=1200000000000000000000026

相關文章