方法:C語言擷取網卡方法之WSAIoctl函數
在WinSock中可以通過調用WSAIoctl()函數,通過設定標誌為SIO_GET_INTERFACE_LIST 的方法擷取網路介面資訊。其函數在MSDN定義如下:
int WSAIoctl(
SOCKET s, // SOCKET控制代碼
DWORD dwIoControlCode, // 控制碼,SIO_GET_INTERFACE_LIST在MSDN中並沒有是通過宏定義計算轉換的
LPVOID lpvInBuffer, // 輸入緩衝區的地址
DWORD cbInBuffer,// 出入緩衝區的大小
LPVOID lpvOutBuffer,// 輸出緩衝區地址
DWORD cbOutBuffer,// 輸出緩衝區大小
LPDWORD lpcbBytesReturned,// 實際輸出位元組數地址
LPWSAOVERLAPPED lpOverlapped,// WSAOVERLAPPED結構的地址
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine // 操作結束後調用的曆程指標
);
該函數定義在ws2tcpip.h中所以要先包含該標頭檔,另外需要提到的就是儲存資訊結構體,如下:
typedef struct _INTERFACE_INFO
{
u_long iiFlags;// 介面的類型和狀態
struct sockaddr iiAddress;// 介面IP地址
struct sockaddr iiBroadcastAddress; // 介面對應的廣播位址
struct sockaddr iiNetmask; // 介面對應的子網路遮罩
} INTERFACE_INFO;
實現的核心代碼如下:
//
// 返回通訊端資訊結構體,參數type:type=-1表示列出所有網卡資訊,不等於-1則是選擇指定網卡顯示
//
int GetIoInfo(int type)
{
int ret;
int nFace; // IoInfo個數
int i;
SOCKET InfoSock;
// 儲存實際的網卡介面資訊位元組數
DWORD BytesReturned;
InfoSock=WSASocket(AF_INET,SOCK_DGRAM,0,0,0,0);
if(INVALID_SOCKET==InfoSock)
{
printf("WSASocket Error:%s\n",WSAGetLastError());
return 0;
}
// 設定標誌SIO_GET_INTERFACE_LIST表示擷取網路介面資訊
ret=WSAIoctl(InfoSock,SIO_GET_INTERFACE_LIST,0,0,&IOInfo,sizeof(IOInfo),&BytesReturned,0,0);
if(SOCKET_ERROR==ret)
{
printf("WSAIoctl Error:%s\n",WSAGetLastError());
return 0;
}
// 計算網卡介面資訊個數
nFace=BytesReturned/sizeof(INTERFACE_INFO);
// type=-1 -- List All Adapter Infomation
// type!=-1 -- List the Number [type] Adapter Information
switch(type)
{
case -1:
{
for(i=0;i<nFace;i++) // 迴圈輸出所有網路介面資訊
{
printf("\nThe %d NetInterFace Information:\n",i);
// 得到網卡地址,並將IP格式轉換為字串格式輸出
printf("IP Address:%s\n",inet_ntoa(IOInfo[i].iiAddress.AddressIn.sin_addr));
}
return 1;
break;
}
default:
{
if(type<nFace&&type>=0){
printf("\nThe %d NetInterFace Information:\n",type);
// 得到網卡地址,並將IP格式轉換為字串格式輸出
printf("IP Address:%s\n",inet_ntoa(IOInfo[type].iiAddress.AddressIn.sin_addr));
}else{
printf("The Net InteFace %d is Not Found!\n",type);
return 0;
}
return 1;
break;
}
}
return 1;
}
方法:C語言擷取網卡方法之GetAdaptersInfo函數
接著上一篇,我們通過第二種方法實現,這種方法擷取到資訊更加完整,也比較實際應用。主要函數是GetAdaptersInfo,該函數在在標頭檔iphlpapi.h中提供的。但是有個問題該檔案在預設只安裝VC6.0的環境下是沒有,他被包含在platform SDK(軟體開發包)中,我從安裝的SDK包提取出包含的檔案頭及相關檔案直接放在開發目錄下就可以了。在文章的最後會給出下載。
首先瞭解下GetAdaptersInfo函數:
DWORD GetAdaptersInfo(
// 接受資料的緩衝區,指向一個結構IP_ADAPTER_INFO
PIP_ADAPTER_INFO pAdapterInfo,
// 指向輸出緩衝區的大小的指標
PULONG pOutBufLen
);
這個函數中最重要是第一個參數,看看這個結構有點啥?MSDN中說明如下:
typedef struct _IP_ADAPTER_INFO {
struct _IP_ADAPTER_INFO* Next; // 鏈表指標,指向下一個單元
DWORD ComboIndex;
char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4]; // 介面資訊實體名稱
char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];// 介面描述資訊
UINT AddressLength; // MAC地址的長度
BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH]; // MAC地址
DWORD Index;
UINT Type;
UINT DhcpEnabled;
PIP_ADDR_STRING CurrentIpAddress;
IP_ADDR_STRING IpAddressList; // IP地址清單
IP_ADDR_STRING GatewayList; // 網關地址清單
IP_ADDR_STRING DhcpServer; // DHCP地址
BOOL HaveWins;
IP_ADDR_STRING PrimaryWinsServer; // 首選WINS 伺服器
IP_ADDR_STRING SecondaryWinsServer; // 備用WINS伺服器
time_t LeaseObtained;
time_t LeaseExpires;
} IP_ADAPTER_INFO, *PIP_ADAPTER_INFO;
在上面我只介紹了幾個常用的參數。這些參數足以了。下面看下實現的小例子,代碼如下:
#include "stdafx.h"
#include "winsock.h"
#include "stdio.h"
#include "iphlpapi/iphlpapi.h" // GetAdaptersInfo()
#pragma comment(lib,"iphlpapi/iphlpapi.lib")
int main(int argc, char* argv[])
{
// 網路介面資訊,最多20個
IP_ADAPTER_INFO IOInfo[20];
// 鏈表結構指標初始化
PIP_ADAPTER_INFO pIOInfo=NULL;
DWORD Result=0;
// 擷取大小
unsigned long nLen=sizeof(IOInfo);
// 擷取網卡資訊
Result=GetAdaptersInfo(IOInfo,&nLen);
if(NO_ERROR!=Result)
{
printf("GetAdaptersInfo Error.\n");
return 0;
}else{
pIOInfo=IOInfo; // 將鏈表指標指向網路介面資訊儲存結構
while(pIOInfo!=NULL) // 不為空白就迴圈讀取網卡
{
static int Num;
Num++;
printf("\n┌────────────Num.%d────────────┐\n",Num);
printf("│Name:%s\n",pIOInfo->AdapterName);
printf("│Desc:%s\n",pIOInfo->Description);
printf("│IP:%s\n",pIOInfo->IpAddressList.IpAddress.String);
printf("│MAC:%02X:%02X:%02X:%02X:%02X:%02X\n",pIOInfo->Address[0],pIOInfo->Address[2],pIOInfo->Address[3],pIOInfo->Address[4],pIOInfo->Address[5]);
printf("│GateWay:%s\n",pIOInfo->GatewayList.IpAddress.String);
printf("└────────────Num.%d────────────┘\n",Num);
// 鏈表指標指向下一個
pIOInfo=pIOInfo->Next;
}
}
return 0;
}
方法三:hostent結構遍曆
#include "stdio.h"
#include "winsock2.h"
#pragma comment(lib,"ws2_32.lib")
int main(int argc, char* argv[])
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
return 0;
}
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 ) {
WSACleanup( );
}
char host[255];
memset(host,0,255);
gethostname(host,255);
printf("%s\n",host);
struct hostent *Host;
Host=gethostbyname(host);
struct in_addr addr;
for(int i=0;;i++){
if(Host->h_addr_list[i]!='\0'){
memmove(&addr,Host->h_addr_list[i],4);
char *ip;
ip=inet_ntoa(addr);
printf("ip:%s\n",ip);
}else{
break;
}
}
WSACleanup();
return 0;
}